diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index e80acce..0000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,30 +0,0 @@ -// For format details, see https://aka.ms/devcontainer.json. For config options, see the -// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node -{ - "name": "Node.js & TypeScript", - // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile - "image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm", - "features": { - "ghcr.io/devcontainers/features/common-utils:2": { - "username": "automatic", - "userUid": "automatic", - "userGid": "automatic", - "upgradePackages": false - } - }, - - // Features to add to the dev container. More info: https://containers.dev/features. - // "features": {}, - - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], - - // Use 'postCreateCommand' to run commands after the container is created. - "postCreateCommand": "echo 'exec zsh' >> /home/node/.bashrc" - - // Configure tool-specific properties. - // "customizations": {}, - - // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. - // "remoteUser": "root" -} diff --git a/.gitignore b/.gitignore deleted file mode 100644 index ba5aa84..0000000 --- a/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -.idea/ -*.iml -*.iws -*.eml -out/ -.DS_Store -.svn -log/*.log -tmp/** -node_modules/ -.sass-cache \ No newline at end of file diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 362d612..0000000 --- a/.npmignore +++ /dev/null @@ -1,5 +0,0 @@ -/test -/examples -.github -.sass-cache -gulpfile.js diff --git a/CNAME b/CNAME index 7a968b8..f1bdb4b 100644 --- a/CNAME +++ b/CNAME @@ -1 +1 @@ -basic.study.pylapaz.org \ No newline at end of file +study.pylapaz.org \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 261eeb9..0000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/README.md b/README.md deleted file mode 100644 index e72f482..0000000 --- a/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# ¡Bienvenidos al *_Python Study Group for Beginners_* ! 💻🚀 - -En este repositorio encontrarás una ruta para no solo aprender a programar en Python si no para aprender a hablar este lenguaje de programación. - -Todos los recursos que encontrarás han sido desarrollados con mucho cariño por la comunidad para que cualquier persona que pueda manejar una computadora pueda convertirse en un Pythonista 🐍 - -## Contenido 📚 - -* Iniciando nuestro Setup: Introducción a VS Code y Git 💻🔧 -* Iniciando nuestro Setup: Introducción a Git y GitHub 💻🌐 -* Iniciando nuestro Setup: Introducción a Python I 🐍📚 -* Iniciando nuestro Setup: Introducción a Python II 🐍🎓 -* Tipos de datos: Datos numéricos 1️⃣🔢 -* Tipos de datos: Datos Booleanos 🧮🔵 -* Tipos de datos: Cadenas 🔤💬 -* Estructuras de datos: Tuplas 📦📊 -* Estructuras de datos: Listas 📜📝 -* Estructuras de datos: Conjuntos 🔄🧩 -* Estructuras de datos: Diccionarios 📚📖 -* Estructuras de control: Sentencias Condicionales ⚖️🔄 -* Estructuras de control: Sentencias iterativas 🔁🔄 -* Funciones: Bloques de código 🛠️🧱 -* Errores y Excepciones: Try - Except ❌❗🛠️ - -## Equipo 👩‍💻👨‍💻 - -* **[Jonathan](https://github.com/jevillanueva):** Creador del contenido 📝👨‍💻 -* **[Tatiana](https://github.com/taicoding):** Diseño curricular 🎨📚 -* **[Andrei](https://www.linkedin.com/in/alberto-andrei-soria-gomez-b32ba9264/):** Curador de contenido 📌🔍 -* **[Rafa](https://www.linkedin.com/in/andres-rafael-tito-04a240178/):** Curador de contenido 📌🔍 - -## Contributors - - - - - -### Con mucho ❤️ Python La Paz 🐍 -[![Pagina Web](https://img.shields.io/badge/Web-Python%20La%20Paz-blue.svg)](https://pylapaz.org/) diff --git a/content/Logo.png b/content/Logo.png deleted file mode 100644 index 6a02728..0000000 Binary files a/content/Logo.png and /dev/null differ diff --git a/content/custom.css b/content/custom.css deleted file mode 100644 index 23cda12..0000000 --- a/content/custom.css +++ /dev/null @@ -1,29 +0,0 @@ -:root { - --green: #057985; /* Verde */ - --burgundy: #9e0059; /* Bordo */ - --yellow: #ffec9b; /* Amarillo */ - --light-blue: #c0d6e1; /* Celeste */ - --cream: #ecece2; /* Crema */ - - --turquoise-green: #2ec4b6; /* Verde Turquesa */ - --pastel-orange: #f8d682; /* Naranja Pastel */ - --creamy-orange: #f6d7c5; /* Naranja Cremoso */ - --creamy-magenta: #f1dbe7; /* Magenta Cremoso */ -} - -.custom-btn-home { - position: absolute; - top: 1%; - left: 1%; -} -.custom-btn-home img { - width: 3vh; -} - -strong { - color: var(--yellow); -} - -.slides p code { - color: var(--turquoise-green); -} diff --git a/content/github_logo.png b/content/github_logo.png deleted file mode 100644 index 50b8175..0000000 Binary files a/content/github_logo.png and /dev/null differ diff --git a/content/homeico.svg b/content/homeico.svg deleted file mode 100644 index 8bf175f..0000000 --- a/content/homeico.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/content/psg-bg-dark.png b/content/psg-bg-dark.png deleted file mode 100644 index 241e215..0000000 Binary files a/content/psg-bg-dark.png and /dev/null differ diff --git a/content/sesion01/Readme.md b/content/sesion01/Readme.md deleted file mode 100644 index ceec2cf..0000000 --- a/content/sesion01/Readme.md +++ /dev/null @@ -1,649 +0,0 @@ - -![Python La paz](../Logo.png) - -
-
-
- -### Sesión 01 -### Iniciando nuestro Setup -### Introducción a VS Code y Git - ---- -#### ¿Qué es un editor de Código? -Un editor de código es un editor de texto diseñado para editar el código fuente de los programas informáticos - ---- -Tienen características diseñadas para simplificar y acelerar la escritura de código fuente como: -- Resultado de sintaxis -- Autocompletado -- Igualación de llaves - ---- -Algunos ejemplos de editores de código: - -- Visual Studio Code -- Sublime Text -- Atom -- Notepad++ -- Vim - ---- -Utilizaremos **Visual Studio Code** por su facilidad de instalación, compatibilidad entre plataformas y optimización de recursos - ---- -Características de Visual Studio Code - -| | | -| ----------------------- | ----------------------------------------------------------------------- | -| IntelliSense | ![IntelliSense](./img/001.png) | -| Run & Debug | ![Run & Debug](./img/003.png) | -| Comandos Git Integrados | ![Comandos Git Integrados](./img/004.png) | - ---- -**IntelliSense**: Es una combinación de autocompletado de código, asistencia de contenido y sugerencia de código - -![IntelliSense](./img/000.gif) - ---- -**Run & Debug**: Realizar Debug desde el editor de código, ejecutar o enlazar la ejecución de apps y realizar debug utilizando breakpoints - -![Run & Debug](./img/002.png) - ---- -**Comandos Git Integrados**: Trabajar con GIT es esencial en el mundo del desarrollo y VS Code permite revisar diffs, stage de archivos, realizar commits desde el editor, push y pull desde cualquier SCM (source code management) - ---- -**Extensiones**: Posee la capacidad de instalar extensiones que agregan más características, extiende y personaliza el editor, instalar extensiones para nuevos lenguajes, temas, herramientas de debug, conectar a servicios - -![Extensiones](./img/005.png) - ---- -#### Instalación de VSCode -Visual Studio Code o VS Code se puede utilizar tanto en Windows, Linux y Mac OS se puede descargar los binarios de la siguiente dirección - -[code.visualstudio.com](https://code.visualstudio.com/download) - ---- -Descargaremos los binarios de acuerdo al sistema operativo que estén utilizando - -- En Windows descargaremos el archivo .exe -- En Linux descargaremos el archivo .deb o .rpm -- En Mac OS descargaremos el archivo .zip - - De acuerdo a Chip Intel (i3, i5, i7) - - o Apple Silicon(M1, M2, M3, M4) - ---- -##### Windows - -Ejecutar el archivo `.exe` - -Instalación tradicional con interfaz guiada añadiendo la opción de agregar al PATH para poder ejecutarlo desde la consola - ---- - -##### Linux (Debian & Ubuntu) - -Descargar el archivo `.deb` y ejecutar el siguiente comando en la terminal - -```bash [1-2|3-5] -# Ubuntu & Debian -sudo apt install ./.deb -# Otra Forma para Distribuciones más antiguas -sudo dpkg -i .deb -sudo apt-get install -f -``` - ---- -##### Linux (RHEL, Fedora & CentOS) - -Descargar el archivo `.rpm` y ejecutar el siguiente comando en la terminal - -```bash [1-2|3-5] -# RHEL, Fedora & CentOS -sudo dnf install ./.rpm -# Otra Forma para Distribuciones más antiguas -sudo rpm -ivh .rpm -``` - ---- -##### Otros sistemas operativos - -- [openSUSE](https://code.visualstudio.com/docs/setup/linux#_opensuse-and-slebased-distributions) -- [Arch Linux](https://code.visualstudio.com/docs/setup/linux#_aur-package-for-arch-linux) -- [Nix package for NixOS](https://code.visualstudio.com/docs/setup/linux#_nix-package-for-nixos-or-any-linux-distribution-using-nix-package-manager) -- [Termux I](https://www.codewithharry.com/blogpost/install-vs-code-in-android/) -- [Termux II](https://gist.github.com/ppoffice/b9e88c9fd1daf882bc0e7f31221dda01) - ---- -Mediante package manager o administrador de paquetes -```bash [1-7|8-9] -# Ubuntu & Debian -sudo apt-get install wget gpg -wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > packages.microsoft.gpg -sudo install -D -o root -g root -m 644 packages.microsoft.gpg /etc/apt/keyrings/packages.microsoft.gpg -sudo sh -c 'echo "deb [arch=amd64,arm64,armhf signed-by=/etc/apt/keyrings/packages.microsoft.gpg] https://packages.microsoft.com/repos/code stable main" > /etc/apt/sources.list.d/vscode.list' -rm -f packages.microsoft.gpg -sudo apt install apt-transport-https -sudo apt update -sudo apt install code -``` - ---- -Mediante package manager o administrador de paquetes -```bash [1-3|4-6|7-9] -# RHEL, Fedora & CentOS -sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc -sudo sh -c 'echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com/yumrepos/vscode\nenabled=1\ngpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc" > /etc/yum.repos.d/vscode.repo' -# Versiones superiores a Fedora 22: -Sudo dnf check-update -sudo dnf install code -# Versiones anteriores a Fedora 22: -yum check-update -sudo yum install code -``` - ---- -##### Mac OS 1/2 - -Desde la página de descarga de [VS Code para Mac](https://code.visualstudio.com/docs/setup/mac) - -Descarga el archivo, abrir y arrastrar - -"Visual Studio Code.app" - -a la carpeta de "Aplicaciones" - ---- -##### Mac OS 2/2 -Se debe añadir al PATH ejecutando desde VS Code - -* Abrir VS Code -* Paleta de comandos (Ctrl+Shift+P) y escribir "shell command" -* Seleccionar "Shell Command: Install 'code' command in PATH" - ---- -##### Creación de un proyecto -- Después de instalar procedemos a crear un proyecto vacío, una carpeta vacía y abrirla en VS Code -- Crear la carpeta desde la interfaz o la terminal en una ruta del disco duro - ---- -##### Creación de un proyecto -- Es recomendable para los nombres de proyectos no utilizar espacios, sino utilizar guiones o barra baja para separar palabras haciendo más fácil el uso desde la terminal - ---- -##### Creación de un proyecto - -La carpeta se convertirá en el proyecto desde el cual trabajaremos, se puede crear en cualquier ubicación del disco duro, en este caso se creará en la carpeta "2025" en el disco C: - -Abrimos una terminal de acuerdo al sistema operativo - -- Windows: `cmd` o `PowerShell` -- Linux y Mac: `Terminal` - ---- - -Si no tienen la carpeta 2025 pueden crearla en su disco duro - -Para cualquier sistema operativo utilizando la interfaz gráfica o la terminal - -```bash -# Windows -mkdir C:\2025 -# Linux y Mac -mkdir /home/username/2025 -``` - ---- -En la terminal navegaremos a la carpeta "2025" y crearemos una carpeta llamada "psg-example" - -```bash -#Windows -cd C:\ -cd 2025 -#Linux y Mac OS -cd /home/username/2025 -``` - -Luego crearemos la carpeta "psg-example" - -```bash -#Windows, Linux y Mac OS -mkdir psg-example -``` - -![Creación de un proyecto](./img/008.png) - ---- -##### Abriendo el proyecto con VS Code desde la terminal -Para abrir el proyecto podemos ejecutar desde la terminal -```powershell [1-4|5-6] -# Windows -cd C:\ -cd 2025 -code psg-example -# Otra Forma -code C:\path\to\folder\psg-example -``` -![Abriendo el proyecto con VS Code desde la terminal](./img/010.png) - ---- -##### Abriendo el proyecto con VS Code desde la terminal -```powershell [1-3|5-6] -# Linux and Mac -cd 2025 -code psg-example -# Otra Forma -code /home/username/2025/psg-example -``` - -![Abriendo el proyecto con VS Code desde la terminal](./img/012.png) - ---- -Ejecutando el comando **code** se puede abrir cualquier carpeta de la computadora en VS Code - -Se abrirá un VS Code con la carpeta desde el explorador donde se puede ver el nombre del proyecto *"psg-example"* - -![Abriendo el proyecto con VS Code desde la terminal](./img/013.png) - ---- -### ¿Qué es un control de versiones? -El control de versiones es también conocido como "control de código fuente" - -Es la práctica de rastrear y gestionar los cambios en el código de software - -Los desarrolladores de software que trabajan en equipos están escribiendo continuamente nuevo código fuente y cambiando el que ya existe - ---- -El código de un proyecto de software se organiza en una estructura de carpetas o "árbol de archivos" - ---- -Un desarrollador del equipo podría estar trabajando en una nueva función mientras otro desarrollador soluciona un error no relacionado cambiando código - ---- -Cada desarrollador podría hacer sus cambios en varias partes del árbol de archivos al mismo tiempo - ---- -Una de las herramientas de control de versiones más populares hoy en día se llama "Git" es gratuita y de código abierto - ---- -### Ventajas -- Completo historial de cambios a largo plazo de todos los archivos, incluye creación, eliminación y cambios en los archivos - ---- -- Creación de ramas y fusiones, la creación de ramas permite el flujo de trabajo independiente, los unos de los otros - ---- -- Trazabilidad, ser capaz de trazar cada cambio que se hace, tener el historial anotado del código al instante y poder visualizar cómo fue construida - ---- -##### Conceptos básicos de Git - ---- -##### Repositorio -Abarca toda la colección de archivos y carpetas asociados con un proyecto, junto con el historial de cada archivo - -El historial aparece como una línea de tiempo con nodos llamados "commits" - -![Repositorio](./img/014.png) - ---- -##### Commit -Es la operación fundamental, almacena información de los cambios en un repositorio y representa una versión específica del proyecto en un punto en el tiempo - -![Commit](./img/015.png) - ---- -##### Commit -Contiene -- Unique identifier, git asigna un identificador único llamado "commit hash" o "commit SHA" a cada commit, es una larga cadena de caracteres que identifica al commit -- Message, cada commit tiene un mensaje asociado que describe los cambios realizados en el mismo, es un resumen - ---- -##### Commit -- Date & Time, la fecha y la hora que se realiza el commit -- Author, nombre y correo electrónico del autor del commit - ---- -##### Commit -- Snapshot & Changes, captura instantánea de los archivos modificados en el commit como una fotografía, involucran adición, eliminación y modificaciones en los archivos existentes - ---- -##### Commit -- Parent Commit, almacena el ID del padre o padres del commit, para tener un orden cronológico y enlazado en las diversas ramas de proyecto - ---- -##### Branch -Es una línea de desarrollo independiente, es una rama del árbol de archivos - -Crear branch o ramas significa trabajar en una línea separada, cada rama se puede volver a fusionar a la línea principal para incorporar sus cambios - -![Branch](./img/016.png) - ---- -##### Ventajas de usar Git en desarrollo de software -- Historial completo y rastreable, esencial para resolver problemas y mantener la transparencia en el repositorio -- Desarrollo colaborativo sin fricción, pueden trabajar en paralelo en diferentes características utilizando branches de manera fluida - ---- -##### Ventajas de usar Git en desarrollo de software -- Reversión sencilla y segura, en caso de errores Git permite retroceder en commits de manera rápida y segura reduciendo el impacto negativo -- Flujo de trabajo flexible, adapta desde un modelo de ramificación sencilla hasta entornos más complejos como GitFlow - ---- -##### Ventajas de usar Git en desarrollo de software -- Integración con plataformas, Plataformas como GitHub ofrecen características de seguimiento, revisión, colaboración y Git se adapta perfectamente con estas herramientas - ---- -##### Instalación de Git -Git se instala de diversas formas, se descarga de la página oficial: [git-scm.com/downloads](https://git-scm.com/downloads) - -Para Windows descargar el instalador y seguir los pasos de instalación y añadir al PATH - -![Instalación de Git](./img/017.png) - ---- -Para Linux y Mac instalar mediante package manager o administrador de paquetes -```bash [1-2|3-6|7-8] -# Ubuntu y Debian -apt install git -# Fedora <= 21 -yum install git -# Fedora >= 22 -dnf install git -# Mac OS -brew install git -``` - -[Mac OS Instalar brew](https://brew.sh/) - ---- -Una vez instalado en cualquier sistema podemos utilizar el siguiente comando y probar la instalación -```bash -git --version -``` -![Instalación de Git](./img/020.png) -![Instalación de Git](./img/021.png) - ---- -##### Configuración de Git Usuario y Correo -Existen tres tipos de configuraciones de usuario en Git, local, global y de sistema - -- Local: Configuración a nivel del repositorio actual, al realizar una confirmación o commit se utilizará los ajustes definidos de manera local para ese proyecto - ---- -##### Configuración de Git Usuario y Correo -- Global: Configuración a nivel global para el usuario actual, estos ajustes se utilizarán para todos los proyectos desde cualquier ubicación del sistema - ---- -##### Configuración de Git Usuario y Correo -- Sistema: Configuración a nivel de todo el sistema para todos los usuarios de la computadora - ---- -Utilizaremos el nivel global para que todos los proyectos utilicen los mismos ajustes de usuario y correo electrónico - ---- -##### Configuración de Git Usuario y Correo -```bash[1-3|4-5] -# Configuración de usuario y correo global -git config --global user.name "Jhon Doe" -git config --global user.email "jhon_doe@domain.com" -# Verificar configuración -git config -l -``` -![Configuración de Git Usuario y Correo](./img/023.png) - ---- -##### Creación de un repositorio local -Para crear el repositorio local dirigirse a la carpeta del proyecto creada anteriormente y ejecutar el comando "git init" para inicializar - -```bash -# Inicializar repositorio -cd /home/username/2025/psg-example -git init -``` -![Creación de un repositorio local](./img/025.png) - ---- -Se observa que se encuentra vacío utilizando el comando "git status" - -La rama principal creada en el proyecto se llama "master", puede tener otros nombres como "main", "principal" u otros -```bash -# Verificar estado del repositorio -git status -``` -![Creación de un repositorio local](./img/027.png) - ---- -##### Crear mi primer archivo -Abrir VS Code en la dirección del proyecto -```bash -# Abrir VS Code en la carpeta del repositorio local -cd /home/username/2025/psg-example -code . -``` -![Crear mi primer archivo](./img/029.png) - ---- -El proyecto está vacío y cuenta con un repositorio local, la carpeta .git se encuentra oculta -![Crear mi primer archivo](./img/030.png) - ---- -Crear un archivo llamado "sesion01.txt" y escribir "Hola Mundo" en el archivo - -Para crear click derecho sobre el espacio del explorador y crear "New File… " - -![Crear mi primer archivo](./img/031.png) - ---- -Se creará un archivo en blanco en el cual se le dará el nombre y su extensión, el archivo está en la carpeta del proyecto en el disco duro - -Escribiremos "Hola Mundo" en el archivo y guardar con Ctrl+S o desde el menú File > Save - -![Crear mi primer archivo](./img/032.png) - ---- -Se encuentra en el editor, en la línea 1, el texto escrito - -En el explorador está el archivo "sesion01.txt", de color verde y con una letra U - -- Color verde, Git y el editor lo detecta como archivo nuevo en el proyecto -- "U", el archivo está "Untracked" o sin seguimiento dentro del repositorio al ser nuevo no tiene historial anterior - -![Crear mi primer archivo](./img/033.png) - ---- -##### Mi primer commit -Utilizando la terminal que ya viene incorporada en el VS Code, iremos en el menú contextual a la dirección Terminal > New Terminal - -![Mi primer commit](./img/034.png) - ---- -Git status, nos mostrará cual es el estado actual del repositorio y si existen archivos nuevos en el mismo -```bash -# Verificar estado del repositorio -git status -``` - -![Mi primer commit](./img/036.png) - ---- -Adicionaremos el archivo para prepararlo para el commit con el comando "git add" - -Una vez adicionado observamos que la letra U de Untracked cambió ahora a la letra A de Added -```bash -# Adicionar archivo al repositorio -git add sesion01.txt -``` -![Mi primer commit](./img/038.png) - ---- -Git status, nos muestra el estado con el archivo adicionado y preparado para el commit -```bash -# Verificar estado del repositorio -git status -``` - -![Mi primer commit](./img/039.png) - ---- -Para confirmar el commit del archivo utilizaremos el comando "git commit" - -La etiqueta -m que indica que lo siguiente entre comillas es el mensaje del resumen - -```bash -# Crear la primera confirmación -git commit -m "Mi primer commit" -``` - -![Mi primer commit](./img/041.png) - ---- -Después de realizar el commit aparece el mensaje que un archivo cambió y se insertó uno nuevo - -Observamos que el archivo volvió a su color inicial y ya no tiene ninguna letra eso significa que el archivo ya se encuentra bajo seguimiento del repositorio - -![Mi primer commit](./img/041.png) - ---- -Para observar el historial de los commit utilizamos el comando "git log" -```bash -# Observar el historial -git log -``` - -![Mi primer commit](./img/043.png) - -Podemos ver el hash, autor, correo electrónico, fecha y hora y el mensaje del commit realizado - ---- -Una página interactiva para practicar y conocer más del ciclo de vida de un repositorio - -[Learn Git Branching](https://learngitbranching.js.org/?locale=es_ES) - - - ---- -##### GitHub como plataforma remota -GitHub es una empresa que ofrece un servicio de alojamiento de repositorios GIT basados en la nube - -Facilita a los individuos o equipos a utilizar GIT para el control de versiones y colaboración - ---- -Cualquier persona puede registrarse y alojar repositorios de manera gratuita - -Eso hace que GitHub sea la plataforma más popular para alojar proyectos open source - -![GitHub](./img/044.png) - ---- -Cada persona que utiliza GitHub inicia sesión con una cuenta personal, esta es su identidad en GitHub, tiene un nombre de usuario y un perfil - -![Perfil GitHub](./img/045.png) - ---- -Pasos para crear una cuenta personal en GitHub - -1. Ingresa a [github.com](https://github.com) -2. Click en Sign up -3. Continua con los pasos para crear tu cuenta personal ---- -![Pasos para crear una cuenta](./img/046.png) - ---- -Después de llenar los datos, se te pedirá que verifiques tu cuenta a través de un correo electrónico - -Y listo, ya tienes tu cuenta personal en GitHub - ---- -##### Resumen - - -- Un editor de código es una herramienta para editar el código fuente de programas -- Ejemplos populares son Visual Studio Code, Sublime Text, Atom, Notepad++ y Vim -- Visual Studio Code es preferido por su facilidad de instalación y optimización de recursos -- Características de Visual Studio Code incluyen IntelliSense, ejecución y depuración de código, y comandos Git integrados - ---- -- IntelliSense ofrece autocompletado, asistencia de contenido y sugerencias de código -- Ejecución y depuración permiten debugging y ejecución de aplicaciones -- Comandos Git integrados facilitan el trabajo con Git directamente desde el editor -- Visual Studio Code se puede extender mediante extensiones para agregar más características - ---- -- La instalación varía según el sistema operativo, descargando desde el sitio web oficial o usando administradores de paquetes en Linux -- Control de versiones, como Git, es esencial para rastrear y gestionar cambios en el código de software -- Git permite historial completo de cambios, ramificación, fusiones y trazabilidad -- Repositorio abarca toda la colección de archivos y carpetas asociados con un proyecto - ---- -- Commit es una operación fundamental en Git que almacena información de los cambios en un repositorio -- Branch es una rama de desarrollo en Git -- Para instalar Git, se puede descargar desde el sitio web oficial o instalar mediante administradores de paquetes en sistemas Linux y Mac -- La configuración de usuario y correo en Git se realiza a nivel local, global o de sistema - ---- -- `git config` permite configurar el usuario y correo en Git -- `git init` inicializa un repositorio local en una carpeta -- `git add` adiciona archivos al repositorio -- `git commit` crea un commit con los cambios en el repositorio - ---- -- GitHub es una plataforma popular para alojar repositorios Git en la nube, facilitando la colaboración y el control de versiones -- Para crear una cuenta en GitHub, se debe registrar en el sitio web y verificar la cuenta a través de un correo electrónico - ---- -##### Retos - -Crear una carpeta con el nombre "retos_sesion_01" dentro del proyecto, en la cual por cada ejercicio debes crear un archivo - -```bash -# Ejemplo carpeta -psg-example/ - retos_sesion_01/ - ejercicio_01.txt - ejercicio_02.txt - ... -``` - ---- -1. Crea un archivo llamado "ejercicio_01.txt" y escribe un mensaje de bienvenida dirigido a toda la comunidad de Python La Paz, guarda el archivo y realiza un commit con el mensaje "Bienvenida desde PSG For Beginners" - ---- -2. Crea un archivo llamado "ejercicio_02.txt" y escribe una receta de cocina de tu postre favorito, guarda el archivo y realiza un commit con el mensaje "Receta de mi postre favorito" - ---- -3. Crea una cuenta en GitHub y envía el link de tu usuario de GitHub en el siguiente formulario [Formulario de Retos](https://forms.gle/jMeCtPBLsy3kTG7f8) - ---- - - -
-
-
-
-
- -[![GitHub](../../content/github_logo.png) ](https://github.com/python-la-paz/python-study-group-fundamentals/tree/main/content/sesion01) - -Repositorio de la Sesión - ---- - -## Bibliografía y Referencias -- [Source Code Editor](https://en.wikipedia.org/wiki/Source-code_editor) -- [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense) -- [Run & Debug](https://code.visualstudio.com/docs/editor/debugging) -- [Source Control](https://code.visualstudio.com/docs/sourcecontrol/overview) -- [Extension Marketplace](https://code.visualstudio.com/docs/editor/extension-marketplace) -- [What is Version Control](https://www.atlassian.com/es/git/tutorials/what-is-version-control) -- [About Repositories](https://docs.github.com/en/get-started/using-git/about-git#about-repositories) -- [Commit in Git](https://medium.com/@Ariobarxan/commit-in-git-9ddc141c674d) -- [Branches in a Nutshell](https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell) -- [Descubriendo Git](https://www.kranio.io/blog/descubriendo-git-caracteristicas-y-ventajas) -- [Git Downloads](https://git-scm.com/downloads) -- [What is Git](https://www.linkedin.com/pulse/what-git-basic-concepts-installation-commands-examples-hassan/) -- [Git Config](https://www.atlassian.com/git/tutorials/setting-up-a-repository/git-config) -- [Setting your commit email address](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-email-preferences/setting-your-commit-email-address#setting-your-email-address-for-every-repository-on-your-computer) -- [Learn Git Branching](https://learngitbranching.js.org/) -- [Vs Code on Termux](https://www.codewithharry.com/blogpost/install-vs-code-in-android/) \ No newline at end of file diff --git a/content/sesion01/img/000.gif b/content/sesion01/img/000.gif deleted file mode 100644 index 670cc08..0000000 Binary files a/content/sesion01/img/000.gif and /dev/null differ diff --git a/content/sesion01/img/001.png b/content/sesion01/img/001.png deleted file mode 100644 index 215bf96..0000000 Binary files a/content/sesion01/img/001.png and /dev/null differ diff --git a/content/sesion01/img/002.png b/content/sesion01/img/002.png deleted file mode 100644 index a688ea2..0000000 Binary files a/content/sesion01/img/002.png and /dev/null differ diff --git a/content/sesion01/img/003.png b/content/sesion01/img/003.png deleted file mode 100644 index df588ef..0000000 Binary files a/content/sesion01/img/003.png and /dev/null differ diff --git a/content/sesion01/img/004.png b/content/sesion01/img/004.png deleted file mode 100644 index 1b75e9b..0000000 Binary files a/content/sesion01/img/004.png and /dev/null differ diff --git a/content/sesion01/img/005.png b/content/sesion01/img/005.png deleted file mode 100644 index a4cb586..0000000 Binary files a/content/sesion01/img/005.png and /dev/null differ diff --git a/content/sesion01/img/006.png b/content/sesion01/img/006.png deleted file mode 100644 index 41ca60d..0000000 Binary files a/content/sesion01/img/006.png and /dev/null differ diff --git a/content/sesion01/img/007.png b/content/sesion01/img/007.png deleted file mode 100644 index d026a2a..0000000 Binary files a/content/sesion01/img/007.png and /dev/null differ diff --git a/content/sesion01/img/008.png b/content/sesion01/img/008.png deleted file mode 100644 index 8f99b24..0000000 Binary files a/content/sesion01/img/008.png and /dev/null differ diff --git a/content/sesion01/img/009.png b/content/sesion01/img/009.png deleted file mode 100644 index 5aa6b19..0000000 Binary files a/content/sesion01/img/009.png and /dev/null differ diff --git a/content/sesion01/img/010.png b/content/sesion01/img/010.png deleted file mode 100644 index ddc8537..0000000 Binary files a/content/sesion01/img/010.png and /dev/null differ diff --git a/content/sesion01/img/011.png b/content/sesion01/img/011.png deleted file mode 100644 index 883fd5a..0000000 Binary files a/content/sesion01/img/011.png and /dev/null differ diff --git a/content/sesion01/img/012.png b/content/sesion01/img/012.png deleted file mode 100644 index 907d4ef..0000000 Binary files a/content/sesion01/img/012.png and /dev/null differ diff --git a/content/sesion01/img/013.png b/content/sesion01/img/013.png deleted file mode 100644 index 266bfce..0000000 Binary files a/content/sesion01/img/013.png and /dev/null differ diff --git a/content/sesion01/img/014.png b/content/sesion01/img/014.png deleted file mode 100644 index d8a3d1f..0000000 Binary files a/content/sesion01/img/014.png and /dev/null differ diff --git a/content/sesion01/img/015.png b/content/sesion01/img/015.png deleted file mode 100644 index 3d87cbc..0000000 Binary files a/content/sesion01/img/015.png and /dev/null differ diff --git a/content/sesion01/img/016.png b/content/sesion01/img/016.png deleted file mode 100644 index 8de8fd3..0000000 Binary files a/content/sesion01/img/016.png and /dev/null differ diff --git a/content/sesion01/img/017.png b/content/sesion01/img/017.png deleted file mode 100644 index 006a257..0000000 Binary files a/content/sesion01/img/017.png and /dev/null differ diff --git a/content/sesion01/img/018.png b/content/sesion01/img/018.png deleted file mode 100644 index f2c97d5..0000000 Binary files a/content/sesion01/img/018.png and /dev/null differ diff --git a/content/sesion01/img/019.png b/content/sesion01/img/019.png deleted file mode 100644 index c508a4c..0000000 Binary files a/content/sesion01/img/019.png and /dev/null differ diff --git a/content/sesion01/img/020.png b/content/sesion01/img/020.png deleted file mode 100644 index 1718ada..0000000 Binary files a/content/sesion01/img/020.png and /dev/null differ diff --git a/content/sesion01/img/021.png b/content/sesion01/img/021.png deleted file mode 100644 index fba3f36..0000000 Binary files a/content/sesion01/img/021.png and /dev/null differ diff --git a/content/sesion01/img/022.png b/content/sesion01/img/022.png deleted file mode 100644 index 3b2606c..0000000 Binary files a/content/sesion01/img/022.png and /dev/null differ diff --git a/content/sesion01/img/023.png b/content/sesion01/img/023.png deleted file mode 100644 index 5881fe9..0000000 Binary files a/content/sesion01/img/023.png and /dev/null differ diff --git a/content/sesion01/img/024.png b/content/sesion01/img/024.png deleted file mode 100644 index d6bacb2..0000000 Binary files a/content/sesion01/img/024.png and /dev/null differ diff --git a/content/sesion01/img/025.png b/content/sesion01/img/025.png deleted file mode 100644 index f04f4a6..0000000 Binary files a/content/sesion01/img/025.png and /dev/null differ diff --git a/content/sesion01/img/026.png b/content/sesion01/img/026.png deleted file mode 100644 index f39e602..0000000 Binary files a/content/sesion01/img/026.png and /dev/null differ diff --git a/content/sesion01/img/027.png b/content/sesion01/img/027.png deleted file mode 100644 index 4ae0795..0000000 Binary files a/content/sesion01/img/027.png and /dev/null differ diff --git a/content/sesion01/img/028.png b/content/sesion01/img/028.png deleted file mode 100644 index 7132b0e..0000000 Binary files a/content/sesion01/img/028.png and /dev/null differ diff --git a/content/sesion01/img/029.png b/content/sesion01/img/029.png deleted file mode 100644 index 8f339f0..0000000 Binary files a/content/sesion01/img/029.png and /dev/null differ diff --git a/content/sesion01/img/030.png b/content/sesion01/img/030.png deleted file mode 100644 index 208320b..0000000 Binary files a/content/sesion01/img/030.png and /dev/null differ diff --git a/content/sesion01/img/031.png b/content/sesion01/img/031.png deleted file mode 100644 index 716b58e..0000000 Binary files a/content/sesion01/img/031.png and /dev/null differ diff --git a/content/sesion01/img/032.png b/content/sesion01/img/032.png deleted file mode 100644 index 6a42ab7..0000000 Binary files a/content/sesion01/img/032.png and /dev/null differ diff --git a/content/sesion01/img/033.png b/content/sesion01/img/033.png deleted file mode 100644 index 6c7f035..0000000 Binary files a/content/sesion01/img/033.png and /dev/null differ diff --git a/content/sesion01/img/034.png b/content/sesion01/img/034.png deleted file mode 100644 index 27fcb83..0000000 Binary files a/content/sesion01/img/034.png and /dev/null differ diff --git a/content/sesion01/img/035.png b/content/sesion01/img/035.png deleted file mode 100644 index f39e602..0000000 Binary files a/content/sesion01/img/035.png and /dev/null differ diff --git a/content/sesion01/img/036.png b/content/sesion01/img/036.png deleted file mode 100644 index 92fa792..0000000 Binary files a/content/sesion01/img/036.png and /dev/null differ diff --git a/content/sesion01/img/037.png b/content/sesion01/img/037.png deleted file mode 100644 index 83400a0..0000000 Binary files a/content/sesion01/img/037.png and /dev/null differ diff --git a/content/sesion01/img/038.png b/content/sesion01/img/038.png deleted file mode 100644 index 845a2d3..0000000 Binary files a/content/sesion01/img/038.png and /dev/null differ diff --git a/content/sesion01/img/039.png b/content/sesion01/img/039.png deleted file mode 100644 index 7c0f93b..0000000 Binary files a/content/sesion01/img/039.png and /dev/null differ diff --git a/content/sesion01/img/040.png b/content/sesion01/img/040.png deleted file mode 100644 index a1b46ee..0000000 Binary files a/content/sesion01/img/040.png and /dev/null differ diff --git a/content/sesion01/img/041.png b/content/sesion01/img/041.png deleted file mode 100644 index d2fca79..0000000 Binary files a/content/sesion01/img/041.png and /dev/null differ diff --git a/content/sesion01/img/042.png b/content/sesion01/img/042.png deleted file mode 100644 index e9cee74..0000000 Binary files a/content/sesion01/img/042.png and /dev/null differ diff --git a/content/sesion01/img/043.png b/content/sesion01/img/043.png deleted file mode 100644 index 8bfd201..0000000 Binary files a/content/sesion01/img/043.png and /dev/null differ diff --git a/content/sesion01/img/044.png b/content/sesion01/img/044.png deleted file mode 100644 index 50b8175..0000000 Binary files a/content/sesion01/img/044.png and /dev/null differ diff --git a/content/sesion01/img/045.png b/content/sesion01/img/045.png deleted file mode 100644 index 054e5bc..0000000 Binary files a/content/sesion01/img/045.png and /dev/null differ diff --git a/content/sesion01/img/046.png b/content/sesion01/img/046.png deleted file mode 100644 index cc0aeac..0000000 Binary files a/content/sesion01/img/046.png and /dev/null differ diff --git a/content/sesion01/index.html b/content/sesion01/index.html deleted file mode 100644 index f8ee4b5..0000000 --- a/content/sesion01/index.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - Sesión 01 | Python Study Group | Fundamentals - - - - - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/content/sesion02/Readme.md b/content/sesion02/Readme.md deleted file mode 100644 index 165f57c..0000000 --- a/content/sesion02/Readme.md +++ /dev/null @@ -1,535 +0,0 @@ - -![Python La paz](../Logo.png) - -
-
-
- -### Sesión 02 -### Iniciando nuestro Setup -### Introducción a Git y GitHub ---- -##### Creando un repositorio remoto en GitHub -Después de iniciar sesión en GitHub, en la esquina superior derecha, da click en el signo + y selecciona "New repository" - -![Crear repositorio](./img/04.png) - ---- -1. Se abrirá una ventana donde irá el nombre del repositorio -2. La visibilidad del repositorio puede ser público o privado, utilizaremos público -3. Un checkbox para inicializar el repositorio con un README, activar el checkbox - ---- -4. Un dropdown para seleccionar .gitignore, selecciona Python -5. La ventana indica el nombre de la rama principal, en este caso "main" -6. Selecciona "Create repository" ---- -![Crear repositorio](./img/05.png) - ---- - -Se abrirá una ventana con el repositorio creado - -![Repositorio creado](./img/06.png) - -En la barra de navegación, esta la url del repositorio -Observamos que tiene los archivos README.md y .gitignore en el branch main - ---- -Clonaremos el repositorio en nuestra PC con el comando "git clone" - -Iremos a la carpeta donde deseas clonar el repositorio y ejecutaremos el comando - -```bash -cd 2025 -git clone https://github.com/ej2v/psg02 -``` -![Clonar repositorio](./img/07.png) - ---- -El repositorio se habrá descargado en la carpeta y lo abriremos con VS Code -![Abrir repositorio](./img/08.png) - ---- -En VS Code, observamos el archivo README.md y .gitignore que se descargaron del repositorio remoto -![Abrir repositorio](./img/09.png) - ---- -##### ¿Qué es un archivo .gitignore? -Para entender qué es un .gitignore, debemos entender como detecta Git los archivos - -1. Con seguimiento, son los archivos que Git detecta y que están en el repositorio con anterioridad -2. Sin seguimiento (U), son los archivos que Git detecta pero que no están en el repositorio -3. Ignorados, un archivo que se le ha dicho explícitamente a Git que ignore ---- -Los archivos ignorados generalmente son - -- Caches de dependencia, como node_modules o pycache -- Código compilado, como .pyc o .class -- Directorios de salida de compilación, como dist o build ---- -- Archivos generados en tiempo de ejecución, como .log o .lock -- Archivos ocultos o de sistema, como .DS_Store o Thumbs.db -- Archivos personales de configuración, como .idea/workspace.xml -- Archivos de credenciales, como .env o .pem ---- -No existe un comando especial para ignorar archivos, por lo que debemos crear un archivo .gitignore para listar archivos, directorios o patrones a ignorar - -Se encuentra en la raíz del repositorio y se edita manualmente lo que se desea ignorar - -Contienen patrones que establecen coincidencias con nombres de archivos para ignorar - ---- -##### Ejemplo de patrones -- **\*.log** - ignora todos con extensión .log -- **logs/** - ignora todos los archivos en el directorio logs -- **debug[0-9].log** - ignora debug0.log, debug1.log, ... debug9.log ---- -##### Casos especiales -- **!logs/important.log** - al poner un signo de exclamación, no se ignora el archivo important.log -- **foo\\ \[01\\ \].txt** - el uso de backslash, permite que el corchete sea parte del nombre del archivo y no un patrón como "foo[01].txt" -- **#** - las líneas que comienzan con # son comentarios - ---- -Practicaremos con el archivo .gitignore - -Crear un archivo "claves.txt", simulará ser un archivo de credenciales - -Se observa que git lo detecta como sin seguimiento (U) - -![Archivo de credenciales](./img/10.png) - ---- -Adicionaremos al final del archivo .gitignore la línea "claves.txt" para crear una regla - -Las claves no deben ser subidas al repositorio, por seguridad se debe ignorar - -Una vez guardado el archivo .gitignore, se observa que git lo detecta como ignorado - -![Archivo de credenciales](./img/11.png) - ---- -##### ¿Qué es un archivo README.md y Markdown (.md)? - -Los archivos .md son archivos de texto en formato markdown, en el repositorio se encuentra el archivo README.md - -Sirven para comunicar información importante sobre el proyecto, es la primera información que se ve al abrir el repositorio - ---- -Muestra información sobre el proyecto: - -- Qué hace el proyecto -- Por qué el proyecto es útil -- Cómo pueden comenzar los usuarios con el proyecto -- Dónde pueden recibir ayuda los usuarios con tu proyecto -- Quién mantiene y contribuye con el proyecto - ---- -El archivo README.md en GitHub puede ir en diferentes directorios - -- .github - en una carpeta .github -- docs - en una carpeta docs -- En la raíz del repositorio - ---- -Markdown es un lenguaje de marcado ligero, permite adicionar formato a los elementos escrito en texto plano - -Almacena texto que se procesa y genera HTML dinámicamente para visualizarlo - -![Markdown](./img/12.png) - ---- -##### Sintaxis de Markdown -Es una forma rápida y sencilla de tomar notas o crear contenido para la web, posee la siguiente sintaxis - -```markdown[1-4|5-6|7-8|9-10|11-14|15-18|19-20|21-22|23-24] -Títulos -# Título 1 -## Título 2 -### Título 3 -Negrillas -**bold text** -Italic -*italic text* -Citas -> contenido de otra fuente -Listas Ordenadas -1. First Item -2. Second Item -3. Third Item -Listas No Ordenadas -- First Item -- Second Item -- Third Item -Código -`code` -Enlaces -[Titulo](https://miruta.com) -Imágenes -![texto alterno]("ruta/de/la/imagen") -``` ---- -Estos elementos son los elementos básicos de Markdown, existen más elementos que se pueden consultar en la documentación de [Markdown](https://www.markdownguide.org/basic-syntax/) - ---- -Pondremos en práctica la sintaxis de Markdown en el archivo README.md - -- Título principal con el texto "Sesión 02" -- Un subtítulo H2 con el texto ".gitignore y Markdown" -- Un texto que cuente con algunas palabras en negrilla -- Una cita -- Una lista ordenada con el contenido del repositorio actual ---- -```markdown -# Sesión 02 - -## .gitignore y Markdown - -En esta sesión se utiliza markdown y se modifico el archivo **.gitignore** para que no se suba el archivo **clave.txt** - -> Como parte de la sesión 02 - -Se lista el contenido del directorio actual: - -1. .gitignore -2. README.md -3. clave.txt -``` ---- - -Observamos las diferentes partes de la sintaxis de Markdown y desde el explorador se observa que existen cambios en el archivo README.md de color amarillo y una letra "M" - -![Markdown](./img/13.png) - ---- -##### Realizando un commit -Con estos cambios realizaremos un commit en el repositorio local desde la terminal con "git add" y git "commit" - -```bash -# Verificamos el estado -git status -# Adicionamos los cambios -git add . -# Verificamos el estado -git status -# Realizamos el commit -git commit -m "Modificación ignore y readme" -# Verificamos el log de commits -git log -``` - ---- -![Markdown](./img/14.png) - ---- -##### Sincronizar datos de subida -Cuando se clonó el repositorio desde GitHub a la PC local, se realizó una copia del repositorio en la nube (remoto) a la computadora del desarrollador (local) - -![Markdown](./img/15.png) - ---- -Con el comando git remote -v, se puede ver la URL del repositorio remoto en GitHub - -```bash -git remote -v -``` -![Markdown](./img/16.png) - ---- -Para sincronizar los datos de subida, se utiliza el comando "git push" - -Un push comunica un repositorio con otro repositorio, calcula lo que el repositorio local tiene que el repositorio remoto no tiene y luego sube la diferencia al repositorio remoto - -Para el proceso se requiere autenticación, se solicitará las credenciales de GitHub - ---- -Existen dos formas de realizar el push mediante la interfaz de VS Code o mediante la terminal - -La interfaz de VS Code es más sencilla, se da click en el botón de Control de Código y se selecciona "Sync" - -![Markdown](./img/17.png) - ---- -Mediante la terminal, se utilizará las credenciales - -GitHub eliminó el uso de contraseñas para autenticarse, ahora se utiliza un token de acceso personal como contraseña - -Dirigirse en la página de GitHub a Settings > Developer settings > Personal access tokens > [Tokens (classic)](https://github.com/settings/tokens) - -Selecciona "Generate new token" y se abrirá una ventana para crear un token - -![Markdown](./img/18.png) - ---- -Agregar una nota para identificar el token, seleccionar la fecha de expiración y seleccionar los permisos - -![Markdown](./img/19.png) - ---- -Una vez creado el token, se copia ya que no se puede ver nuevamente - -![Markdown](./img/20.png) - -El token generado se introduce como contraseña en la terminal para realizar el push - ---- -Después de realizar el push, la terminal solicitará las credenciales de GitHub para autenticarse -```bash -git push -``` -![Markdown](./img/21.png) - -Se observa que se realizó el push y se sincronizaron los datos de subida - ---- -Desde el navegador, se observa que se sincronizaron los datos del repositorio local al repositorio remoto y se visualiza el archivo README.md - -![Markdown](./img/22.png) - ---- -Como resultado final tenemos sincronizado el repositorio local con el repositorio remoto en GitHub - -![Markdown](./img/23.png) - ---- -##### Sincronizar datos de bajada - -La acción del comando "git pull" es utilizado para buscar cambios (fetch) - -Descargarlos de un repositorio remoto y actualizar el repositorio local con el contenido - -El comando "git pull", primero ejecuta el comando "git fetch" que busca los cambios del repositorio remoto, luego ejecuta "git merge" que combina la referencia del contenido remoto con la referencia del contenido local actualizando el repositorio - ---- -Este escenario se puede visualizar donde D es el punto inicial donde se realizó el clone, - -A, B, C son los commits realizados en el repositorio remoto posterior al clone - -E, F, G son los commits realizados en el repositorio local - -![Markdown](./img/24.png) - ---- -Se realiza el comando "git pull" - -Los cambios en el punto donde el main local y main remoto divergen con A, B, C y se realiza el merge generando un nuevo commit H - -![Markdown](./img/25.png) - ---- -Para probar este escenario utilizaremos el editor online de GitHub para modificar el archivo remoto y desde la terminal realizaremos el pull - -Crear el archivo "cloud.txt" en el repositorio remoto con un contenido Lorem Ipsum - -![Markdown](./img/26.png) -![Markdown](./img/27.png) - ---- -Después de editar el archivo, hacer click al botón "Commit changes" - -![Markdown](./img/28.png) - ---- -Ahora el repositorio cuenta con más commits que el repositorio local - -![Markdown](./img/29.png) - ---- -Los nuevos cambios se deben sincronizar con el repositorio local, utilizamos el comando "git pull" - -```bash -git pull -``` -![Markdown](./img/30.png) - -Observamos que ya se descargo el archivo cloud.txt - ---- -Utilizando el comando "git log", se observa que se realizó un nuevo commit con el archivo cloud.txt - -```bash -git log -``` - -Vemos que existe el commit y la cabeza del repositorio main (local) y main (remoto) "origin" es el mismo estando el repositorio actualizado - -![Markdown](./img/31.png) - ---- -##### Creando un repositorio remoto vacío en GitHub - -Vimos que se puede clonar un repositorio remoto en GitHub a la PC local - -Se puede modificar bidireccionalmente, los cambios y sincronizarlos - -Existen escenarios donde el proyecto se inicia en la PC local y se desea subir a GitHub, para esto se crea un repositorio remoto vacío en GitHub - ---- -Crearemos un repositorio remoto vacío en GitHub para el primer proyecto "psg-example" donde no tendrá ningún archivo solo su nombre y visibilidad pública - -![Markdown](./img/32.png) - ---- -Después de crearlo observamos que el repositorio está vacío y tiene sugerencias para iniciar el repositorio - -![Markdown](./img/33.png) - ---- -##### Agregar remoto a un repositorio local - -Abrimos el proyecto "psg-example" desde la terminal -```bash -cd 2025 -code psg-example -``` -![Markdown](./img/34.png) - -![Markdown](./img/35.png) - ---- -Antes de agregar el remoto crearemos un archivo "sesion02.md" un archivo markdown - -Escribiremos como un enlace la URL de nuestro otro repositorio creado "psg02" - -```markdown -# Sesión 02 -[Enlace a mi otro repositorio](https://github.com/ej2v/psg02) -``` - -![Markdown](./img/38.png) - ---- -Guardamos y realizamos un commit en nuestro repositorio local - -```bash -git add . -git commit -m "Sesión 2 Introducción a GitHub" -``` - -![Markdown](./img/39.png) - ---- -Ahora en la terminal de VS Code usaremos el comando "git remote add" para agregar el repositorio remoto - -```bash -# Agregar un remoto a un repositorio local -git remote add -# Cambiar el nombre de nuestra rama principal a un nombre nuevo -git branch -M -# Publicar los cambios hacia el repositorio remoto -git push -u -``` - ---- -Para el proyecto "psg-example" utilizaremos el nombre remoto "origin" y branch principal "main" -```bash -git remote add origin https://github.com/ej2v/psg-example.git -git branch -M main -``` ---- -##### Publicar el repositorio local al remoto -El último paso en "git push" agrega la bandera -u que significa "upstream", establece una relación de seguimiento entre la rama local y la rama remota - -Para facilitar futuros comandos "git push" y "git pull" - -```bash -git push -u origin main -``` - -![Markdown](./img/36.png) - ---- -Ingresando a GitHub, observamos que se sincronizaron los datos del repositorio local al repositorio remoto - -![Markdown](./img/37.png) - ---- -##### Resumen - -- Creamos un repositorio remoto en GitHub -- Selección de .gitignore y README.md -- Clonar un repositorio remoto en la PC local con `git clone` -- Abrir el repositorio en VS Code - ---- -- `.gitignore` y su función de ignorar archivos y directorios -- `README.md` y su función de mostrar información del proyecto -- Markdown es un lenguaje de marcado ligero para dar formato a texto plano -- Puede ir en diferentes directorios como `.github`, `docs` o en la raíz del repositorio - ---- -- La sintaxis de Markdown nos permite crear títulos, negrillas, itálicas, citas -- Tmabien crear listas ordenadas y no ordenadas, código, enlaces e imágenes -- Realizamos un commit para guardar los cambios -- El repositorio remoto se puede ver con `git remote -v` - ---- -- La sincronización de datos de subida con `git push` -- Para utilizar `git push` se necesita un token de acceso personal -- GitHub eliminó el uso de contraseñas para autenticarse -- Se debe crear un token de acceso personal en la página de GitHub para acceder desde la Terminal - ---- -- Se observa el archivo README.md en el repositorio remoto en GitHub -- La sincronización de datos de bajada con `git pull` -- `git pull` busca cambios en el repositorio remoto y actualiza el repositorio local -- `git log` muestra los commits realizados en el repositorio - ---- -- Creamos un repositorio remoto vacío en GitHub -- Agregamos un remoto a un repositorio local con `git remote add` -- Publicamos el repositorio local al remoto con `git push -u` - ---- -##### Retos - -Crear una carpeta con el nombre "retos_sesion_02" dentro del proyecto, en la cual por cada ejercicio debes crear un archivo - -```bash -# Ejemplo carpeta -psg-example/ - retos_sesion_02/ - ejercicio_01.md - ejercicio_02.md - Readme.md -``` - ---- -1. Crea un archivo llamado "ejercicio_01.md" y escribe una receta para hacer un sandwich de mantequilla y mermelada, guarda el archivo y realiza un commit con el mensaje "Receta de sandwich de mantequilla y mermelada", utiliza Markdown y sube el archivo al repositorio remoto con el comando `git push` - ---- -2. Crea un archivo llamado "ejercicio_02.md" y haz una breve biografía tuya, utiliza Markdown con títulos, negrillas, itálicas, listas ordenadas y no ordenadas, y una cita con una frase que te motiva a seguir adelante, guarda el archivo y realiza un commit con el mensaje "Biografía personal", sube el archivo al repositorio remoto con el comando `git push` - -> Puedes añadir una imagen tuya en la carpeta añadirla al markdown y subirla al repositorio - ---- -3. Crea un archivo "Readme.md" en la raiz del proyecto, escribe una breve descripción de tu repositorio del Python Study Group For Beginners, utiliza Markdown, guarda el archivo y realiza un commit con el mensaje "Descripción del proyecto", sube el archivo al repositorio remoto con el comando `git push` - - ---- - - -
-
-
-
-
- -[![GitHub](../../content/github_logo.png) ](https://github.com/python-la-paz/python-study-group-fundamentals/tree/main/content/sesion02) - -Repositorio de la Sesión - ---- - -## Bibliografía y Referencias - -- [What is GitHub?](https://kinsta.com/knowledgebase/what-is-github/) -- [Logos](https://github.com/logos) -- [Creating an account on GitHub](https://docs.github.com/en/get-started/quickstart/creating-an-account-on-github) -- [Customizing your repository](https://docs.github.com/es/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-readmes) -- [What is .gitignore](https://www.atlassian.com/es/git/tutorials/saving-changes/gitignore) -- [Getting started with Markdown](https://www.markdownguide.org/getting-started/) -- [Markdown Cheat Sheet](https://www.markdownguide.org/cheat-sheet/) -- [Compartir y actualizar proyectos](https://git-scm.com/book/es/v2/Ap%C3%A9ndice-C%3A-Comandos-de-Git-Compartir-y-Actualizar-Proyectos) -- [Syncing](https://www.atlassian.com/git/tutorials/syncing) -- [Git Pull](https://www.atlassian.com/git/tutorials/syncing/git-pull) \ No newline at end of file diff --git a/content/sesion02/img/04.png b/content/sesion02/img/04.png deleted file mode 100644 index f36d533..0000000 Binary files a/content/sesion02/img/04.png and /dev/null differ diff --git a/content/sesion02/img/05.png b/content/sesion02/img/05.png deleted file mode 100644 index 1cc5b18..0000000 Binary files a/content/sesion02/img/05.png and /dev/null differ diff --git a/content/sesion02/img/06.png b/content/sesion02/img/06.png deleted file mode 100644 index e1c45e0..0000000 Binary files a/content/sesion02/img/06.png and /dev/null differ diff --git a/content/sesion02/img/07.png b/content/sesion02/img/07.png deleted file mode 100644 index 1be2c68..0000000 Binary files a/content/sesion02/img/07.png and /dev/null differ diff --git a/content/sesion02/img/08.png b/content/sesion02/img/08.png deleted file mode 100644 index 3464186..0000000 Binary files a/content/sesion02/img/08.png and /dev/null differ diff --git a/content/sesion02/img/09.png b/content/sesion02/img/09.png deleted file mode 100644 index 7a33cf1..0000000 Binary files a/content/sesion02/img/09.png and /dev/null differ diff --git a/content/sesion02/img/10.png b/content/sesion02/img/10.png deleted file mode 100644 index d62c964..0000000 Binary files a/content/sesion02/img/10.png and /dev/null differ diff --git a/content/sesion02/img/11.png b/content/sesion02/img/11.png deleted file mode 100644 index 2b66ac3..0000000 Binary files a/content/sesion02/img/11.png and /dev/null differ diff --git a/content/sesion02/img/12.png b/content/sesion02/img/12.png deleted file mode 100644 index 035f760..0000000 Binary files a/content/sesion02/img/12.png and /dev/null differ diff --git a/content/sesion02/img/13.png b/content/sesion02/img/13.png deleted file mode 100644 index accc232..0000000 Binary files a/content/sesion02/img/13.png and /dev/null differ diff --git a/content/sesion02/img/14.png b/content/sesion02/img/14.png deleted file mode 100644 index 2e1c039..0000000 Binary files a/content/sesion02/img/14.png and /dev/null differ diff --git a/content/sesion02/img/15.png b/content/sesion02/img/15.png deleted file mode 100644 index 7f180f1..0000000 Binary files a/content/sesion02/img/15.png and /dev/null differ diff --git a/content/sesion02/img/16.png b/content/sesion02/img/16.png deleted file mode 100644 index cfc4e03..0000000 Binary files a/content/sesion02/img/16.png and /dev/null differ diff --git a/content/sesion02/img/17.png b/content/sesion02/img/17.png deleted file mode 100644 index 2143d53..0000000 Binary files a/content/sesion02/img/17.png and /dev/null differ diff --git a/content/sesion02/img/18.png b/content/sesion02/img/18.png deleted file mode 100644 index 7755088..0000000 Binary files a/content/sesion02/img/18.png and /dev/null differ diff --git a/content/sesion02/img/19.png b/content/sesion02/img/19.png deleted file mode 100644 index 439f093..0000000 Binary files a/content/sesion02/img/19.png and /dev/null differ diff --git a/content/sesion02/img/20.png b/content/sesion02/img/20.png deleted file mode 100644 index f326853..0000000 Binary files a/content/sesion02/img/20.png and /dev/null differ diff --git a/content/sesion02/img/21.png b/content/sesion02/img/21.png deleted file mode 100644 index 20ab60b..0000000 Binary files a/content/sesion02/img/21.png and /dev/null differ diff --git a/content/sesion02/img/22.png b/content/sesion02/img/22.png deleted file mode 100644 index 22ef7c4..0000000 Binary files a/content/sesion02/img/22.png and /dev/null differ diff --git a/content/sesion02/img/23.png b/content/sesion02/img/23.png deleted file mode 100644 index 26399be..0000000 Binary files a/content/sesion02/img/23.png and /dev/null differ diff --git a/content/sesion02/img/24.png b/content/sesion02/img/24.png deleted file mode 100644 index f1e5f12..0000000 Binary files a/content/sesion02/img/24.png and /dev/null differ diff --git a/content/sesion02/img/25.png b/content/sesion02/img/25.png deleted file mode 100644 index 7166d03..0000000 Binary files a/content/sesion02/img/25.png and /dev/null differ diff --git a/content/sesion02/img/26.png b/content/sesion02/img/26.png deleted file mode 100644 index d28297b..0000000 Binary files a/content/sesion02/img/26.png and /dev/null differ diff --git a/content/sesion02/img/27.png b/content/sesion02/img/27.png deleted file mode 100644 index 515b3ee..0000000 Binary files a/content/sesion02/img/27.png and /dev/null differ diff --git a/content/sesion02/img/28.png b/content/sesion02/img/28.png deleted file mode 100644 index 22cd0e6..0000000 Binary files a/content/sesion02/img/28.png and /dev/null differ diff --git a/content/sesion02/img/29.png b/content/sesion02/img/29.png deleted file mode 100644 index 971f68a..0000000 Binary files a/content/sesion02/img/29.png and /dev/null differ diff --git a/content/sesion02/img/30.png b/content/sesion02/img/30.png deleted file mode 100644 index 9315d2d..0000000 Binary files a/content/sesion02/img/30.png and /dev/null differ diff --git a/content/sesion02/img/31.png b/content/sesion02/img/31.png deleted file mode 100644 index f4f2f20..0000000 Binary files a/content/sesion02/img/31.png and /dev/null differ diff --git a/content/sesion02/img/32.png b/content/sesion02/img/32.png deleted file mode 100644 index 2a5cc55..0000000 Binary files a/content/sesion02/img/32.png and /dev/null differ diff --git a/content/sesion02/img/33.png b/content/sesion02/img/33.png deleted file mode 100644 index 5d0b8d2..0000000 Binary files a/content/sesion02/img/33.png and /dev/null differ diff --git a/content/sesion02/img/34.png b/content/sesion02/img/34.png deleted file mode 100644 index aa4fa3e..0000000 Binary files a/content/sesion02/img/34.png and /dev/null differ diff --git a/content/sesion02/img/35.png b/content/sesion02/img/35.png deleted file mode 100644 index beda764..0000000 Binary files a/content/sesion02/img/35.png and /dev/null differ diff --git a/content/sesion02/img/36.png b/content/sesion02/img/36.png deleted file mode 100644 index ff6f274..0000000 Binary files a/content/sesion02/img/36.png and /dev/null differ diff --git a/content/sesion02/img/37.png b/content/sesion02/img/37.png deleted file mode 100644 index 03a641d..0000000 Binary files a/content/sesion02/img/37.png and /dev/null differ diff --git a/content/sesion02/img/38.png b/content/sesion02/img/38.png deleted file mode 100644 index ab84a95..0000000 Binary files a/content/sesion02/img/38.png and /dev/null differ diff --git a/content/sesion02/img/39.png b/content/sesion02/img/39.png deleted file mode 100644 index f0accd1..0000000 Binary files a/content/sesion02/img/39.png and /dev/null differ diff --git a/content/sesion02/index.html b/content/sesion02/index.html deleted file mode 100644 index 4a7c3b9..0000000 --- a/content/sesion02/index.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - Sesión 02 | Python Study Group | Fundamentals - - - - - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/content/sesion03/Readme.md b/content/sesion03/Readme.md deleted file mode 100644 index c65f82c..0000000 --- a/content/sesion03/Readme.md +++ /dev/null @@ -1,540 +0,0 @@ - -![Python La paz](../Logo.png) - -
-
-
- -### Sesión 03 -### Iniciando nuestro Setup -### Introducción a Python I ---- -##### ¿Por qué aprender a escribir programas? - ---- -Escribir programas es una actividad muy creativa, puedes escribir programas por muchas razones - -- Desde mantenerte activo resolviendo un problema por diversión -- Hasta resolver un problema de análisis de datos complejos - ---- -En la vida cotidiana estamos rodeados de computadoras (laptops y celulares), son como asistentes personales que se ocupan de muchas tareas - -- Sacar fotografías -- Escuchar música -- Revisar correo electrónico -- Llamar a otras personas, etc. ---- -Son muy útiles, poseen gran procesamiento y memoria - -Si fuera tan fácil explicarle al dispositivo que queremos que haga ahora - -Tener un idioma y explicarle que queremos ahora - ---- -Y ese lenguaje se encuentra en la **programación** - -Crear obras escritas que pueda entender las computadoras y realizar acciones - -Como tareas repetitivas o aburridas como limpiar el SPAM en el correo electrónico - ---- -##### Comprendiendo la programación - -Necesitas dos capacidades para ser programador: - -1. **Saber un lenguaje de programación**, conocer su vocabulario y su gramática, ser capaz de deletrear correctamente las palabras y saber construir "frases" bien formadas y coherentes - ---- - -##### Comprendiendo la programación - -Necesitas dos capacidades para ser programador: - -2. **Saber contar una historia**, al escribir un cuento se combinan palabras, frases para comunicar la idea al lector, nuestro programa es el cuento y el problema a resolver es la idea a comunicar. - ---- -Vamos a utilizar Python como nuestro lenguaje de programación - ---- -![Python](./img/01.png) -##### ¿Qué es Python? ---- -Python es un lenguaje de programación -- Interpretado -- Orientado a objetos -- De alto nivel -- Con semántica dinámica ---- -La sintaxis simple y fácil de aprender de Python enfatiza en la legibilidad, reduciendo el costo de mantenimiento del programa y la reutilización de código - ---- -El intérprete de Python y la biblioteca está disponible en formato fuente o binarios sin costo para todas las plataformas y se distribuye gratuitamente - -![Interprete](./img/02.png) - ---- -##### Algunas características de Python - ---- -- **Usa una sintaxis elegante**, haciendo los programas escritos fáciles de leer -- **Es un lenguaje "easy-to-use"**, es muy fácil empezar a programar, ideal para desarrollo de prototipos -- El modo interactivo de Python permite probar fragmentos de código fácilmente -- Es fácil extender añadiendo nuevos módulos implementados en lenguajes compilados como C o C++ - ---- -- **Ejecuta en cualquier lugar**, incluido Windows, Linux, Mac OS, de manera no oficial Android y iOS -- **Es software libre en dos sentidos**, no tiene ningún costo de descarga ni costo de uso -- El lenguaje tiene **derechos de autor** pero está bajo una licencia de open source software y puede ser modificado y redistribuido - ---- -##### Algunas características del -##### *lenguaje de programación Python* - ---- -- Variedad de tipos de datos básicos disponibles, numbers (punto flotante, complejos, enteros sin límite de longitud), cadenas (ASCII y Unicode), listas y diccionarios -- Python soporta programación orientada a objetos con clases y múltiples herencias - ---- -- El código puede ser agrupado en módulos y paquetes -- Admite el manejo de excepciones, resultando en un manejo limpio de errores - ---- -- Tipos de datos se escriben de manera fuerte y dinámica - -Combinar tipos de datos incompatibles genera excepciones que pueden ser detectadas antes como adicionar una cadena a un número - ---- -- Python posee componentes avanzados como generadores y listas por comprensión -- Administra automáticamente la memoria liberando y asignando memoria libre al código - ---- -Escribir código Pythónico no es difícil - -Pero tienes que utilizar las reglas de estilo de código (PEP) para mejorar la elegancia y legibilidad del código - -Puedes probar, revisar y mejorar tu código la herramienta online [Python 3 Style Checker](https://www.codewof.co.nz/style/python3/) - -> Makes Your Code Great Again - ---- -##### ¿Cuál es su campo de aplicación? - -Es ampliamente utilizado en -- Aplicaciones web -- Automatización -- Desarrollo de software -- Ciencia de datos -- Machine learning (ML) - ---- -##### Desarrollo web del lado del servidor - -Incluye las funciones complejas de backend que los sitios web llevan a cabo para mostrar información al usuario - -Interacción con las bases de datos, comunicarse con otros sitios web y proteger los datos cuando se los envía a través de la red - ---- -Python es útil para escribir código del lado del servidor debido a que ofrece muchas bibliotecas - -Que constan de código pre escrito para crear funciones de backend complejas - ---- -##### Automatización con scripts de Python - -Automatiza las tareas que suelen llevar a cabo las personas - -Se utilizan ampliamente los scripts de Python para automatizar muchas tareas diarias - ---- -- Cambiar el nombre de una gran cantidad de archivos a la vez -- Convertir un archivo en otro tipo de archivo -- Eliminar palabras duplicadas de un archivo de texto -- Llevar a cabo operaciones matemáticas básicas - ---- -- Enviar mensajes por email -- Descargar contenido -- Efectuar análisis básicos de registros -- Encontrar errores en varios archivos - ---- -##### Tareas de ciencia de datos y machine learning - -Extraer conocimientos valiosos a partir de los datos - -Mientras se le enseña a las computadoras a aprender automáticamente de los datos y a efectuar predicciones precisas - ---- -Utilizan Python para realizar tareas de ciencia de datos, como las que se indican: - -- Corregir y eliminar datos incorrectos, lo que se conoce como limpieza de datos -- Extraer y seleccionar varias características de los datos, que consiste en agregar nombres significativos a los datos - ---- -- Buscar diferentes estadísticas a partir de los datos -- Visualizar los datos mediante el uso de tablas y gráficos, como los gráficos de líneas, los de barras, los circulares y los histogramas - ---- -Los científicos de datos utilizan las bibliotecas de ML de Python para entrenar los modelos de ML y crear clasificadores que organicen los datos con precisión - ---- -##### Desarrollo de software - -Los desarrolladores de software suelen utilizar Python para realizar distintas tareas de desarrollo y aplicaciones de software - ---- -- Realizar un seguimiento de los errores en el código del software -- Crear el software de forma automática -- Administrar los proyectos de software - ---- -- Desarrollar prototipos de software -- Desarrollar aplicaciones de escritorio por medio de las bibliotecas de interfaz gráfica de usuario (GUI) -- Desarrollar juegos simples basados en texto a videojuegos más complejos - ---- -##### ¿Quién lo mantiene? - -Python fue creado por Guido van Rossum, y lanzado en 1991 versión 0.9.0, él fue el Benevolente Dictador de por Vida (BDFL), se retiró como BDFL el año 2018 - -![Guido](./img/03.png) - ---- -- Tenía la autoridad final de tomar decisiones en disputas dentro de la comunidad de desarrollo de Python -- Guía y Visión, establecía los principios que rigen el lenguaje y las directrices para el diseño del mismo - ---- -- Revisión de PEPs, tenía la responsabilidad de revisar y aprobar todos los documentos PEPs que son los (Python Enhancement Proposals) que describen características o cambios en Python - ---- -Posterior a su retiro el mantenimiento del lenguaje de programación Python paso a un modelo de toma de decisiones más democrático - -Mantenido por la comunidad y la - -**Python Software Foundation** - ---- -##### Python Software Foundation (PSF) - -Es una organización dedicada al avance de la tecnología open source relacionada con el lenguaje de programación Python - -Es la organización actual detrás del lenguaje, y se dedica a crear las condiciones para que Python y la comunidad Python crezcan - ---- -###### Actividades principales - -*Infraestructura* - -> Generar estructura y estabilidad para prosperar - -- Distribuir Python de forma gratuita y disponible para todos, para siempre - ---- -- Administradores de la Propiedad Intelectual, establece licencias PSF, poseen derechos sobre la mayoría de las versiones de Python y las marcas comerciales -- Destinan recursos para coordinar y mejorar el código base de Python y las nuevas versiones - ---- -*Comunidad* - -> Crear conexión, diversidad, apoyo y crecimiento para todos dentro la comunidad - -- Organizar la PyCon US, evento anual de mayor duración para celebrar, reunirse y aprender en torno a Python - ---- -- Otorgar subvenciones a grupos de todo el mundo que organizan eventos para y por Pythonistas que se apoyan mutuamente y dan la bienvenida a los recién llegados. -- Responsables de establecer, mantener y cumplir el Código de Conducta, para trabajar en un espacio seguro y acogedor para todos. - ---- -*Invertir en Python y Herramientas* - -> Construir, apoyar y mantener los bienes públicos críticos para la comunidad - -- Alojar **PyPI**, el repositorio de paquetes de Python en el que confían miles de usuarios con una amplia gama de proyectos - ---- -- Adicionado Desarrolladores en CPython a tiempo completo para mejorar la extracción de CPython y abordar mejoras estructurales - ---- -##### Instalación de Python - -Python se puede descargar desde su pagina oficial [Python](https://www.python.org/downloads/) para todas las plataformas - -Para Windows es necesario descargar los binarios desde la página oficial e instalarlos, puede ser añadido al PATH para ser accesible desde cualquier lugar - ---- -![Windows](./img/04.png) - ---- -![Windows](./img/05.png) - ---- -![Windows](./img/06.png) - ---- -![Windows](./img/06_1.png) - ---- -Python es una herramienta integral en muchos sistemas operativos basados en Linux - -Por lo cual la mayoría de las veces ya traen una instalación de Python predeterminada - -Puedes verificar si se encuentra instalado ejecutando - -```sh -python --version -# o -python3 --version -``` ---- -Si no se encuentra una instalación puede instalarse mediante el gestor de paquetes - -```sh [1-2|3-5|6-7|8-11] -# Ubuntu & Debian -apt install python3 -# CentOS, Fedora &RHEL -dnf install python3 -yum install python3 -# MacOS -brew install python -# Utilizamos para verificar la instalación -python --version -# o -python3 --version -``` -![Instalación](./img/07.png) - ---- -##### ¿Qué es un archivo con extensión ".py"? - -Los archivos con la extensión .py contienen código fuente de Python - -El formato del archivo **.py** se basa en python que fue diseñado para facilitar la lectura y tiene similitudes con el inglés y las matemáticas - ---- -Utiliza líneas nuevas para indicar el comando completo en lugar de puntos, comas o paréntesis como se utilizan en otros idiomas - -Python se basa en la sangría y los espacios en blanco en lugar de llaves comúnmente usadas - ---- -Algunas prácticas comunes al nombrar archivos de Python - ---- -- Usar nombres en minúsculas "script.py" -- Utilizar guiones bajos para separar palabras en lugar de espacios "mi_script.py" - ---- -- Evita usar caracteres especiales y espacios "year.py" en lugar de "año.py" -- Evita utilizar nombres que coincidan con módulos estándar de Python "math.py" ya que existe el módulo estándar math - ---- -Según la guía de estilo para Python PEP 8 - ---- -- Utilizar 4 espacios por nivel de indentación -- No usar el símbolo de tabulador sino espaciado - ---- -- Limitar las líneas de código a 79 caracteres para código -- Limitar las líneas de código a 72 caracteres para comentarios - ---- -##### Mi primer hola mundo - -Abrimos el proyecto que tenemos ya creado en una sesión pasada - -```sh -code .\psg-example -``` - ---- -Crearemos el archivo **sesion03.py** este archivo será nuestro primer hola mundo -![Hola Mundo](./img/08.png) - ---- -Escribiremos en el área de edición - -```python -print ("Hola Mundo") -``` -![Hola Mundo](./img/09.png) - ---- -La instrucción escrita en el archivo significa lo siguiente -- **print**: Es la función básica para imprimir contenido en la terminal, todos los elementos a imprimir son convertidos a caracteres -- **"Hola Mundo"**: Es el contenido de tipo cadena que vamos a imprimir en la terminal - ---- -##### Ejecutar desde la terminal - -Abrimos una terminal integrada de VS Code - -![Terminal](./img/10.png) - -Nos encontramos ubicados en la ruta del proyecto desde aquí podemos ejecutar el archivo que hemos creado - ---- -Ejecutaremos el comando - -```sh -python sesion03.py -``` - -![Terminal](./img/11.png) - -El comando se divide de la siguiente manera - -- python: Esa parte del comando se encarga de invocar al intérprete de Python para ejecutar alguna acción o archivo - ---- -- sesion03.py: Hace referencia al archivo que queremos que Python ejecute -- Hola Mundo: Es la salida después de ejecutar el archivo ".py" - ---- -##### Terminal interactiva de python - -La consola interactiva es una herramienta que nos permite escribir sentencias de código de Python al mismo tiempo que se ejecutan - -Ideal para probar pequeñas porciones de código - -Al cerrarla se pierde todo lo que hayamos escrito en ella - ---- -Para invocar la terminal interactiva solo se debe escribir el comando python - -```sh -python -``` -![Terminal](./img/12.png) - -Aquí la terminal cambia y nos indica con los caracteres ">>>" que es donde debemos escribir código Python - ---- -Escribamos ahora ahí "Hola desde la Terminal" y presionamos Enter - -```python ->>> print ("Hola desde la Terminal") -``` - -![Terminal](./img/13.png) - ---- -Para cerrar la terminal interactiva utilizamos la función y palabra clave quit() - -```python ->>> quit() -``` - -![Terminal](./img/14.png) - ---- -Realizaremos un commit de nuestros cambios al repositorio - -```sh -git add sesion03.py -git commit -m "Adición de la sesión 3" -git push -``` -![Git](./img/15.png) - ---- -##### Resumen - -- Escribir programas es una actividad creativa que puede ser realizada por diversión o para resolver problemas -- En la vida cotidiana estamos rodeados de computadoras que realizan tareas repetitivas o aburridas - ---- -- Para programar necesitas dos capacidades saber un lenguaje de programación y saber contar una historia -- Python es un lenguaje de programación interpretado, orientado a objetos, de alto nivel y con semántica dinámica - ---- -- Python es fácil de aprender y de usar, se ejecuta en cualquier lugar y es software libre -- Python es utilizado en aplicaciones web, automatización, desarrollo de software, ciencia de datos y machine learning - ---- -- Python fue creado por Guido van Rossum y actualmente es mantenido por la Python Software Foundation -- Guido van Rossum fue el Benevolente Dictador de por Vida (BDFL) de Python hasta 2018 - ---- -- Luego de su retiro el mantenimiento de Python paso a un modelo de toma de decisiones más democrático -- Es mantenido por la comunidad y la Python Software Foundation - ---- -- La PSF es una organización dedicada al avance de la tecnología open source relacionada con Python -- Sus actividades principales son infraestructura, comunidad e invertir en Python y herramientas - ---- -- Python se puede instalar en Windows, Linux y MacOS -- Los archivos con extensión `.py` contienen código fuente de Python - ---- -- Utiliza lineas nuevas para indicar el comando completo en lugar de puntos, comas o paréntesis -- Python se basa en la sangría y los espacios en blanco en lugar de llaves comúnmente usadas - ---- -- Los nombres de los archivos de Python deben ser en minúsculas y utilizar guiones bajos para separar palabras -- No utilizar caracteres especiales y espacios en los nombres de los archivos - ---- -- No utilizar nombres que coincidan con módulos estándar de Python como math -- Se ejecuta un archivo `.py` con el comando `python nombre_archivo.py` - ---- -- La terminal interactiva de Python es una herramienta que permite escribir sentencias de código de Python al mismo tiempo que se ejecutan -- Se ejecuta la terminal interactiva de Python con el comando `python` - ---- -##### Retos - -Crear una carpeta con el nombre "retos_sesion_03" dentro del proyecto del "psg-example", por cada ejercicio debes crear un archivo - -```bash -# Ejemplo carpeta -psg-example/ - retos_sesion_03/ - ejercicio_01.py - ejercicio_02.py - ejercicio_03.py -``` - ---- -1. Crea un archivo llamado **ejercicio_01.py**, utiliza el comando `print` para imprimir el titulo y artista de una canción que más te gusta. Realiza un `commit` y un `push` para subir tus cambios. - ---- -2. Crea un archivo llamado **ejercicio_02.py** y con múltiples `print` muestra un diálogo entre una persona y su gato, donde salude al gato, el gato responda, la persona le haga una pregunta y el gato le responda, al final se despiden. Realiza un `commit` y un `push` para subir tus cambios. - ---- -3. Crea un archivo llamado **ejercicio_03.py** y utilizando múltiples `print` realiza un tutorial de como lavar los platos, se lo más detallado posible indica desde que tipo de esponja utilizar hasta el orden en que se lava y como secar los platos. Realiza un `commit` y un `push` para subir tus cambios. - ---- - - -
-
-
-
-
- -[![GitHub](../../content/github_logo.png) ](https://github.com/python-la-paz/python-study-group-fundamentals/tree/main/content/sesion03) - -Repositorio de la Sesión - ---- - -## Bibliografía y Referencias - -- [Python Learn](https://do1.dr-chuck.com/pythonlearn/ES_es/pythonlearn.pdf) -- [Python](https://www.python.org/doc/essays/blurb/) -- [Python Beginners Guide](https://wiki.python.org/moin/BeginnersGuide/Overview) -- [Python 3 Style Checker](https://www.codewof.co.nz/style/python3/) -- [AWS Python](https://aws.amazon.com/es/what-is/python/) -- [Python Institute](https://pythoninstitute.org/about-python) -- [Guido Van Rossum](https://gvanrossum.github.io/) -- [Linux Journal](https://www.linuxjournal.com/content/guido-van-rossum-stepping-down-role-pythons-benevolent-dictator-life) -- [Python Software Foundation](https://www.python.org/psf/about/) -- [Python 3.12.1](https://www.python.org/downloads/release/python-3121/) -- [Python Docs](https://docs.fileformat.com/es/programming/py/) -- [PEP 8](https://peps.python.org/pep-0008/#indentation) -- [Python Print](https://python-reference.readthedocs.io/en/latest/docs/functions/print.html) -- [Python Interpreter](https://docs.python.org/es/3/tutorial/interpreter.html) -- [Python Tutorial](https://tutorial.recursospython.com/consola-interactiva/) \ No newline at end of file diff --git a/content/sesion03/img/01.png b/content/sesion03/img/01.png deleted file mode 100644 index 037cc67..0000000 Binary files a/content/sesion03/img/01.png and /dev/null differ diff --git a/content/sesion03/img/02.png b/content/sesion03/img/02.png deleted file mode 100644 index 2ea8d15..0000000 Binary files a/content/sesion03/img/02.png and /dev/null differ diff --git a/content/sesion03/img/03.png b/content/sesion03/img/03.png deleted file mode 100644 index c19e8c1..0000000 Binary files a/content/sesion03/img/03.png and /dev/null differ diff --git a/content/sesion03/img/04.png b/content/sesion03/img/04.png deleted file mode 100644 index 61ce234..0000000 Binary files a/content/sesion03/img/04.png and /dev/null differ diff --git a/content/sesion03/img/05.png b/content/sesion03/img/05.png deleted file mode 100644 index 644d5fe..0000000 Binary files a/content/sesion03/img/05.png and /dev/null differ diff --git a/content/sesion03/img/06.png b/content/sesion03/img/06.png deleted file mode 100644 index 14a38cb..0000000 Binary files a/content/sesion03/img/06.png and /dev/null differ diff --git a/content/sesion03/img/06_1.png b/content/sesion03/img/06_1.png deleted file mode 100644 index 8023335..0000000 Binary files a/content/sesion03/img/06_1.png and /dev/null differ diff --git a/content/sesion03/img/07.png b/content/sesion03/img/07.png deleted file mode 100644 index a9fea25..0000000 Binary files a/content/sesion03/img/07.png and /dev/null differ diff --git a/content/sesion03/img/08.png b/content/sesion03/img/08.png deleted file mode 100644 index 89ab4f9..0000000 Binary files a/content/sesion03/img/08.png and /dev/null differ diff --git a/content/sesion03/img/09.png b/content/sesion03/img/09.png deleted file mode 100644 index 2b15655..0000000 Binary files a/content/sesion03/img/09.png and /dev/null differ diff --git a/content/sesion03/img/10.png b/content/sesion03/img/10.png deleted file mode 100644 index 7c49e3a..0000000 Binary files a/content/sesion03/img/10.png and /dev/null differ diff --git a/content/sesion03/img/11.png b/content/sesion03/img/11.png deleted file mode 100644 index 186c42b..0000000 Binary files a/content/sesion03/img/11.png and /dev/null differ diff --git a/content/sesion03/img/12.png b/content/sesion03/img/12.png deleted file mode 100644 index 28c144d..0000000 Binary files a/content/sesion03/img/12.png and /dev/null differ diff --git a/content/sesion03/img/13.png b/content/sesion03/img/13.png deleted file mode 100644 index c48fdb8..0000000 Binary files a/content/sesion03/img/13.png and /dev/null differ diff --git a/content/sesion03/img/14.png b/content/sesion03/img/14.png deleted file mode 100644 index 0a40eff..0000000 Binary files a/content/sesion03/img/14.png and /dev/null differ diff --git a/content/sesion03/img/15.png b/content/sesion03/img/15.png deleted file mode 100644 index 3a6328e..0000000 Binary files a/content/sesion03/img/15.png and /dev/null differ diff --git a/content/sesion03/index.html b/content/sesion03/index.html deleted file mode 100644 index f38cf8e..0000000 --- a/content/sesion03/index.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - Sesión 03 | Python Study Group | Fundamentals - - - - - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/content/sesion04/Readme.md b/content/sesion04/Readme.md deleted file mode 100644 index 76ad76e..0000000 --- a/content/sesion04/Readme.md +++ /dev/null @@ -1,555 +0,0 @@ - -![Python La paz](../Logo.png) - -
-
-
- -### Sesión 04 -### Iniciando nuestro Setup -### Introducción a Python II ---- -##### Sintaxis básica - -La sintaxis son las reglas y estructuras fundamentales que rigen la construcción de instrucciones en el lenguaje de programación - -Es importante estas reglas ya que permite que el intérprete pueda entender y ejecutar código correctamente - ---- -Aspectos clave de la sintaxis básica - ---- -###### Indentación - -Python utiliza indentación para definir bloques de código - -A diferencia de otros lenguajes que utilizan llaves '{}' o palabras clave como 'begin', 'end' para delimitar los bloques de código - ---- -La indentación también llamada sangría consiste en espacios en blanco iniciales (espacios o tabulaciones) - -La ejecución de un archivo se rechaza si se mezcla tabulaciones y espacios en un mismo archivo - ---- -Según la guía de estilo de Python PEP8 se debe utilizar 4 espacios por cada nivel de indentación - -![Indentación](./img/01.png) - ---- -Ejemplo de indentación incorrecta - -```python[1-7|2-7|3|4|5-6|7] - def perm(l): # error: first line indented -for i in range(len(l)): # error: not indented - s = l[:i] + l[i+1:] - p = perm(l[:i] + l[i+1:]) # error: unexpected indent - for x in p: - r.append(l[i:i+1] + x) - return r # error: inconsistent dedent -``` - ---- -Ejemplo de indentación correcta pero no recomendada - -```python[1-11|2|3-4|5|6-10|10|11] -def perm(l): - # Compute the list of all permutations of l - if len(l) <= 1: - return [l] - r = [] - for i in range(len(l)): - s = l[:i] + l[i+1:] - p = perm(s) - for x in p: - r.append(l[i:i+1] + x) - return r -``` - ---- -Ejemplo de indentación correcta según PEP8 - -```python[1-11|2|3-4|5-8|9-10|11] -def perm(l): -# Compute the list of all permutations of l - if len(l) <= 1: - return [l] - r = [] - for i in range(len(l)): - s = l[:i] + l[i + 1:] - p = perm(s) - for x in p: - r.append(l[i:i + 1] + x) - return r -``` - ---- -###### Comentarios - -Son una parte muy importante del código - -En especial al momento de leer código propio o ajeno - ---- -Puede contener una descripción de lo que hace el código o una explicación de por qué se hace de esa manera - -Ayudan a comprender lo que se hace en los diferentes bloques de código - ---- -Los comentarios en Python se pueden hacer de dos maneras - -- Comentarios de una sola línea -- Comentarios de varias líneas - ---- -Al momento de ejecutar código se ignoran los comentarios - -Son solo para la comprensión del programador - -Un comentario inicia con el carácter hash, - -numeral (#) - ---- -Comentarios de una sola línea - -```python -# This is a comment in one line -``` - ---- -Comentarios de varias líneas - -```python -# This is a comment -# in multiple -# lines -``` ---- -Comentario en línea con código - -```python -print("Hola, mundo!") # This is an inline comment -``` - ---- -Algunas reglas al momento de escribir comentarios - ---- -1. Siempre actualice el comentario cuando haya cambios en el código, un comentario contradictorio es peor que no tener comentarios -2. Los comentarios deben ser oraciones completas y deben empezar con letra capital - ---- -3. Los comentarios se recomiendan siempre escribirlos en Inglés, a no ser que esté 120% seguro que su código no va ser leído por personas que no hablan su idioma - ---- -###### Variables y tipos de datos - -En python las variables se pueden declarar sin especificar su tipo de dato ya que es de tipado dinámico - ---- -Los tipos de datos fundamentales incluyen -- Enteros -- Números de punto flotante -- Cadenas de texto -- Booleanos -- Listas -- Tuplas -- Conjuntos -- Diccionarios - ---- -###### Flujo de ejecución lineal - -El flujo de ejecución lineal se refiere a la secuencia ordenada de instrucciones que se ejecutan una tras otra - ---- - -Las instrucciones se ejecutan de arriba hacia abajo - -Línea por línea sin saltos o desviaciones - ---- -Ejemplo -```python[1-3|5-6|8-9|11-12] -# Example of execution flow -# Instruction 1 -print("Start of the program") - -# Instruction 2 -print(" Print second instruction") - -# Instruction 3 -print("Hello, World!") - -# Instruction 4 -print("End of the program") -``` - ---- -##### Jupyter Notebooks - -Es un entorno computacional interactivo antiguamente conocido como IPython, en el cual se puede combinar ejecución de código, texto enriquecido, matemáticas, gráficas y contenido multimedia enriquecido - ---- - -Provee una rica arquitectura para la computación interactiva como -- Una aplicación web para interactuar desde el navegador -- Un terminal interactiva -- Un Kernel para Jupyter -- Soporte para visualización interactiva - ---- -Utilizaremos el Kernel y la extensión de Jupyter para VS Code para interactuar no haremos uso del servidor de Jupyter desde el navegador - ---- -##### Instalación de la extensión en VS Code - -Para instalar la extensión de Jupyter para VS Code primero ingresamos a la pestaña de extensiones, donde encontraremos un buscador en el cual escribiremos "Jupyter" - -![Jupyter](./img/02.png) - ---- -Listará varias opciones disponibles de las cuales la que vamos a instalar la llamada "Jupyter" y el publisher es Microsoft - -Lleva un número 4 ya que es un paquete de varias extensiones más pequeñas - -![Jupyter](./img/03.png) - ---- -Seleccionado la extensión podemos ver que es lo que viene con la extensión - -La cantidad de veces que fue descargado la versión, la opción de "Instalar" y mucho más - -![Jupyter](./img/04.png) - ---- -Una vez instalado podemos instalar el kernel para poder empezar a utilizar los notebooks - ---- -##### Instalación del Kernel de Jupyter mediante PIP - -Vamos a instalar el kernel necesario para correr desde VS Code - -Lo instalaremos mediante el comando de instalación de librerías y paquetes de python "pip" - ---- -pip es "Package Installer for Python" el Instalador de paquetes para Python - -Nos permite instalar, desinstalar, listar los paquetes instalados - ---- -Practicaremos con pip veremos la versión de pip que tenemos instalada -```bash[1-2|3-6] -# Windows -pip --version -# Linux & Mac -pip --version -# o -pip3 --version -``` - -![PIP Version](./img/05.png) - ---- -Listemos los paquetes que tenemos actualmente instalados con el comando "list" - -```bash[1-2|3-6] -# Windows -pip list -# Linux & Mac -pip list -# o -pip3 list -``` - -![PIP List](./img/06.png) - ---- -Instalaremos el kernel de Jupyter con el comando de instalación "install" y el nombre del paquete - -```bash -pip install ipykernel -# o -pip3 install ipykernel -``` - -Al ejecutar instalará el paquete y todas las dependencias necesarias para su funcionamiento - ---- -Después de instalar podemos listar los paquetes instalados con "list" - -```bash -pip list -# o -pip3 list -``` - -![PIP List](./img/07.png) - ---- -Ya se encuentra instalado el Kernel - -Podemos empezar a utilizar los notebooks de Jupyter - -En VS Code - ---- -##### Mi primer notebook .ipynb - -Los archivos de notebooks tienen la extensión **.ipynb** - -Interactive PYthon NoteBook - -Contienen las entradas y salidas de las sesiones interactivas, el texto y contenido enriquecido - ---- -Internamente estos documentos son archivos JSON - -JSON es un formato de texto plano que puede ser versionado y compartido - ---- -En nuestro proyecto desde VS Code crearemos un archivo llamado "sesion04.ipynb" y lo abriremos - -![New Notebook I](./img/08.png) - -1. Botón "+ Code": Nos permite adicionar bloques de código -2. Botón "+ Markdown": Nos permite añadir bloques texto enriquecido con Markdown - ---- -![New Notebook II](./img/09.png) - -3. Botón "Run All": Para ejecutar todos los bloques de código en cadena de arriba hacia abajo -4. Botón "Restart": Para reiniciar toda la ejecución interactiva generada -5. Botón "Play": Para ejecutar una celda específica -6. Área para escribir código o Markdown -7. Kernel actual para realizar la ejecución - ---- -##### Adicionar bloques de código y comentarios - -Escribiremos hola mundo y ejecutaremos usando el botón Play - -```python -print ("Hola, Mundo desde Notebook!") -``` - ---- -![Hello World](./img/10.png) - -- Un número 1 entre corchetes indicando que es el primer fragmento ejecutado -- Tenemos un check y el tiempo que le tomó en ejecutar el código -- Salida de la ejecución - ---- -Agregaremos un comentario y volvemos a ejecutar - -```python -# Code 01 -print ("Hola, Mundo desde Notebook!") -``` - -![Hello World](./img/11.png) - -- El número de ejecución es 2, porque es la segunda ejecución -- El comentario "Code 01" no se ejecuta y la salida es la misma - ---- -##### Dibujar un árbol con prints en Notebook - -Como un ejercicio práctico dibujen un árbol con prints en el Notebook - - - ---- -Ejemplo - -![Tree](./img/12.png) - ---- -Solución - -```python -#Tree -print(" *") -print(" ***") -print(" *****") -print("*******") -print (" | |") -``` - -![Tree](./img/13.png) - ---- -##### Adicionar texto Markdown al Notebook - -Adicionaremos texto markdown al Notebook - -Crearemos un bloque con el botón - -**+ Markdown** - -Se abrirá un bloque en el cual escribiremos texto - ---- -```markdown -# Sesión 04 -- Mi primer notebook -- Imprimir árbol -- Crear Markdown -- Subir a mi repositorio de GitHub -``` - -![Markdown](./img/14.png) - ---- -Después de editar el contenido markdown hacemos click en el Botón check para visualizar el texto Markdown recién creado - -![Markdown](./img/15.png) - -Ahora vemos renderizado el contenido y el botón check es ahora botón editar - ---- -##### Subir a mi repositorio de GitHub - -Subiremos los cambios adicionando el archivo .ipynb a un commit y publicaremos los cambios en GitHub - -```bash -git add sesion04.ipynb -git commit -m "Sesión 4 Mi primer Notebook" -git push -``` - -![GitHub](./img/16.png) - ---- -Abriremos el repositorio en GitHub para visualizar el archivo del Notebook - -Con todo su contenido tanto las salidas de ejecución y el markdown escrito - -![GitHub](./img/17.png) - ---- -##### Resumen - -- La sintaxis es fundamental para la construcción de instrucciones en Python -- La indentación es el espacio en blanco inicial que se utiliza para definir bloques de código -- Los comentarios son una parte importante del código para la comprensión del programador - ---- -- Los tipos de datos fundamentales en Python son enteros, números de punto flotante, cadenas de texto, booleanos, listas, tuplas, conjuntos y diccionarios -- El flujo de ejecución lineal se refiere a la secuencia ordenada de instrucciones que se ejecutan una tras otra -- Jupyter Notebooks es un entorno computacional interactivo - ---- -- Permite combinar ejecución de código, texto enriquecido, matemáticas, gráficas y contenido multimedia enriquecido -- Posee kernel, terminal, aplicación web y soporte para visualización interactiva -- Se instala la extensión de Jupyter para VS Code y el kernel de Jupyter - ---- -- Se instala el kernel mediante pip con el comando `pip install ipykernel` -- Los archivos de notebooks tienen la extensión .ipynb -- Internamente son archivos JSON - ---- -- Jupyter posee bloques de código y comentarios -- Los bloques de texto enriquecido utilizan Markdown -- Se pueden ejecutar los notebooks en VS Code - ---- -- Los notebooks se pueden subir a un repositorio de GitHub -- Se visualizan en GitHub los notebooks con todo su contenido - ---- -##### Retos - -Crear una carpeta con el nombre "retos_sesion_04" dentro del proyecto del "psg-example", por cada ejercicio debes crear un archivo - -```bash -# Ejemplo carpeta -psg-example/ - retos_sesion_04/ - ejercicio_01.py - ejercicio_02.ipynb - ejercicio_03.py - ejercicio_04.ipynb -``` - ---- -1. Crea un archivo "ejercicio_01.py", añade un comentario con la descripción de este ejercicio y crea un triángulo rectángulo con prints - -```text -* -** -*** -**** -***** -``` - -Realiza un `commit` y un `push` para subir tus cambios - ---- -1. Crea un archivo "ejercicio_02.ipynb", añade un texto en markdown con la descripción de este ejercicio y crea una imagen utilizando símbolos y prints - -`Símbolos: * , () \ | / o " ' = C` - -```text -Ejemplo - (()(() - (=*o*)/") -C(,,)(,,) -``` - -Realiza un `commit` y un `push` para subir tus cambios - ---- -1. Crea un archivo "ejercicio_03.py", escribe las reglas de tu juego de mesa favorito con múltiples prints, por ejemplo: - -```text -Reglas tres en raya -1. El juego se juega en un tablero de 3x3 -2. Los jugadores eligen un símbolo para jugar -3. Inicia el jugador "X" -4. Continua el jugador "O" y así sucesivamente -5. No se puede jugar en una casilla ocupada -6. Gana el jugador que logre alinear tres símbolos en línea horizontal, vertical o diagonal -7. Si no hay más casillas disponibles y no hay ganador es empate -``` - -Realiza un `commit` y un `push` para subir tus cambios - ---- -4. Crea un archivo "ejercicio_04.ipynb", y diseña un juego - -- El título y descripción deben ser un bloque de markdown -- Las reglas deben ser un bloque de markdown -- El diseño del tablero debe ser un bloque de código en Python con prints -- La descripción de las piezas debe ser un bloque de markdown -- El diseño de las piezas debe ser un bloque de código en Python con prints - -Realiza un `commit` y un `push` para subir tus cambios - ---- - - -
-
-
-
-
- -[![GitHub](../../content/github_logo.png) ](https://github.com/python-la-paz/python-study-group-fundamentals/tree/main/content/sesion04) - -Repositorio de la Sesión - ---- - -## Bibliografía y Referencias - -- [Python Syntax](https://www.scaler.com/topics/python/python-syntax/) -- [Lexical Analysis](https://docs.python.org/3/reference/lexical_analysis.html#indentation) -- [PEP 8 Indentation](https://peps.python.org/pep-0008/#indentation) -- [What is Jupyter](https://jupyter-notebook-beginner-guide.readthedocs.io/en/latest/what_is_jupyter.html) -- [Jupyter Notebook Introduction](https://realpython.com/jupyter-notebook-introduction/) -- [IPython Notebook](https://ipython.org/notebook.html) -- [Jupyter](https://jupyter.org/) -- [Notebook](https://jupyter-notebook.readthedocs.io/en/stable/notebook.html) diff --git a/content/sesion04/img/01.png b/content/sesion04/img/01.png deleted file mode 100644 index 6d82d4a..0000000 Binary files a/content/sesion04/img/01.png and /dev/null differ diff --git a/content/sesion04/img/02.png b/content/sesion04/img/02.png deleted file mode 100644 index e80f04b..0000000 Binary files a/content/sesion04/img/02.png and /dev/null differ diff --git a/content/sesion04/img/03.png b/content/sesion04/img/03.png deleted file mode 100644 index 8cf0a1f..0000000 Binary files a/content/sesion04/img/03.png and /dev/null differ diff --git a/content/sesion04/img/04.png b/content/sesion04/img/04.png deleted file mode 100644 index 7575835..0000000 Binary files a/content/sesion04/img/04.png and /dev/null differ diff --git a/content/sesion04/img/05.png b/content/sesion04/img/05.png deleted file mode 100644 index 6ab658f..0000000 Binary files a/content/sesion04/img/05.png and /dev/null differ diff --git a/content/sesion04/img/06.png b/content/sesion04/img/06.png deleted file mode 100644 index ac9b659..0000000 Binary files a/content/sesion04/img/06.png and /dev/null differ diff --git a/content/sesion04/img/07.png b/content/sesion04/img/07.png deleted file mode 100644 index 634bebc..0000000 Binary files a/content/sesion04/img/07.png and /dev/null differ diff --git a/content/sesion04/img/08.png b/content/sesion04/img/08.png deleted file mode 100644 index 802e8d7..0000000 Binary files a/content/sesion04/img/08.png and /dev/null differ diff --git a/content/sesion04/img/09.png b/content/sesion04/img/09.png deleted file mode 100644 index 56f3434..0000000 Binary files a/content/sesion04/img/09.png and /dev/null differ diff --git a/content/sesion04/img/10.png b/content/sesion04/img/10.png deleted file mode 100644 index a9154ba..0000000 Binary files a/content/sesion04/img/10.png and /dev/null differ diff --git a/content/sesion04/img/11.png b/content/sesion04/img/11.png deleted file mode 100644 index 98c437e..0000000 Binary files a/content/sesion04/img/11.png and /dev/null differ diff --git a/content/sesion04/img/12.png b/content/sesion04/img/12.png deleted file mode 100644 index 6f326a8..0000000 Binary files a/content/sesion04/img/12.png and /dev/null differ diff --git a/content/sesion04/img/13.png b/content/sesion04/img/13.png deleted file mode 100644 index cb044d6..0000000 Binary files a/content/sesion04/img/13.png and /dev/null differ diff --git a/content/sesion04/img/14.png b/content/sesion04/img/14.png deleted file mode 100644 index f0645a1..0000000 Binary files a/content/sesion04/img/14.png and /dev/null differ diff --git a/content/sesion04/img/15.png b/content/sesion04/img/15.png deleted file mode 100644 index 53405c3..0000000 Binary files a/content/sesion04/img/15.png and /dev/null differ diff --git a/content/sesion04/img/16.png b/content/sesion04/img/16.png deleted file mode 100644 index 3f814a7..0000000 Binary files a/content/sesion04/img/16.png and /dev/null differ diff --git a/content/sesion04/img/17.png b/content/sesion04/img/17.png deleted file mode 100644 index 24726cb..0000000 Binary files a/content/sesion04/img/17.png and /dev/null differ diff --git a/content/sesion04/index.html b/content/sesion04/index.html deleted file mode 100644 index e4f08c2..0000000 --- a/content/sesion04/index.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - Sesión 04 | Python Study Group | Fundamentals - - - - - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/content/sesion05/Readme.md b/content/sesion05/Readme.md deleted file mode 100644 index ef7c69e..0000000 --- a/content/sesion05/Readme.md +++ /dev/null @@ -1,576 +0,0 @@ - -![Python La paz](../Logo.png) - -
-
-
- -### Sesión 05 -### Tipos de datos -### Datos numéricos ---- -### Valores y Variables - ---- -### ¿Que es un valor? - -- Un valor es es uno de los elementos mas básicos que utiliza un programa. - -- Puede ser un número, una letra o un conjunto de ambos. - -- El valor que vimos hasta ahora "Hola Mundo" es un valor de tipo "cadena" - ---- - -La función `type`, que funciona de forma parecida a `print`, nos permitirá identificar el tipo de dato de un valor. - -```python -type(valor) -``` - ---- -Crearemos un archivo python **"sesion05.py"** sobre el cual trabajaremos desde nuestro proyecto - ---- -Escribiremos la siguiente linea de código -```python -print(type(1)) -``` -Ejecutamos desde la terminal - -```bash -python sesion05.py -``` - ---- -![Type Python](./img/01.png) - - -- ``: Nos indica el tipo de dato del valor. En este caso es un entero (int) - -- `type(1)`: *type* devuelve el tipo de dato del valor que se le pasa como contenido. -- `print(type(1))`: *print* imprime el valor que se le pasa. - ---- -### ¿Qué es una variable? - -- Una *variable* es una forma de asignar un nombre a un *valor* para poder usarlo dentro de un programa. - -- Es una de las características más poderosas de cualquier lenguaje de programación, por que permite almacenar datos y reutilizarlos. - -- El programador es quien escoge el nombre de sus variables. - ---- - -### Reglas para nombrar variables en Python - ---- -Existen reglas para nombrar variables en Python - -- Pueden contener tanto letras como números -- **NO** pueden comenzar con un número -- **NO** pueden contener espacios -- Se puede utilizar tanto mayúsculas como minúsculas -- El signo igual (=) se usa para asignar un valor a una variable. - -```python -nombre_variable = "valor" -``` - ---- -- Pueden contener el carácter barra baja (_) -- Puede empezar con barra baja pero no se recomienda, a menos que escribas una librería que utilizarán otros -- **NO** se debe usar **palabras reservadas** como nombres de variables. *Python tiene hasta el momento 33 palabras reservadas* - ---- -Si nombramos una variable sin seguir estas reglas Python generará un **error de sintaxis** - -Experimentemos en la terminal interactiva. - -```sh -python -``` -```python ->>> 1variable = 1 ->>> mas@ = 1 ->>> class = 1 -``` - -![Error de sintaxis](./img/02.png) - ---- -Es recomendable utilizar nombres de variables que contengan un contexto claro y describan lo que representan - -```python -x1q3z9ahd = 35.0 -x1q3z9afd = 12.50 -x1q3p9afd = x1q3z9ahd * x1q3z9afd -print(x1q3p9afd) -``` - ---- -```python -horas = 35.0 -tarifa = 12.50 -salario = horas * tarifa -print(salario) -``` - -- Ambos fragmentos hacen exactamente lo mismo desde el punto de vista del intérprete. Pero el programador los puede asimilar de manera diferente - -- Los humanos entienden mejor el segundo fragmento, porque el nombre de las variables describen lo que representan y otorgan un contexto. - ---- -### Datos Numéricos - -Hay tres tipos numéricos - -- Integers (int) -- Floating (float) -- Números complejos (complex) ---- -## Números Enteros -### Integers -**int** - ---- -### ¿Qué son los números enteros? - ---- - -- Son números sin parte decimal. -- Pueden ser positivos, negativos o cero. - -- Tienen precisión ilimitada, pueden representar números muy grandes o muy pequeños sin perder exactitud. - -`$ \Z = \{...,-3,-2,-1,0,1,2,3,...\}$` - ---- -- Los números enteros en Python pueden declararse en distintas bases: decimal, binaria, octal y hexadecimal. - -- La base solo afecta su forma de escritura, no el valor que representan. - ---- -#### ¿Cómo declarar un número entero? - -Se puede declarar directamente en el código - -```python -# Valor 10 Entero -print (10) -print ( type (10) ) -``` - -![Entero](./img/03.png) - ---- -#### ¿Cómo declarar un número entero? - -Se puede declarar en una variables - -```python -# Variable 100 Entero -variable = 100 -print (variable) -print ( type (variable) ) -``` - -![Entero](./img/04.png) - ---- -#### ¿Cómo declarar un número entero? -Se puede declarar usando la función **int** - -```python -# Variable 20 Entero -variable_2 = int (20) -print (variable_2) -print ( type (variable_2) ) -``` - -![Entero](./img/05.png) - ---- -Declarando números enteros en otras bases numéricas - -| **Base** | **Prefijo** | **Símbolos válidos** | **Ejemplo** | -| ----------- | ----------- | -------------------- | ----------- | -| Decimal | *(ninguno)* | 0–9 | `10` | -| Binario | `0b` | 0, 1 | `0b1010` | -| Octal | `0o` | 0–7 | `0o12` | -| Hexadecimal | `0x` | 0–9, a–f | `0xa` | - ---- -```python -# Valor 10 en base decimal -print ("Base decimal") -print (10) -# Valor 10 en binario -print ("Base binaria") -print (0b1010) -# Valor 10 en octal -print ("Base octal") -print (0o12) -# Valor 10 en hexadecimal -print ("Base hexadecimal") -print (0xa) -``` - -![Entero en otras Bases](./img/06.png) - ---- -#### ¿Qué tan grande puede ser el valor de un entero en Python? - -- Python no tienen un límite máximo predefinido para los enteros. -- Podemos declarar enteros tan grandes como la memoria del sistema lo permita. ---- - -```python -# Entero con 60 dígitos -variable_3 = 123456789012345678901234567890123456789012345678901234567890 -print (variable_3) -print (type (variable_3)) -``` - -![Entero grande](./img/07.png) - ---- -## Números con punto flotante -### Floating -**float** - ---- -### ¿Qué son los números con punto flotante? - ---- -- Son números que tienen parte decimal -- Pueden ser positivos, negativos o cero. -- Tienen *precisión limitada*, no pueden representar números con una cantidad *infinita* de decimales. - -![Flotante](./img/08.png) - -`$ \R = \{...,-2.5,-1.5,-0.5,0.5,1.5,2.5,...\}$` - ---- -- En python los números con coma o punto flotante son llamados "float" - -- Internamente este tipo utiliza el formato de **doble precisión (double)** del lenguaje C. - -- Permite almacenar valores decimales con mayor exactitud que un float tradicional en C. - ---- -#### ¿Cómo declarar un número flotante? - -Se puede declarar directamente en el código - -```python -# Valor 0.5 Flotante -print (0.5) -print ( type (0.5) ) -``` - -![Flotante](./img/09.png) - ---- -#### ¿Cómo declarar un número flotante? - -Se puede declarar en una variables - -```python -# Variable 0.100546 Flotante -variable_4 = 0.100546 -print (variable_4) -print ( type (variable_4) ) -``` - -![Flotante con variables](./img/10.png) - ---- -#### ¿Cómo declarar un número flotante? - -Se puede declarar usando la función float - -```python -# Variable 1 Flotante -variable_7 = float (1) -print(variable_7) -print ( type (variable_7) ) -``` - -![Flotante con float](./img/11.png) - ---- - -#### ¿Cómo declarar un número flotante? -Se puede declarar utilizando notación científica con la letra "e" y el exponente - -```python -# Valor 2.0e-3 Flotante -variable_6 = 2.0e-3 -print(variable_6) -print ( type (variable_6) ) -``` - -![Flotante con notación científica](./img/13.png) - ---- - -#### ¿Cual es el limite de precisión de un flotante? - -Precisión máxima con 17 decimales - -```python -# Precisión de 17 decimales -variable_5 = 0.9999999999999999 -print(variable_5) -print ( type (variable_5) ) -``` - -![Flotante con 17 decimales](./img/12.png) - - ---- -## Operadores aritméticos ---- -#### ¿Que son los operadores aritméticos? - -- Son símbolos especiales que representan operaciones matemáticas como la suma, la multiplicación y otros cálculos. -- Una operación matemática tiene un operador y uno o más operandos. -- Los operandos son los valores que se utilizan en la operación. - ---- -#### Operadores aritméticos en Python - -- `$+$` : Suma -- `$-$` : Resta -- `$*$` : Multiplicación -- `$/$` : División -- `$**$` : Potencia -- `$//$` : División entera -- `$\%$` : Módulo o residuo - ---- -```python[1-3|4-6|7-9|10-12|13-15|16-18|19-21|22-24] -# Operadores aritméticos -a = 10 -b = 3 -# Suma -print ("Suma") -print (a + b) -# Resta -print ("Resta") -print (a - b) -# Multiplicación -print ("Multiplicación") -print (a * b) -# División -print ("División") -print (a / b) -# Potencia -print ("Potencia") -print (a ** b) -# Módulo o residuo -print ("Módulo o residuo") -print (a % b) -# División entera -print ("División entera") -print (a // b) -``` - -![Operadores aritméticos](./img/14.png) - ---- -- Podemos combinar los operadores para crear operaciones más complejas - -- Cuando existe más de un operador se sigue un orden de precedencia en la evaluación de la operación - -- Python sigue las reglas matemáticas tradicionales - ---- -El acrónimo **PEMDSR** nos ayuda a recordar: -- *Paréntesis* tiene la mayor prioridad, Lo que esté dentro se evalúa primero. Por lo tanto `2*(3-1)` es `4` -- *Exponenciación* o potencia sigue en la lista de prioridad. Por lo tanto `2**1+1` es `3` - ---- -- *Multiplicación* y *División* tienen la misma prioridad y se evalúan de izquierda a derecha. Por lo tanto `2*3*1/2` es `3` -- Finalmente, *Suma* y *Resta* que también comparten prioridad y se evalúan de izquierda a derecha. Por lo tanto `5-3-1` es `1` - ---- -#### Ejercicio 01 - -Un contador tiene 300 minutos y se le suman 3600 segundos, ¿Cuántas horas en total son? - -*Recuerda que una hora tiene 60 minutos y un minuto tiene 60 segundos* - - - ---- -```python -# Operaciones más complejas -minutos = 300 -tiempo_extra_segundos = 3600 -horas = (minutos + tiempo_extra_segundos / 60) / 60 -print (horas) -``` -```markdown -Horas: 6.0 -``` - ---- -## Operadores de comparación - ---- -#### ¿Qué son los operadores de comparación? - -- Son símbolos especiales que permiten comparar dos valores. - -- Se utilizan para evaluar relaciones como igualdad, mayor que, menor que, entre otras. - -- Los valores comparados no necesitan ser del mismo tipo para ser comparados - -- El resultado de una comparación siempre es un valor booleano: `True` o `False`. ---- -#### Operadores de comparación en Python - - -- <: Estrictamente menor que -- \>: Estrictamente mayor que -- ==: Estrictamente igual que -- <=: Menor o igual que -- \>=: Mayor o igual que -- != : Estrictamente diferente que - ---- -```python -print ("Operadores de comparación") -comparar = 10 -print (comparar < 10) -print (comparar > 10) -print (comparar == 10) -print (comparar <= 10) -print (comparar >= 10) -print (comparar != 10) -``` -![Operadores de comparación](./img/15.png) - ---- -Los valores numéricos de diferente tipo también pueden ser comparados -```python -print ("Operadores de comparación con int - float") -entero = 10 -flotante = 10.0 -print (entero < flotante) -print (entero > flotante) -print (entero == flotante) -print (entero <= flotante) -print (entero >= flotante) -print (entero != flotante) -``` - -![Operadores de comparación int - float](./img/16.png) - ---- -##### Commit de la sesión - -Realizamos un commit de nuestros cambios realizados al repositorio en GitHub - -```sh -git add . -git commit -m "Clase sesión 05" -git push -``` - ---- -## Resumen - -- Los valores son uno de los elementos más básicos que utiliza un programa. -- Una variable es simplemente un nombre que se asigna a un valor. -- Los números enteros son valores sin parte decimal. - ---- -- Los números con punto flotante son números reales tanto positivos como negativos -- Los operadores aritméticos son símbolos especiales que indican cálculos matemáticos. -- Los operadores aritmenticos que podemos usar en Python son: suma `+`, resta `-`, multiplicación `*`, división `/`, potencia `**`, división entera `//` y módulo `%`. - ---- -- El acrónimo *PEMDSR* nos ayuda a recordar el orden de evaluación de los operadores - -**P**aréntesis → **E**xponentes → **M**ultiplicación y **D**ivisión → **S**uma y **R**esta. -- Los operadores de comparación son símbolos especiales que representan comparación entre dos valores - ---- -- Es posible comparar dos valores numéricos de diferente tipo -- Podemos combinar operadores para construir expresiones mas complejas - ---- -##### Retos - -Crear una carpeta con el nombre "retos_sesion_05" dentro del proyecto del "psg-example", por cada ejercicio debes crear un archivo - -```bash -# Ejemplo carpeta -psg-example/ - retos_sesion_05/ - ejercicio_01.py - ejercicio_02.py - ejercicio_03.py - ejercicio_04.py - sesion05.ipynb -``` - -Sube la carpeta a tu repositorio en GitHub cuando termines los retos - ---- - -Realiza los siguientes ejercicios para practicar el uso de números enteros y con punto flotante - -1. Escribe un programa en Python que calcule el total a pagar si se compran 12 productos iguales donde cada uno cuesta 3.75 USD. - ---- - -2. Escribe un programa en Python que convierta las siguientes temperaturas de grados Fahrenheit a grados Celsius: - -- 25 ºF -- 300 ºF -- 76 ºF - ---- - -3. Escribe un programa en Python que convierta 1000000 de segundos en semanas, días, horas, minutos y segundos - -Ejemplo: - -```bash -788521 segundos = 9 días 3 horas 2 minutos 1 segundo -``` - ---- -4. Calcular el volumen de un cubo donde uno de sus lados mide 15 metros, utilizando la fórmula general del volumen de un cubo - ---- -5. Convertir y ejecutar el archivo de la "sesion05.py" a un archivo en jupyter notebook "sesion05.ipynb" - ---- - - -
-
-
-
-
- -[![GitHub](../../content/github_logo.png) ](https://github.com/python-la-paz/python-study-group-fundamentals/tree/main/content/sesion05) - -Repositorio de la Sesión - ---- - -## Bibliografía y Referencias -[Stdtypes](https://docs.python.org/es/3/library/stdtypes.html) -[Pythonlearn](https://do1.dr-chuck.com/pythonlearn/ES_es/pythonlearn.pdf) -[Integer Literals](https://docs.python.org/es/3/reference/lexical_analysis.html#integer-literals) -[Built-in Functions Int](https://www.codecademy.com/resources/docs/python/built-in-functions/int) -[Float Python](https://ellibrodepython.com/float-python) -[Float Literals](https://docs.python.org/es/3/reference/lexical_analysis.html#floating-point-literals) -[Stdtypes Comparisons](https://docs.python.org/es/3.10/library/stdtypes.html#comparisons) -[Value Comparisons](https://docs.python.org/es/3.10/reference/expressions.html#value-comparisons) diff --git a/content/sesion05/img/01.png b/content/sesion05/img/01.png deleted file mode 100644 index 3b1804f..0000000 Binary files a/content/sesion05/img/01.png and /dev/null differ diff --git a/content/sesion05/img/02.png b/content/sesion05/img/02.png deleted file mode 100644 index 81091ac..0000000 Binary files a/content/sesion05/img/02.png and /dev/null differ diff --git a/content/sesion05/img/03.png b/content/sesion05/img/03.png deleted file mode 100644 index 5a0b2ec..0000000 Binary files a/content/sesion05/img/03.png and /dev/null differ diff --git a/content/sesion05/img/04.png b/content/sesion05/img/04.png deleted file mode 100644 index 0561c9a..0000000 Binary files a/content/sesion05/img/04.png and /dev/null differ diff --git a/content/sesion05/img/05.png b/content/sesion05/img/05.png deleted file mode 100644 index d195296..0000000 Binary files a/content/sesion05/img/05.png and /dev/null differ diff --git a/content/sesion05/img/06.png b/content/sesion05/img/06.png deleted file mode 100644 index c787939..0000000 Binary files a/content/sesion05/img/06.png and /dev/null differ diff --git a/content/sesion05/img/07.png b/content/sesion05/img/07.png deleted file mode 100644 index 3ee0d0c..0000000 Binary files a/content/sesion05/img/07.png and /dev/null differ diff --git a/content/sesion05/img/08.png b/content/sesion05/img/08.png deleted file mode 100644 index 1cf17d0..0000000 Binary files a/content/sesion05/img/08.png and /dev/null differ diff --git a/content/sesion05/img/09.png b/content/sesion05/img/09.png deleted file mode 100644 index 84daa3a..0000000 Binary files a/content/sesion05/img/09.png and /dev/null differ diff --git a/content/sesion05/img/10.png b/content/sesion05/img/10.png deleted file mode 100644 index 510bc86..0000000 Binary files a/content/sesion05/img/10.png and /dev/null differ diff --git a/content/sesion05/img/11.png b/content/sesion05/img/11.png deleted file mode 100644 index 3bc670f..0000000 Binary files a/content/sesion05/img/11.png and /dev/null differ diff --git a/content/sesion05/img/12.png b/content/sesion05/img/12.png deleted file mode 100644 index 77ba321..0000000 Binary files a/content/sesion05/img/12.png and /dev/null differ diff --git a/content/sesion05/img/13.png b/content/sesion05/img/13.png deleted file mode 100644 index c60d8e2..0000000 Binary files a/content/sesion05/img/13.png and /dev/null differ diff --git a/content/sesion05/img/14.png b/content/sesion05/img/14.png deleted file mode 100644 index 2477909..0000000 Binary files a/content/sesion05/img/14.png and /dev/null differ diff --git a/content/sesion05/img/15.png b/content/sesion05/img/15.png deleted file mode 100644 index 4ef00ed..0000000 Binary files a/content/sesion05/img/15.png and /dev/null differ diff --git a/content/sesion05/img/16.png b/content/sesion05/img/16.png deleted file mode 100644 index 1c8e66d..0000000 Binary files a/content/sesion05/img/16.png and /dev/null differ diff --git a/content/sesion05/index.html b/content/sesion05/index.html deleted file mode 100644 index 641984e..0000000 --- a/content/sesion05/index.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - Sesión 05 | Python Study Group | Fundamentals - - - - - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/content/sesion06/Readme.md b/content/sesion06/Readme.md deleted file mode 100644 index 7854bd3..0000000 --- a/content/sesion06/Readme.md +++ /dev/null @@ -1,731 +0,0 @@ - -![Python La paz](../Logo.png) - -
-
-
- -### Sesión 06 -### Tipos de datos -### Datos Booleanos ---- -##### ¿Qué es un Booleano? - ---- -Es un tipo de dato lógico que solo puede tener dos valores posibles - -- **True** -- **False** - -> Representa valores de verdad ---- -En python los booleanos están implementados como una subclase de los números enteros - -- Un booleano **True** puede ser considerado como el número 1 -- Un booleano **False** puede ser considerado como el número 0 - ---- -Vamos a crear un archivo llamado **"sesion06.py"** - ---- -```python [1-3|4-9] -print("Tipos de datos booleanos") -print (True) -print (False) -# Operaciones aritméticas con booleanos -print (True + True) -print (True * True) -print (True * False) -print (False + False) -print (False * False) -``` - -![Tipos de datos booleanos](./img/01.png) - ---- -Al ser una subclase de los enteros se puede realizar operaciones aritméticas entre números y booleanos - -```python [1-3|4-5] -print ("Números y booleanos") -print (10 + True) -print (10 + False) -print (10 * True) -print (10 * False) -``` - -![Números y booleanos](./img/02.png) - ---- -#### ¿Cómo declarar un booleano? - -Se puede declarar en una variable - -```python [1-4|5-7] -print ("Declarar variables booleanas") -var_booleana = True -print (var_booleana) -print (type(var_booleana)) -var_booleana = False -print (var_booleana) -print (type(var_booleana)) -``` - -![Declarar variables booleanas](./img/03.png) - ---- -#### ¿Cómo declarar un booleano? -Se puede declarar usando la función bool() - - -```python [1-4|5-7|8-10] -print ("Declarar mediante función bool()") -var_booleana = bool(1) -print (var_booleana) -print (type(var_booleana)) -var_booleana = bool(0) -print (var_booleana) -print (type(var_booleana)) -var_booleana = bool(15) -print (var_booleana) -print (type(var_booleana)) -``` - -![Declarar mediante función bool()](./img/04.png) - ---- -#### ¿Cómo declarar un booleano? -Se puede declarar como resultado de una operación de comparadores lógicos - ---- -##### Operadores de comparación - -Los operadores de comparación son utilizados para comparar dos valores - -Como vimos en la "Sesión 05: Datos Numéricos" - ---- - -Existen operadores para realizar una comparación entre números - -Se adicionan dos más en total teniendo 8 operadores básicos - ---- -#### Operadores de comparación -| Operador | Significado | -| -------- | ----------------------- | -| `<` | Estrictamente menor que | -| `>` | Estrictamente mayor que | -| `<=` | Menor o igual que | -| `>=` | Mayor o igual que | - ---- -#### Operadores de igualdad e identidad -| Operador | Significado | -| -------- | ------------------------------------------------------- | -| `==` | Igualdad de valores (estrictamente igual que) | -| `!=` | Desigualdad de valores (estrictamente diferente que) | -| `is` | Igualdad de identidad (mismo objeto en memoria) | -| `is not` | Desigualdad de identidad (objetos distintos en memoria) | - ---- -El resultados de la operación de comparación es un objeto de tipo `bool` - -Puede ser `True` or `False` - ---- -```python -print ("Operadores de comparación") -print (10 == 10) -print (10 != 10) -print (10 < 10) -print (10 > 10) -print (10 <= 10) -print (10 >= 10) -print (10 is 10) -print (10 is not 10) -``` - -![Operadores de comparación](./img/05.png) - ---- -Los resultados de los comparadores pueden ser asignados a variables y también puede ser utilizados como parte de expresiones lógicas más complejas - -```python [1-4|5-6] -print ("Asignación de variables") -x = 10 -mayor_que_cero = x > 0 -print (mayor_que_cero) -diferente_de_10 = x != 10 -print (diferente_de_10) -``` - -![Asignación de variables](./img/06.png) - ---- -#### Operadores lógicos - -Son operadores especiales que nos permiten realizar cálculos lógicos para **agrupar**, **excluir** y **negar** **expresiones** - ---- -#### Operadores lógicos -Existen tres operadores lógicos: - -- `not`: Negación lógica -- `and`: Conjunción lógica -- `or`: Disyunción lógica - ---- -#### `not` -- Significa **"NO"**. -- Es un **operador unario**, lo que significa que solo necesita una expresión. -- Su función es invertir el valor lógico de la expresión. -- Si la expresión es **True**, not la convierte en **False**. -- Si la expresión es **False**, not la convierte en **True**. - ---- -#### `and` -- Significa **"Y"**. -- Es un **operador binario**, lo que significa que necesita dos expresiones. -- Su función es verificar si ambas expresiones son verdaderas. -- El resultado es `True` solo si las dos expresiones son `True`. -- Si alguna de las expresiones es `False`, el resultado es `False`. - ---- -#### `or` -- Significa **"O"**. -- Es un **operador binario**, lo que significa que necesita dos expresiones. -- Su función es verificar si al menos una de las expresiones es verdadera. -- El resultado es `True` si al menos una de las expresiones es `True`. -- Si ambas expresiones son `False`, el resultado es `False`. - ---- -```python [1-3|4-5|6-7] -print ("Operadores lógicos") -print (True and True) -print (True and False) -print (False or True) -print (False or False) -print (not True) -print (not False) -``` - -![Operadores lógicos](./img/07.png) - ---- -Los operadores lógicos siguen un orden de prioridad al momento de ser evaluados - -1. Se ejecuta el operador de negación `not` -2. Se evalúan las operaciones de conjunción `and` -3. Finalmente las operaciones de disyunción `or` -4. Se puede utilizar paréntesis para evaluar una operación antes que otras, como en los operadores aritméticos - ---- -```python [1-2|3|4|5|6|7] -print("Operadores lógicos y prioridad") -print(False and False or True) -print(False and (False or True)) -print(not True and False or True) -print(not (True and False or False)) -print(not True and (False or False)) -print(not True and False or False) -``` - -![Operadores lógicos y prioridad](./img/08.png) - ---- -#### Funciones lógicas básicas y Tablas de Verdad - ---- -#### ¿Qué son las tablas de verdad? -- Las tablas de verdad son una herramienta que nos permite representar el comportamiento lógico de las expresiones o circuitos digitales -- Muestra todas las combinaciones posibles de valores de entrada. Como `1` y `0` o `True` y `False` -- Indica el resultado de salida para cada combinación, según la lógica definida con los operadores `and`, `or` y `not` - ---- -##### Construcción de tablas de verdad -- Se construyen a partir de las combinaciones posibles de valores de entrada -- Cada fila de la tabla representa una combinación de valores de entrada -- La última columna representa el resultado de la operación lógica para esa combinación -- El número de filas en la tabla depende del número de variables de entrada ---- -#### Tamaño de la tabla de verdad - -El tamaño de una tabla de verdad se determina usando la fórmula: - -`$$ 2^n $$` - -Donde `n` representa la cantidad de variables lógicas o entradas. ---- -#### Tabla de verdad para 1 variable - -![Tablas de verdad 2](./img/09.png) - ---- -#### Tabla de verdad para 2 variables - -![Tablas de verdad 2](./img/10.png) - ---- -#### Tabla de verdad para 3 variables - -![Tablas de verdad 3](./img/11.png) - ---- -#### Tabla de verdad para 4 variable - -![Tablas de verdad 4](./img/12.png) - ---- -Las tres operaciones básica son: - -- AND: Producto booleano -- OR: Suma booleana -- NOT: Negación booleana - -Se puede representar sus tablas de verdad - ---- -Tabla de verdad de "not" - -| A | not A | -| --- | ----- | -| V | F | -| F | V | - -`$$ \overline{A} $$` -`$$ \neg A $$` - ---- -Tabla de verdad de "and" - -| A | B | A and B | -| --- | --- | ------- | -| V | V | V | -| V | F | F | -| F | V | F | -| F | F | F | - -` $$ A \cdot B $$ ` -` $$ A \land B $$ ` - ---- -Tabla de verdad de "or" -| A | B | A or B | -| --- | --- | ------ | -| V | V | V | -| V | F | V | -| F | V | V | -| F | F | F | - -` $$ A + B $$ ` -` $$ A \lor B $$ ` - -` $$ A + B $$ ` -` $$ A \lor B $$ ` - ---- -Existen otras funciones lógicas que nacen a partir de las tres fundamentales - -- NAND: Negación de la función AND -- NOR: Negación de la función OR - ---- -- XOR: Función O exclusiva, True cuando los dos términos son diferentes y False cuando son Iguales "O el uno O el otro" -- XNOR: Negación de la función XOR - ---- -Tablas de verdad de NAND - -| A | B | A nand B | -| --- | --- | -------- | -| V | V | F | -| V | F | V | -| F | V | V | -| F | F | V | - -` $$ \overline{A \cdot B} $$ ` -` $$ \neg (A \land B) $$ ` - ---- -Tablas de verdad de NOR - -| A | B | A nor B | -| --- | --- | ------- | -| V | V | F | -| V | F | F | -| F | V | F | -| F | F | V | - -` $$ \overline{A + B} $$ ` -` $$ \neg (A \lor B) $$ ` - ---- -Tablas de verdad de XOR - -| A | B | A xor B | -| --- | --- | ------- | -| V | V | F | -| V | F | V | -| F | V | V | -| F | F | F | - -` $$ A \oplus B = A\cdot \overline{B} + \overline{A} \cdot B $$ ` -` $$ (A \lor B) \land \neg (A \land B) $$ ` - ---- -Tablas de verdad de XNOR - -| A | B | A xnor B | -| --- | --- | -------- | -| V | V | V | -| V | F | F | -| F | V | F | -| F | F | V | - -` $$ \overline{A \oplus B} = A \cdot B + \overline{A + B} $$ ` -` $$ \neg((A \lor B) \land \neg (A \land B)) $$ ` - ---- -En Python vimos que los operadores AND, OR, NOT están por defecto como palabras reservadas - -El caso de NAND, NOR, XOR, XNOR no existen - -Pueden ser construidas fácilmente utilizando los tres operadores fundamentales - ---- -AND - -```python -print ("Operador AND") -print (True and True) -print (True and False) -print (False and True) -print (False and False) -``` - -![Operador AND](./img/13.png) - ---- -OR - -```python -print ("Operador OR") -print (True or True) -print (True or False) -print (False or True) -print (False or False) -``` - -![Operador OR](./img/14.png) - ---- -NOT - -```python -print ("Operador NOT") -print (not True) -print (not False) -``` - -![Operador NOT](./img/15.png) - ---- -NAND - -```python -print ("Operador NAND") -print (not (True and True)) -print (not (True and False)) -print (not (False and True)) -print (not (False and False)) -``` - -![Operador NAND](./img/16.png) - ---- -NOR - -```python -print ("Operador NOR") -print (not (True or True)) -print (not (True or False)) -print (not (False or True)) -print (not (False or False)) -``` - -![Operador NOR](./img/17.png) - ---- -XOR - -```python [1-4|5-7] -print ("Operador XOR") -a = True -b = False -print ((a or b) and not (a and b)) -a = True -b = True -print ((a or b) and not (a and b)) -``` - -![Operador XOR](./img/18.png) - ---- -Si un sensor detecta movimiento y tiene batería entonces enciende la luz - -```python [1-4|5-7|8-10|11-13] -print ("Ejemplo de uso Sensor y Batería") -sensor = True -bateria = True -print (sensor, "and", bateria, "=", sensor and bateria) -sensor = True -bateria = False -print (sensor, "and", bateria, "=", sensor and bateria) -sensor = False -bateria = True -print (sensor, "and", bateria, "=", sensor and bateria) -sensor = False -bateria = False -print (sensor, "and", bateria, "=", sensor and bateria) -``` - -![Ejemplo de uso Sensor y Batería](./img/19.png) - ---- -La importancia de estos operadores en el mundo real - -Diseño de circuitos lógicos: AND, OR, NOT, NAND, NOR, XOR y XNOR, para construir circuitos digitales utilizados en todos los aparatos electrónicos - ---- -Criptografía: XOR y XNOR para cifrado y descifrado realizando mezcla y enmascaramiento de datos - ---- -Sistemas de control y automatización: NAND y NOR para diseño de relés en sistemas de automatización industrial - ---- -Diseño de algoritmos: XOR y XNOR para realizar operaciones a nivel de bits o bitwise - -(operaciones a nivel binario) - ---- -Redes de computadoras: NAND y NOR se utilizan para la lógica de acceso permitiendo o denegando el acceso de dispositivos a una red - ---- -##### Combinación de operadores de comparación, lógicos y aritméticos - -- Es posible combinar operadores de comparación, lógicos y aritméticos para construir expresiones más complejas que permitan evaluar condiciones precisas dentro de un programa. - ---- -Ejemplo 1 - -Determinar si el número 20 está en el rango 0 a 100 - - - ---- -```python -print ("Ejemplo 1 - Comparación y Lógicos") -numero = 20 -print (numero >= 0 and numero <= 100) -``` -```markdown -Ejemplo 1 - Comparación y Lógicos -True -``` - ---- -Ejemplo 2 - -Un estudiante obtuvo las siguientes notas en sus exámenes: 15, 20, 16 determinar si el estudiante aprobó con una nota superior a 50 - - - ---- -```python -print ("Ejemplo 2 - Aritméticos y comparación") -nota1 = 15 -nota2 = 20 -nota3 = 16 -print ((nota1 + nota2 + nota3) > 50) -``` -```markdown -Ejemplo 2 - Aritméticos y comparación -True -``` - ---- -Ejemplo 3 - -Determinar si el número 15 es divisible por 3 y 5, pero no por 2 - - - ---- -```python -print ("Ejemplo 3 - Aritméticos, comparación y lógicos") -numero = 15 -print ((numero % 3 ==0) and (numero % 5 ==0) and (numero % 2 !=0)) -``` -```markdown -Ejemplo 3 - Aritmético, comparación y lógicos -True -``` - ---- -##### Cortocircuitos - ---- -Es un comportamiento de los operadores lógicos "and" y "or" al momento de evaluar expresiones booleanas - -Se basa en la evaluación perezosa - ---- -Cortocircuito con "and": Cuando se evalúa una expresión en la cual el primer término de la expresión es False - -no importa el resultado del segundo término la expresión siempre será False - -Por lo cual no evalúa al segundo término por ya sabe que será False el resultado - ---- -```python [1-3|4|5] -print ("Cortocircuito con operador and") -x = 1 -y = 0 -print (x > 2 and (x/y) > 2) -print (x > 0 and (x/y) > 0) -``` - -![Cortocircuito con operador and](./img/20.png) - ---- - -La primera expresión tiene un cortocircuito porque x no es mayor que 2 por lo que el resultado directo es False y no necesita evaluar la segunda parte - -La segunda expresión falla ya que al ser True la primera parte del and necesita de la evaluación de la segunda expresión (x/y) > 0 pero no existe la división sobre 0 por lo que la ejecución termina con un error - -> Comentemos la segunda expresión para evitar el error - ---- -Cortocircuito con "or": Cuando se evalúa una expresión en la cual el primer término de la expresión es True - -El resultado siempre será True por lo que Python no evalúa el segundo término - -Ya que sabe cuál será el resultado - ---- -```python [1-3|4|5] -print ("Cortocircuito con operador or") -x = 1 -y = 0 -print (x > 0 or (x/y) > 0) -print (x > 2 or (x/y) > 2) -``` - -![Cortocircuito con operador or](./img/21.png) - ---- -La primera expresión tiene un cortocircuito porque x es mayor que 0 por lo que el resultado directo es True y no necesita evaluar la segunda parte - -La segunda expresión falla ya al ser la primera parte False depende del segundo término para el resultado por lo que se evalúa la segunda expresión (x/y) > 2 pero no existe la división sobre 0 por lo que la ejecución termina con un error - -> Comentemos la segunda expresión para evitar el error - ---- -##### Commit - -Realizamos un commit de nuestros cambios realizados al repositorio en GitHub - -```sh -git add . -git commit -m "Clase sesión 06" -git push -``` - ---- -##### Resumen - -- Los booleanos son un tipo de dato que tiene dos constantes True y False -- Los booleanos son subclases de los enteros -- Se pueden realizar operaciones aritméticas entre números y booleanos - ---- -- Se pueden declarar variables booleanas directamente o mediante la función bool() -- Los operadores de comparación son utilizados para comparar dos valores -- Los operadores lógicos son utilizados para realizar cálculos lógicos - ---- -- Las tablas de verdad son una herramienta que nos permite representar la lógica de los circuitos digitales -- El tamaño de una tabla de verdad se determina por `2^n` -- Los operadores lógicos fundamentales son AND, OR, NOT - ---- -- Los operadores lógicos NAND, NOR, XOR, XNOR pueden ser construidos utilizando los operadores fundamentales -- Los operadores lógicos pueden ser combinados con operadores de comparación y aritméticos -- Los cortocircuitos son un comportamiento de los operadores lógicos "and" y "or" al momento de evaluar expresiones booleanas - ---- -- Los cortocircuitos se basan en la evaluación perezosa -- Los cortocircuitos con "and" y "or" permiten optimizar la evaluación de expresiones booleanas - ---- -##### Reto -Crear una carpeta con el nombre "reto_sesion_06" en la cual por cada ejercicio debe crear un script de python - -```bash -# Ejemplo carpeta -psg-example/ - retos_sesion_06/ - ejercicio_01.py - ejercicio_02.py - ... - ejercicio_07.py - sesion06.ipynb -``` - -Subir la carpeta a su repositorio en GitHub cuando termine los retos - ---- -1. ¿Si se declara una variable boolean del valor 0.0000000001 es True o False? -2. Construir el operador XNOR en Python - ---- -3. Imprime una tabla de verdad para la siguiente sentencia: "Un sistema de seguridad controla el acceso a una habitación, la puerta sólo se abre si se introduce una tarjeta válida o la huella dactilar, pero no ambas al mismo tiempo. Si se introduce la tarjeta y la huella dactilar, la puerta no se abre. ¿Qué operador lógico se puede utilizar?" - ---- -4. La resta de los números 17 y 9 es un número par? -5. Comparar los números `44 y 98` , `111 y 333` , comprobar si tienen la misma paridad ambos pares o ambos impares - ---- -6. ¿El cubo de 300 se encuentra en el siguiente rango? [N > 0 & N < 27_000_000] -7. ¿El cuadrado y la suma de 2 y 2 son iguales? - ---- -8. Convertir y ejecutar el archivo de la "sesion06.py" a un archivo en jupyter notebook - ---- - - -
-
-
-
-
- -[![GitHub](../../content/github_logo.png) ](https://github.com/python-la-paz/python-study-group-fundamentals/tree/main/content/sesion06) - -Repositorio de la Sesión - ---- - -## Bibliografía y Referencias -- [Pythonlearn](https://do1.dr-chuck.com/pythonlearn/ES_es/pythonlearn.pdf) -- [Stdtypes](https://docs.python.org/3/library/stdtypes.html#boolean-type-bool) -- [Booleano Python](https://ellibrodepython.com/booleano-python) -- [Tablas de verdad](https://ney.one/tablas-de-verdad-segun-la-cantidad-de-variables-circuitos-logicos/) -- [Principios de la Tabla de Verdad](https://electropreguntas.com/aprende-los-principios-de-la-tabla-de-verdad-binaria-de-forma-facil-y-practica/) -- [Funciones booleanas](https://sedici.unlp.edu.ar/bitstream/handle/10915/3835/B_-_Funciones_booleanas.pdf) -- [Principios de la tabla de verdad](https://docs.hektorprofe.net/python/operadores-y-expresiones/operadores-logicos/) -- [Operadores lógicos](https://docs.python.org/3.10/library/stdtypes.html#truth-value-testing) -- [Diseño digital](http://www.ollintec.com/SistemasDigitales/libros/Dise%C3%B1o%20digital,%203ra%20Edici%C3%B3n%20-%20M.%20Morris%20Mano-FREELIBROS.ORG.pdf) -- [Digital Logic Design](https://www.portcity.edu.bd/files/636444791235373856_Digitallogicdesign.pdf) -- [Compuertas lógicas](https://www.logicbus.com.mx/blog/compuertas-logicas/) diff --git a/content/sesion06/img/01.png b/content/sesion06/img/01.png deleted file mode 100644 index 1447471..0000000 Binary files a/content/sesion06/img/01.png and /dev/null differ diff --git a/content/sesion06/img/02.png b/content/sesion06/img/02.png deleted file mode 100644 index 6ada765..0000000 Binary files a/content/sesion06/img/02.png and /dev/null differ diff --git a/content/sesion06/img/03.png b/content/sesion06/img/03.png deleted file mode 100644 index e0eb735..0000000 Binary files a/content/sesion06/img/03.png and /dev/null differ diff --git a/content/sesion06/img/04.png b/content/sesion06/img/04.png deleted file mode 100644 index 22c5f86..0000000 Binary files a/content/sesion06/img/04.png and /dev/null differ diff --git a/content/sesion06/img/05.png b/content/sesion06/img/05.png deleted file mode 100644 index 94c68eb..0000000 Binary files a/content/sesion06/img/05.png and /dev/null differ diff --git a/content/sesion06/img/06.png b/content/sesion06/img/06.png deleted file mode 100644 index cb5298f..0000000 Binary files a/content/sesion06/img/06.png and /dev/null differ diff --git a/content/sesion06/img/07.png b/content/sesion06/img/07.png deleted file mode 100644 index 4d9bb16..0000000 Binary files a/content/sesion06/img/07.png and /dev/null differ diff --git a/content/sesion06/img/08.png b/content/sesion06/img/08.png deleted file mode 100644 index be06729..0000000 Binary files a/content/sesion06/img/08.png and /dev/null differ diff --git a/content/sesion06/img/09.png b/content/sesion06/img/09.png deleted file mode 100644 index 8641e08..0000000 Binary files a/content/sesion06/img/09.png and /dev/null differ diff --git a/content/sesion06/img/10.png b/content/sesion06/img/10.png deleted file mode 100644 index 613294c..0000000 Binary files a/content/sesion06/img/10.png and /dev/null differ diff --git a/content/sesion06/img/11.png b/content/sesion06/img/11.png deleted file mode 100644 index 9c9a6e2..0000000 Binary files a/content/sesion06/img/11.png and /dev/null differ diff --git a/content/sesion06/img/12.png b/content/sesion06/img/12.png deleted file mode 100644 index 8348341..0000000 Binary files a/content/sesion06/img/12.png and /dev/null differ diff --git a/content/sesion06/img/13.png b/content/sesion06/img/13.png deleted file mode 100644 index a3a8307..0000000 Binary files a/content/sesion06/img/13.png and /dev/null differ diff --git a/content/sesion06/img/14.png b/content/sesion06/img/14.png deleted file mode 100644 index 2ea2bfd..0000000 Binary files a/content/sesion06/img/14.png and /dev/null differ diff --git a/content/sesion06/img/15.png b/content/sesion06/img/15.png deleted file mode 100644 index 5a0f312..0000000 Binary files a/content/sesion06/img/15.png and /dev/null differ diff --git a/content/sesion06/img/16.png b/content/sesion06/img/16.png deleted file mode 100644 index 04b55e3..0000000 Binary files a/content/sesion06/img/16.png and /dev/null differ diff --git a/content/sesion06/img/17.png b/content/sesion06/img/17.png deleted file mode 100644 index 756165c..0000000 Binary files a/content/sesion06/img/17.png and /dev/null differ diff --git a/content/sesion06/img/18.png b/content/sesion06/img/18.png deleted file mode 100644 index 5e53101..0000000 Binary files a/content/sesion06/img/18.png and /dev/null differ diff --git a/content/sesion06/img/19.png b/content/sesion06/img/19.png deleted file mode 100644 index 4889af6..0000000 Binary files a/content/sesion06/img/19.png and /dev/null differ diff --git a/content/sesion06/img/20.png b/content/sesion06/img/20.png deleted file mode 100644 index dcb77ec..0000000 Binary files a/content/sesion06/img/20.png and /dev/null differ diff --git a/content/sesion06/img/21.png b/content/sesion06/img/21.png deleted file mode 100644 index d7866ac..0000000 Binary files a/content/sesion06/img/21.png and /dev/null differ diff --git a/content/sesion06/index.html b/content/sesion06/index.html deleted file mode 100644 index 9a25852..0000000 --- a/content/sesion06/index.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - Sesión 06 | Python Study Group | Fundamentals - - - - - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/content/sesion07/Readme.md b/content/sesion07/Readme.md deleted file mode 100644 index 2b6424a..0000000 --- a/content/sesion07/Readme.md +++ /dev/null @@ -1,792 +0,0 @@ - -![Python La paz](../Logo.png) - -
-
-
- -### Sesión 07 -### Tipos de datos -### Cadenas ---- -##### ¿Qué es una Cadena? - ---- -Una cadena es una secuencia de caracteres - -Todos los caracteres que son imprimibles y no imprimibles - -- Alfabeto -- Números -- Símbolos -- Emojis -- Espacios -- Tabulaciones -- Saltos de línea - ---- -En Python la información textual se representa con objetos de tipo "str" también llamados strings - ---- -Son secuencias inmutables de caracteres Unicode - -En python utilizan la codificación UTF-8 por defecto - -> Unicode Transformation Format - 8-bit - ---- -Los strings en python utilizan la codificación UTF-8 por defecto - -Cada carácter representa una secuencia posible desde 1 a 4 bytes - -Es eficiente para el almacenamiento y transmisión de información, en Inglés y otros idiomas occidentales - -Los strings también son compatibles con ASCII un estándar más básico que UTF-8 - ---- -Existen otros esquemas de codificación como UTF-16 y UTF-32 - -Utilizados en sistemas que trabajan en escritura que requiere más de 16 bits de almacenamiento - -Como Chino, Japonés, Coreano - ---- -##### ¿Cómo declaro una cadena? -Las cadenas se definen en el código de diferentes maneras pero siempre entre alguno de los siguientes caracteres - ---- -- Comillas Simples: 'Mi cadena permite comillas "dobles" en una sola línea ' -- Comillas Dobles: "Mi cadena permite comillas 'simples' en una sola línea " - ---- -- Triples comillas simples: ''' Mi cadena permite contenido en varias líneas''' -- Triples comillas dobles: """ Mi cadena permite contenido en varias líneas """ - ---- -```python [1,9|2,10|3-5,11|6-8,12] -simple = 'Mi cadena permite comillas "dobles" en una sola línea' -doble = "Mi cadena permite comillas 'simples' en una sola línea" -triple_simple = '''Mi cadena -permite contenido -en varias líneas y comillas "dobles" ''' -triple_doble = """Mi cadena -permite contenido -en varias líneas y comillas 'simples' """ -print (simple) -print (doble) -print (triple_simple) -print (triple_doble) -``` - -![Declarar cadena](./img/01.png) - ---- -El método "str" recibe un objeto cualquiera y lo retorna como una cadena de caracteres - ---- -```python [1,5,9|2,6,10|3,7,11|4,8,12] -entero = str(1) -flotante = str(1E-3) -hexadecimal = str(0xA) -booleano = str (True) -print (entero) -print (flotante) -print (hexadecimal) -print (booleano) -print (type(entero)) -print (type(flotante)) -print (type(hexadecimal)) -print (type(booleano)) -``` - -![str](./img/02.png) - ---- -##### Escape de caracteres - -Es la práctica de colocar un carácter especial o conjunto de caracteres dentro de una cadena para que se interprete de manera diferente - ---- -Ciertos caracteres tienen significados especiales por lo tanto necesitan ser escapados para ser interpretados - ---- -En python el carácter especial que nos permite escapar caracteres es el barra invertida o backslash - -`\` - ---- -Ejemplo, imprimir la cadena: - -El mensaje enviado fue: "Hello, I'm a message" - ---- - -```python -print ("El mensaje enviado fue: "Hello, I'm a message"") -print ('El mensaje enviado fue: "Hello, I'm a message"') -``` - -Realizar un print con comillas simples o dobles genera un error - -La cadena contiene ambos caracteres especiales como valores y el intérprete no puede diferenciarlos - ---- -Vamos a escapar los caracteres especiales internos las comillas dobles y la comilla simple - -```python -print ("El mensaje enviado fue: \"Hello, I\'m a message\"") -print ('El mensaje enviado fue: \"Hello, I\'m a message\"') -``` - -Ya no se generan errores de sintaxis al escribir la cadena - -```text -El mensaje enviado fue: "Hello, I'm a message" -El mensaje enviado fue: "Hello, I'm a message" -``` - ---- -Existen combinaciones de escapado que generan caracteres especiales los más comunes son: - -- \n : Agrega el carácter ASCII (LF) que representa un salto de línea -- \t : Agrega el carácter ASCII (TAB) que representa una tabulación horizontal - ---- -- \v : Agrega el carácter ASCII (VT) que representa una tabulación vertical -- \b : Agrega el carácter ASCII (BS) que representa un retroceso -- \\ : Agrega el carácter de backslash o barra invertida -- \ <newline> : Agrega un salto de línea en el código pero no en la impresión - ---- -```python -mensaje = "Hola,\n\teste es un mensaje \vcon algunos caracteres \ -especiales como \\ y tabulador." -print(mensaje) -``` -```text -#Linux -Hola, - este es un mensaje - con algunos caracteres especiales como \ y tabulador. -# Windows Powershell VSCode -Hola, - este es un mensaje ♂con algunos caracteres especiales como \ y tabulador. -``` - ---- -##### Método Input - -El método "input" nos permite ingresar contenido al programa y es procesado como una cadena - ---- -El texto introducido es de una sola línea y se inserta al programa cuando se realiza Enter al terminar de escribir - -```python -entrada = input("Ingrese un valor: ") -print (entrada) -print (type(entrada)) -``` - -![input](./img/03.png) - ---- -Después de introducir el valor desde teclado y presionar Enter - -![input](./img/04.png) - ---- -Cuando introducimos por teclado y es procesado por una cadena puede ser convertido a diferentes tipos como enteros, flotantes, booleanos - -```python -entero = int(input("Ingrese un valor entero: ")) -print (entero, type(entero)) - -flotante = float(input("Ingrese un valor flotante: ")) -print (flotante, type(flotante)) - -booleano = bool(input("Ingrese un valor booleano: ")) -print (booleano, type(booleano)) -``` - -![input](./img/05.png) - ---- -##### Manejo de Indices - -Las cadenas son secuencias de caracteres por lo cual pueden ser representados de la siguiente manera - -![Indices](./img/06.png) - -Se observa que la palabra empieza en el número 0 hasta el número 5 en total teniendo 6 caracteres - ---- -Accedemos a los diferentes caracteres de la cadena utilizando sus índices - -```python -print ("Indexado positivo") -fruta = "banana" -print (fruta) -print (fruta[0]) -print (fruta[5]) -``` - -![Indices](./img/07.png) - ---- -Los índices también puede ser negativos para la misma cadena - -![Indices Negativos](./img/08.png) - -En los índices negativos el último carácter es -1 y el primer carácter es -6 - ---- -Accedemos a los diferentes caracteres de la cadena utilizando sus índices negativos -```python -print ("Indexado negativo") -fruta = "banana" -print (fruta) -print (fruta[-1]) -print (fruta[-3]) -``` - -![Indices Negativos](./img/09.png) - ---- -##### Segmentación o Slicing - -Slicing es la técnica que permite extraer una parte de una secuencia de caracteres utilizando los indices de esta cadena - -El resultado es una sub cadena - ---- -La sintaxis básica del slicing está dada por - -![Slicing](./img/10.png) - - -- Secuencia: La cadena a procesar -- Inicio: El índice o index donde comienza la sub cadena incluyendo el mismo valor -- Fin: El index donde termina la sub cadena siendo excluyente a este valor -- Paso: Es el tamaño de paso entre los índices por defecto es 1 - ---- -```python [1-3|4-6|7-9] -print ("Slicing") -ciudad = "LaPaz-Bolivia" -print (ciudad) -print ("Slicing con índices positivos") -print (ciudad[0:6]) -print (ciudad[0:6:2]) -print ("Slicing con índices negativos") -print (ciudad[-10:-2]) -print (ciudad[-10:-2:2]) -``` - -![Slicing](./img/11.png) - ---- -Se puede dejar en blanco un espacio del slicing para hacer referencia a todo el contenido inicial o contenido final - -```python [1|2|3|4|5|6] -print ("Slicing sin índice inicial y final") -print (ciudad[:6]) -print (ciudad[6:]) -print ("Slicing sin índice inicial ni final") -print (ciudad[:]) -print (ciudad[::2]) -``` - -![Slicing](./img/12.png) - ---- -Cuando se trabaja con pasos negativos los slice se realizan de forma - -```python [1|2|3] -print ("Slicing con paso negativo") -print (ciudad[10:4:-1]) -print (ciudad[10::-2]) -``` - -![Slicing](./img/13.png) - ---- -##### Concatenación de una cadena - -Las cadenas se pueden concatenar con el operador + generando una nueva cadena en el resultado - -```python -print ("Concatenación de cadenas") -cadena1 = "Hola" -cadena2 = "Mundo" -concatenada = cadena1 + " " + cadena2 -print (concatenada) -``` - -```text -Concatenación de cadenas -Hola Mundo -``` - ---- -##### Repetición de una cadena -Las cadenas pueden ser repetidas utilizando el operador * y un número entero N que genera una nueva cadena repetida N veces - -```python -print ("Repetición de cadenas") -cadena = "-#-" -repetida = cadena * 10 -print (repetida) -``` -```text -Repetición de cadenas --#--#--#--#--#--#--#--#--#--#- -``` - ---- -##### Longitud de una cadena - -Una de las funciones más importantes es la función len que nos permite obtener la longitud de una cadena específica - -La longitud de una cadena es del tipo entero - ---- -```python [1-5|3] -print ("Longitud de una cadena") -cadena = "Hola Mundo :D" -longitud = len(cadena) -print (cadena) -print (longitud, type(longitud)) -``` - -![Longitud](./img/14.png) - ---- -##### Métodos de Cadenas - -Las cadenas en Python tienen múltiples métodos para realizar tareas y procesarlas - -Permitiéndonos hacer modificaciones a las cadenas - -Se llama estas funciones utilizando la cadena seguido de un punto, el nombre de la función y paréntesis - -*`cadena.funcion()`* - ---- -###### Upper - -upper(): Retorna una copia de la cadena donde todos los caracteres de la cadena son convertidos a su equivalente en mayúsculas - -```python -print ("Función Upper") -cadena = "cadena Inicial #1" -mayuscula = cadena.upper() -print (cadena) -print (mayuscula) -``` - -![Upper](./img/15.png) - ---- -###### Lower - -lower(): Retorna una copia de la cadena donde todos los caracteres de la cadena son convertidos a su equivalente en minúsculas - -```python -print ("Función Lower") -cadena = "Cadena INICIAL #2" -minuscula = cadena.lower() -print (cadena) -print (minuscula) -``` - -![Lower](./img/16.png) - ---- -###### Capitalize -capitalize(): Retorna una copia de la secuencia de caracteres donde el primer carácter de la cadena es convertido en Mayúscula y el resto de la cadena en minúsculas - -```python -print ("Función Capitalize") -cadena = "cadena INICIAL #3" -capital = cadena.capitalize() -print (cadena) -print (capital) -``` - -![Capitalize](./img/17.png) - ---- -###### Title - -title(): Retorna una copia en formato título de la cadena, la primera letra de cada palabra estará en mayúsculas y el resto en minúsculas - -```python -print ("Función Title") -cadena = "CADENA inicial #4" -titulo = cadena.title() -print (cadena) -print (titulo) -``` - -![Title](./img/18.png) - ---- -###### Swapcase - -swapcase(): Retorna una copia de la cadena donde los caracteres son convertidos en su version inversa, caracteres en upper cambian a lower y vice versa - -```python -print ("Función Swapcase") -cadena = "CADena InIcIaL #5" -swap = cadena.swapcase() -print (cadena) -print (swap) -``` - -![Swapcase](./img/19.png) - ---- -Existen funciones que permiten buscar contenido dentro las cadenas - ---- -###### Count - -count(): Cuenta las veces que aparece una cadena dentro de otra cadena recibe como parámetro la cadena a buscar - -```python -print ("Función Count") -cadena = "Cantidad de veces la letra A" -contar = cadena.count("a") -print(cadena) -print(contar, type(contar)) -``` - -![Count](./img/20.png) - ---- -###### Find - -find(): Busca y devuelve el índice en el que se encuentra la cadena dentro de otra, empezando por la izquierda o inicio, si no encuentra devuelve -1 - -```python -print ("Función Find") -cadena = "Encontrar las letras las" -buscar = cadena.find("las") -print(cadena) -print(buscar, type(buscar)) -``` - -![Find](./img/21.png) - ---- -###### Rfind - -rfind(): Busca y devuelve el índice en el que se encuentra la cadena dentro de otra cadena, empezando por la derecha o final, si no encuentra devuelve -1 - -```python -print ("Función Rfind") -cadena = "Encontrar las letras las" -buscar = cadena.rfind("las") -print(cadena) -print(buscar, type(buscar)) -``` - -![Rfind](./img/22.png) - ---- -Find y Rfind devuelven -1 si no encuentran la cadena - -```python -print ("Función Find y Rfind") -cadena = "Encontrar tres O" -buscar = cadena.find("OOO") -print(cadena) -print(buscar, type(buscar)) -buscar = cadena.rfind("OOO") -print(buscar, type(buscar)) -``` - -![Find y Rfind](./img/23.png) - ---- -Existen funciones para saber si una cadena contiene sólo números, sólo caracteres alfabéticos o mixtos - ---- -- isdigit(): Devuelve un booleano si la cadena contiene sólo números -- isalpha(): Devuelve un booleano si la cadena contiene sólo caracteres alfabéticos -- isalnum(): Devuelve un booleano si la cadena contiene solo números y caracteres alfabéticos - ---- -```python [1-3|4-6|7-9] -print ("Función isdigit") -resultado = "100".isdigit() -print (resultado, type(resultado)) -print ("Función isalpha") -resultado = "Hola".isalpha() -print (resultado, type(resultado)) -print ("Función isalnum") -resultado = "usuario123".isalnum() -print (resultado, type(resultado)) -``` - -![Isdigit](./img/24.png) - ---- -Existen funciones que permiten procesar las cadena donde el resultado no son solo cadenas, sino también otros tipos de datos - ---- -###### Split - -split(): Retorna una lista de palabras utilizando un separador para delimitar las cadenas separadas - -```python -print ("Función split") -cadena = "pan,carne,huevos" -separado = cadena.split(",") -print (cadena) -print (separado, type(separado)) -``` - - -![Split](./img/25.png) - ---- -###### Join - -join(): Retorna una copia de una cadena en la cual concatena la cadena con el contenido de otra cadena - -```python -print ("Función join") -cadena = "abcdefghij" -unido = "-".join(cadena) -print (cadena) -print (unido) -``` - -![Join](./img/26.png) - ---- -###### Strip - -strip(): Remueve los caracteres la izquierda y a la derecha de la cadena por defecto remueve espacios en blanco, si se envía un valor eliminará esos caracteres - -```python -print ("Función strip") -cadena = " Hola Mundo " -limpio = cadena.strip() -print (cadena) -print (limpio) -cadena = "-abc--def-ghi-cba----" -limpio = cadena.strip("bac-") -print (cadena) -print (limpio) -``` - -![Strip](./img/27.png) - ---- -###### Replace - -replace(): Retorna una copia de la cadena con contenido reemplazado por otra cadena - -```python -print ("Función replace") -cadena = "Me gusta programar en JS, Amo JS" -reemplazado = cadena.replace("JS", "Python") -print (cadena) -print (reemplazado) -``` - -![Replace](./img/28.png) - ---- -###### format - -format(): Realiza una operación de formateo e inserta contenido a la cadena delimitado por llaves {} - -```python -print ("Función format") -cadena = "El valor de PI es: {}" -formateado = cadena.format(3.1416) -print (cadena) -print (formateado) -``` - -![Format](./img/29.png) - ---- -###### Format - -Índices para mostrar contenido - -```python -print ("Función format con índices") -cadena = "{2} es la suma de {0} y {1}" -valor_1 = 5 -valor_2 = 3 -resultado = valor_1+valor_2 -formateado = cadena.format(valor_1, valor_2, resultado) -print (cadena) -print (formateado) -``` - -![Format](./img/30.png) - ---- -###### Format - -Tambien puede utilizar nombres de variables - -```python -print ("Función format con nombres") -cadena = "{ciudad} es la capital de {pais}" -pais = "Francia" -ciudad = "París" -formateado = cadena.format(pais=pais, ciudad=ciudad) -print (cadena) -print (formateado) -``` - -![Format](./img/31.png) - ---- -Se puede formatear cadenas de forma más directa utilizando *f-strings* - -Permite formatear cadenas de forma más directa utilizando el nombre de las variables - ---- -```python -print ("Función format con f-string") -moneda = "Boliviano" -pais = "Bolivia" -formateado = f"La moneda de {pais} es el {moneda}" -print (formateado) -``` - -![Format](./img/32.png) - ---- -##### Commit - -Commit de la sesión a nuestro repositorio y push en GitHub - -```sh -git add . -git commit -m "Clase sesión 07" -git push -``` - ---- -##### Resumen - -- Las cadenas son secuencias de caracteres -- Los caracteres pueden ser imprimibles o no imprimibles -- Las cadenas son inmutables - ---- -- Se codifican en UTF-8 -- También son compatibles con ASCII -- Se pueden declarar con comillas simples, dobles o triples - ---- -- Se pueden escapar caracteres especiales con backslash `\` -- Se pueden concatenar con el operador + -- Se pueden repetir con el operador * - ---- -- Se pueden indexar y segmentar -- Existen indexado negativo y slicing -- Se pueden convertir a otros tipos de datos - ---- -- Se pueden obtener la longitud con la función len -- Existen múltiples métodos para procesar las cadenas -- Se pueden buscar contenido con find y rfind - ---- -- Se pueden contar caracteres con count -- Se pueden verificar si son números, alfabéticos o mixtos -- Se pueden separar con split y unir con join - ---- -- Se pueden limpiar con strip -- Se pueden reemplazar con replace -- Se pueden formatear con format y f-strings - ---- -- Se pueden utilizar índices y nombres de variables -- Se pueden formatear de forma más directa con f-strings -- Se pueden realizar operaciones de formateo con format - ---- -##### Retos -Crear una carpeta con el nombre "retos_sesion_07" en la cual por cada ejercicio debe crear un script de python - -```bash -# Ejemplo carpeta -psg-example/ - retos_sesion_07/ - ejercicio_01.py - ejercicio_02.py - ... - ejercicio_06.py - sesion07.ipynb -``` - -Subir la carpeta a su repositorio en GitHub cuando termine los retos - ---- -1. Escribir una cadena con una frase de una libro o un poema - ---- -2. Escribe un programa que reciba tres enteros por teclado y reste su resultado - ---- -3. De la palabra "casas" mostrar solo los caracteres con índice par - ---- -4. Invierte la siguiente palabra "electroencefalografista" - ---- -5. Escribe un programa que reciba una cadena y retorna verdadero o falso si es palindrome sin importar los espacios, mayúsculas o minúsculas - -``` -Ejemplo: "La Ruta Natural" es True -larutanatural ➡ larutanatural -``` - ---- -6. Agregar 5 Ejemplos con otras funciones no vistas en la sesión - -Utilizar la documentación [Métodos de cadenas](https://docs.python.org/3/library/stdtypes.html#string-methods) - ---- -7. Convertir y ejecutar el archivo de la "sesion07.py" a un archivo en jupyter notebook ---- - - -
-
-
-
-
- -[![GitHub](../../content/github_logo.png) ](https://github.com/python-la-paz/python-study-group-fundamentals/tree/main/content/sesion07) - -Repositorio de la Sesión - ---- - -## Bibliografía y Referencias -- [Pythonlearn](https://do1.dr-chuck.com/pythonlearn/ES_es/pythonlearn.pdf) -- [StdTypes](https://docs.python.org/3/library/stdtypes.html#str) -- [Lexical Analysis Escape Sequences](https://docs.python.org/3/reference/lexical_analysis.html#escape-sequences) -- [Text Sequence Type - str](https://docs.python.org/es/3/library/stdtypes.html#text-sequence-type-str) -- [Input](https://docs.python.org/es/3/library/functions.html#input) -- [Slicing and Indexing](https://www.linode.com/docs/guides/how-to-slice-and-index-strings-in-python/) -- [Métodos de las Cadenas](https://docs.hektorprofe.net/python/metodos-de-las-colecciones/metodos-de-las-cadenas/) -- [String Methods](https://docs.python.org/3/library/stdtypes.html#string-methods) -- [Find](https://docs.python.org/3/library/stdtypes.html#str.find) -- [Split](https://docs.python.org/3/library/stdtypes.html#str.split) -- [Join](https://docs.python.org/3/library/stdtypes.html#str.join) -- [Format](https://docs.python.org/3/library/stdtypes.html#str.format) diff --git a/content/sesion07/img/01.png b/content/sesion07/img/01.png deleted file mode 100644 index 946480c..0000000 Binary files a/content/sesion07/img/01.png and /dev/null differ diff --git a/content/sesion07/img/02.png b/content/sesion07/img/02.png deleted file mode 100644 index 3326ff6..0000000 Binary files a/content/sesion07/img/02.png and /dev/null differ diff --git a/content/sesion07/img/03.png b/content/sesion07/img/03.png deleted file mode 100644 index cbe3f4f..0000000 Binary files a/content/sesion07/img/03.png and /dev/null differ diff --git a/content/sesion07/img/04.png b/content/sesion07/img/04.png deleted file mode 100644 index 0eb9e38..0000000 Binary files a/content/sesion07/img/04.png and /dev/null differ diff --git a/content/sesion07/img/05.png b/content/sesion07/img/05.png deleted file mode 100644 index 5db26ec..0000000 Binary files a/content/sesion07/img/05.png and /dev/null differ diff --git a/content/sesion07/img/06.png b/content/sesion07/img/06.png deleted file mode 100644 index 143a7da..0000000 Binary files a/content/sesion07/img/06.png and /dev/null differ diff --git a/content/sesion07/img/07.png b/content/sesion07/img/07.png deleted file mode 100644 index b1eb03b..0000000 Binary files a/content/sesion07/img/07.png and /dev/null differ diff --git a/content/sesion07/img/08.png b/content/sesion07/img/08.png deleted file mode 100644 index 87e5edb..0000000 Binary files a/content/sesion07/img/08.png and /dev/null differ diff --git a/content/sesion07/img/09.png b/content/sesion07/img/09.png deleted file mode 100644 index f6a4b40..0000000 Binary files a/content/sesion07/img/09.png and /dev/null differ diff --git a/content/sesion07/img/10.png b/content/sesion07/img/10.png deleted file mode 100644 index 6fb6be9..0000000 Binary files a/content/sesion07/img/10.png and /dev/null differ diff --git a/content/sesion07/img/11.png b/content/sesion07/img/11.png deleted file mode 100644 index 832d7ab..0000000 Binary files a/content/sesion07/img/11.png and /dev/null differ diff --git a/content/sesion07/img/12.png b/content/sesion07/img/12.png deleted file mode 100644 index 321f5c0..0000000 Binary files a/content/sesion07/img/12.png and /dev/null differ diff --git a/content/sesion07/img/13.png b/content/sesion07/img/13.png deleted file mode 100644 index c92adfb..0000000 Binary files a/content/sesion07/img/13.png and /dev/null differ diff --git a/content/sesion07/img/14.png b/content/sesion07/img/14.png deleted file mode 100644 index 65fb753..0000000 Binary files a/content/sesion07/img/14.png and /dev/null differ diff --git a/content/sesion07/img/15.png b/content/sesion07/img/15.png deleted file mode 100644 index 0f1ff06..0000000 Binary files a/content/sesion07/img/15.png and /dev/null differ diff --git a/content/sesion07/img/16.png b/content/sesion07/img/16.png deleted file mode 100644 index f8dbd9d..0000000 Binary files a/content/sesion07/img/16.png and /dev/null differ diff --git a/content/sesion07/img/17.png b/content/sesion07/img/17.png deleted file mode 100644 index 77ebcfd..0000000 Binary files a/content/sesion07/img/17.png and /dev/null differ diff --git a/content/sesion07/img/18.png b/content/sesion07/img/18.png deleted file mode 100644 index 7828f0e..0000000 Binary files a/content/sesion07/img/18.png and /dev/null differ diff --git a/content/sesion07/img/19.png b/content/sesion07/img/19.png deleted file mode 100644 index 113fb11..0000000 Binary files a/content/sesion07/img/19.png and /dev/null differ diff --git a/content/sesion07/img/20.png b/content/sesion07/img/20.png deleted file mode 100644 index 1d4247f..0000000 Binary files a/content/sesion07/img/20.png and /dev/null differ diff --git a/content/sesion07/img/21.png b/content/sesion07/img/21.png deleted file mode 100644 index 883e455..0000000 Binary files a/content/sesion07/img/21.png and /dev/null differ diff --git a/content/sesion07/img/22.png b/content/sesion07/img/22.png deleted file mode 100644 index 4d260c2..0000000 Binary files a/content/sesion07/img/22.png and /dev/null differ diff --git a/content/sesion07/img/23.png b/content/sesion07/img/23.png deleted file mode 100644 index 6190091..0000000 Binary files a/content/sesion07/img/23.png and /dev/null differ diff --git a/content/sesion07/img/24.png b/content/sesion07/img/24.png deleted file mode 100644 index efd96f4..0000000 Binary files a/content/sesion07/img/24.png and /dev/null differ diff --git a/content/sesion07/img/25.png b/content/sesion07/img/25.png deleted file mode 100644 index d13089b..0000000 Binary files a/content/sesion07/img/25.png and /dev/null differ diff --git a/content/sesion07/img/26.png b/content/sesion07/img/26.png deleted file mode 100644 index e8e45e1..0000000 Binary files a/content/sesion07/img/26.png and /dev/null differ diff --git a/content/sesion07/img/27.png b/content/sesion07/img/27.png deleted file mode 100644 index cda55d1..0000000 Binary files a/content/sesion07/img/27.png and /dev/null differ diff --git a/content/sesion07/img/28.png b/content/sesion07/img/28.png deleted file mode 100644 index 45dcc46..0000000 Binary files a/content/sesion07/img/28.png and /dev/null differ diff --git a/content/sesion07/img/29.png b/content/sesion07/img/29.png deleted file mode 100644 index 806df5b..0000000 Binary files a/content/sesion07/img/29.png and /dev/null differ diff --git a/content/sesion07/img/30.png b/content/sesion07/img/30.png deleted file mode 100644 index 2430214..0000000 Binary files a/content/sesion07/img/30.png and /dev/null differ diff --git a/content/sesion07/img/31.png b/content/sesion07/img/31.png deleted file mode 100644 index 89c82aa..0000000 Binary files a/content/sesion07/img/31.png and /dev/null differ diff --git a/content/sesion07/img/32.png b/content/sesion07/img/32.png deleted file mode 100644 index 98db503..0000000 Binary files a/content/sesion07/img/32.png and /dev/null differ diff --git a/content/sesion07/index.html b/content/sesion07/index.html deleted file mode 100644 index f6f1e5d..0000000 --- a/content/sesion07/index.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - Sesión 07 | Python Study Group | Fundamentals - - - - - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/content/sesion08/Readme.md b/content/sesion08/Readme.md deleted file mode 100644 index 4bf458a..0000000 --- a/content/sesion08/Readme.md +++ /dev/null @@ -1,695 +0,0 @@ - -![Python La paz](../Logo.png) - -
-
-
- -### Sesión 08 -### Estructuras de datos -### Tuplas ---- -##### Estructura de datos - -Una estructura de datos es una forma de organizar y almacenar datos - -De manera eficiente para su uso y manipulación - -Las más comunes son tuplas, listas, conjuntos y diccionarios - ---- -| Estructura | Características | Ejemplo | -| ------------------ | --------------------------------- | --------------------- | -| Tupla | Inmutable, ordenada, indexada | (1,2,3) | -| Lista | Mutable, ordenada, indexada | [1,2,3] | -| Conjunto | Mutable, no ordenado, no indexado | {1,2,3} | -| Diccionario | Mutable, ordenado, indexado | {'a':1, 'b':2, 'c':3} | - - ---- -##### ¿Qué es una tupla? - ---- -Una tupla es un par ordenado de elementos que se almacenan juntos `(x,y)` - -En un inicio almacena dos elementos - -Posteriormente se extendió a más elementos - ---- -Una tupla es una secuencia de objetos **INMUTABLES** - -Ordenados e indexados - ---- -- **Inmutable**: No se puede modificar, agregar o eliminar elementos después de su creación -```python -tupla = (1,2,3) -tupla[0] = 4 # Error -``` - ---- -- **Ordenada**: Los elementos tienen un orden definido y no cambian -```python -tupla1 = (1,2,3) -tupla2 = (3,2,1) -print (tupla1 == tupla2) # False -``` - ---- -- **Indexada**: Cada elemento tiene un índice asociado a su posición en la tupla para acceder a él - -```python -tupla = (1,2,3) -tupla[0] # 1 -tupla[1] # 2 -tupla[2] # 3 -``` - ---- -¿Para qué se usa una tupla? - ---- -1. Empaquetado y desempaquetado de valores - -```python -coordenadas = (3,5) -x,y = coordenadas -``` - ---- -2. Enviar y devolver múltiples valores de una función - -```python -def coordenadas(coordenada): - x,y = coordenada - x = x + 1 - y = y + 1 - return (x,y) -``` - ---- -3. En diccionarios se puede utilizar una tupla como llave compuesta - -```python -agenda = {('Juan','Perez'): 1234567} -``` - ---- - -Una tupla puede almacenar cualquier tipo de dato a la vez - -```python -tupla = (1,2.0,'hola',True) -``` - ---- -Al igual que las cadenas de texto - -- Se puede acceder a los elementos de una tupla mediante el uso de índices -- Se puede utilizar slicing para obtener subconjuntos de la tupla - ---- -##### ¿Como declaro una tupla? - -En python se declara una tupla utilizando comas para separar los elementos - ---- -No es necesario utilizar paréntesis pero **Sí** es una buena práctica para identificar hasta donde es una tupla - -También se puede utilizar la función `tuple()` para crear una tupla - ---- - -```python -mi_tupla = (elemento1, elemento2, elemento3, ...) -``` - -- mi_tupla es el nombre de la variable -- elemento1, elemento2, elemento3, son los objetos que se almacenarán en la tupla - ---- -Crearemos un archivos para la sesion08.py en nuestro proyecto y crearemos tuplas - ---- -Tupla de enteros - -```python -print ("Tupla de enteros") -enteros = (1,2,3,4,5,6) -print (enteros) -print (type(enteros)) -``` - -![Tupla Enteros](./img/01.png) - ---- -Tupla de cadenas - -```python -print ("Tupla de cadenas") -cadenas = ("hola", "mundo", "desde", "python") -print (cadenas) -print (type(cadenas)) -``` - -![Tupla Cadenas](./img/02.png) - ---- -Tupla mixta - -```python -print ("Tupla Mixta") -mixta = (1, "hola", True, 2.5) -print (mixta) -print (type(mixta)) -``` - -![Tupla Mixta](./img/03.png) - ---- -Tupla vacía - -```python -print ("Tupla vacia") -vacia = () -print (vacia) -print (type(vacia)) -``` - -![Tupla Vacía](./img/04.png) - ---- -Tupla con un solo elemento - -```python -print ("Tupla de un solo elemento") -uno = (1,) -print (uno) -print (type(uno)) -``` - -![Tupla Un Elemento](./img/05.png) - ---- -Se usa la función `tuple()` para crear una tupla, su utilidad es convertir una secuencia en una tupla - -Utilizado con cadenas, listas, otras tuplas, etc. - ---- -Tupla de una cadena - -```python -print ("Tupla utilizando la función tuple()") -constructor = tuple("hola") -print (constructor) -print (type(constructor)) -``` - -![Tupla Función](./img/06.png) - ---- -##### Indexación y Slicing - -Se puede acceder a los diferentes valores de la tupla utilizando indexación - -Obtener solo una parte de la tupla utilizando slicing - -Similar a las cadenas de texto - ---- -Se accede a los elementos de la tupla de forma positiva de izquierda a derecha - -Empezando en el índice 0 - -Hasta la `longitud-1` de la tupla - ---- -Acceso utilizando índices positivos - -```python -print ("Indexado positivo de una tupla") -tupla = (1,2.0, "hola", True) -print (tupla[0], type(tupla[0])) -print (tupla[1], type(tupla[1])) -print (tupla[2], type(tupla[2])) -print (tupla[3], type(tupla[3])) -``` - -![Indexado Positivo](./img/07.png) - ---- -Se accede a los elementos de la tupla de forma negativa de derecha a izquierda - -Empezando en el índice `-1` - -Hasta la `-longitud` de la tupla - ---- - -Acceso utilizando índices negativos - -```python -print ("Indexado negativo de una tupla") -tupla = (1,2.0, "hola", True) -print (tupla[-1], type(tupla[-1])) -print (tupla[-2], type(tupla[-2])) -print (tupla[-3], type(tupla[-3])) -print (tupla[-4], type(tupla[-4])) -``` - -![Indexado Negativo](./img/08.png) - ---- -El slicing se utiliza para obtener subconjuntos de la tupla - -Permite extraer una porción de la tupla utilizando dos índices de inicio y fin - -El resultado es una nueva tupla - ---- -La sintaxis para el slicing es - -![Slicing](./img/09.png) - -- `inicio` es el índice donde inicia (incluido) -- `fin` es el índice donde termina (excluido) -- `paso` es el tamaño del paso entre los elementos - ---- - -Slicing de una tupla - -``` python [1-3|4|5-6] -print ("Slicing de una tupla") -tupla = (0,1,2,3,4,5,6,7,8,9,10) -print (tupla) -sub_tupla = tupla[0:5] -print (sub_tupla) -print (type(sub_tupla)) -``` - -![Slicing](./img/10.png) - ---- -Slicing con paso positivo - -``` python [1-3|4|5-6] -print ("Slicing de una tupla con saltos") -tupla = (0,1,2,3,4,5,6,7,8,9,10) -print (tupla) -sub_tupla = tupla[0:10:2] -print (sub_tupla) -print (type(sub_tupla)) -``` - -![Slicing Paso Positivo](./img/11.png) - ---- -Slicing con paso negativo - -``` python [1-3|4|5-6] -print ("Slicing de una tupla con saltos negativos") -tupla = (0,1,2,3,4,5,6,7,8,9,10) -print (tupla) -sub_tupla = tupla[7:2:-2] -print (sub_tupla) -print (type(sub_tupla)) -``` - -![Slicing Paso Negativo](./img/12.png) - ---- -##### Concatenación de tuplas - -Las tuplas se pueden concatenar utilizando el operador `+` - -El resultado es una nueva tupla - -`(a,b) + (c,d) = (a,b,c,d)` - ---- -Concatenación de tuplas - -```python -print ("Concatenación de tuplas") -tupla1 = (1,2,3) -tupla2 = (4,5,6) -concatenar = tupla1 + tupla2 -print (tupla1, tupla2) -print (concatenar) -print (type(concatenar)) -``` - -![Concatenación](./img/13.png) - ---- -##### Repetición de tuplas - -Las tuplas se pueden repetir utilizando el operador `*` y un número entero `n` - -El resultado es una nueva tupla - -`(a,b) * n = (a,b,a,b,...,a,b)` n veces - ---- -Repetición de tuplas - -```python -print ("Repetición de tuplas") -tupla = (1,2,3) -repetir = tupla * 3 -print (tupla) -print (repetir) -print (type(repetir)) -``` - -![Repetición](./img/14.png) - ---- -##### Asignación múltiple de valores - -Es una forma de asignar el valor a variables variables en una sola línea desempaquetando los valores de una tupla - ---- - -No utiliza los indices de la tupla ni los paréntesis - -La cantidad de variables debe ser igual a la cantidad de elementos de la tupla - ---- -Asignación múltiple de valores - -```python -print ("Asignación múltiple") -persona = ("Jhon", "Doe", 22, 1.75) -nombre, apellido, edad, estatura = persona -print (persona) -print (nombre) -print (apellido) -print (edad) -print (estatura) -``` - -![Asignación Múltiple](./img/15.png) - ---- -##### Métodos de las tuplas - -Las tuplas son inmutables, no tienen métodos que modifiquen su contenido - -Solo tienen dos métodos - -- `count()` -- `index()` - -Se llama a los métodos utilizando la notación con punto - -`tupla.metodo()` - ---- -`index()` recibe un valor y devuelve el índice de la primera aparición de ese valor - -Si el valor no existe en la tupla, se genera un error - -```python -print ("Método index(valor)") -tupla = (1,2.0, "hola", True) -print (tupla.index(2.0)) -print (tupla.index("hola")) -``` - -![Index](./img/16.png) - ---- -`count()` recibe un valor y devuelve el número de veces que aparece en la tupla - -```python -print ("Método count(valor)") -tupla = (1, 2.0, "hola", False, "hola", "HOLA") -print (tupla.count(1)) -print (tupla.count("hola")) -print (tupla.count(10)) -``` - -![Count](./img/17.png) - ---- -##### Funciones con tuplas - -Las tuplas interactúan con funciones propias de Python estas son las más importantes - -- `len()` -- `max()` -- `min()` -- `sum()` - -Existen otras funciones pueden encontrarse en la [documentación](https://docs.python.org/3/library/stdtypes.html#common-sequence-operations) -y [funciones incorporadas](https://python-reference.readthedocs.io/en/latest/docs/tuple/#functions) - ---- -`len()` devuelve la longitud de la tupla - -```python [1-2|3|4-5] -print ("Función len()") -tupla = (1,2.0, "hola", True) -longitud = len(tupla) -print (tupla) -print (longitud) -``` - -![Len](./img/18.png) - ---- -`max()` devuelve el valor máximo de la tupla, se debe asegurar que los elementos sean comparables entre sí - -Si la tupla es de cadenas, se comparan alfabéticamente - -Si la tupla es de enteros, se comparan numéricamente - -NO mezclar tipos de datos - ---- -`max()` - -```python [1-2|3|4-5] -print ("Función max()") -tupla = (1,2,10,5,8,0) -maximo = max(tupla) -print (tupla) -print (maximo) -``` - -![Max](./img/19.png) - ---- -`min()` devuelve el valor mínimo de la tupla, se debe asegurar que los elementos sean comparables entre sí - -Si la tupla es de cadenas, se comparan alfabéticamente - -Si la tupla es de enteros, se comparan numéricamente - -NO mezclar tipos de datos - ---- -`min()` - -```python [1-2|3|4-5] -print ("Función min()") -tupla = ("a","z","c","b","f","d") -minimo = min(tupla) -print (tupla) -print (minimo) -``` - -![Min](./img/20.png) - ---- -`sum()` devuelve la suma de los elementos de la tupla - -Se debe asegurar que los elementos sean numéricos - -```python [1-2|3|4-5] -print ("Función sum()") -tupla = (1.0, 0.5, 2.5, 3.1) -suma = sum(tupla) -print (tupla) -print (suma) -``` - -![Sum](./img/21.png) - ---- -##### Tuplas anidadas - -Una tupla puede contener otras tuplas como elementos - -```python [1-2|3-4|5|6] -print ("Tuplas anidadas") -tupla = (1,2,3, (4,5,6)) -print (tupla) -print (tupla, type(tupla)) -print (tupla[3], type(tupla[3])) -print (tupla[3][0], type(tupla[3][0])) -``` - -![Anidadas](./img/22.png) - ---- -Anidado al detalle - -```python [1-3|4-5|6-7|8-9] -print ("Tuplas anidadas") -tupla = (1,2,3, (4,5,6)) -print (tupla, type(tupla)) -anidado = tupla[3] -print (anidado, type(anidado)) -valor_anidado_0 = anidado[0] -print (valor_anidado_0, type(valor_anidado_0)) -valor_anidado_1 = tupla[3][1] -print (valor_anidado_1, type(valor_anidado_1)) -``` - ---- - - ---- -##### Commit -Commit de la sesión a nuestro repositorio - -```sh -git add . -git commit -m "Clase sesión 08" -git push -``` - ---- -##### Resumen - -- Una estructura de datos es una forma de organizar y almacenar datos -- Son secuencias inmutables -- Se declaran con comas y paréntesis -- Acceder a los elementos con índices y slicing -- Concatenar y repetir tuplas -- Asignar múltiples valores a variables -- Tienen dos métodos `index()` y `count()` -- `len()`, `max()`, `min()`, `sum()` son compatibles -- Anidar tuplas - ---- -##### Retos - -Crear una carpeta con el nombre "retos_sesion_08" en la cual por cada ejercicio debe crear un script de python - -```bash -# Ejemplo carpeta -psg-example/ - retos_sesion_08/ - ejercicio_01.py - ejercicio_02.py - ... - ejercicio_06.py - sesion08.ipynb -``` - -Subir la carpeta a su repositorio en GitHub cuando termine los retos - ---- -1. Ingresa por teclado tres coordenadas `'x','y','z'`, - - Convierte los valores a enteros almacena los 3 valores en una tupla e imprime el resultado - ---- -2. Crea una tupla con los siguientes elementos: - -```python -'a','b','c','d','e','f','g','h','i','j' -``` - - - Imprime el primer elemento - - Imprime el último elemento - - Imprime un slice del índice 3 al 5 - - Imprime un slice del 5 al 9 con pasos de 3 - - Imprime un slice del 9 al 0 con pasos de -2 - ---- -3. Ingresa una pregunta por teclado y almacena el valor en una tupla - - Concatena las tupla - -```python -('¿', ) + pregunta + ('?', ) -``` - - - Imprime el resultado concatenado - - Repite la tupla concatenada 2 veces e imprime el nuevo resultado - ---- -4. Las notas de un estudiante durante un semestre son: -```python -10, 61, 00, 21, 22, 0, 32, 30, 41, 51, 5, 23, 100 -``` - -Genera una tupla con los resultados y calcula el promedio -para saber si aprobó o no el semestre utiliza la función `sum()` y `len()` - -El promedio debe ser mayor o igual a 51 para aprobar - ---- -5. De la siguiente guía telefónica - -```markdown -- Jhon, 591123456, Villa fátima -- Jane, 591546324, Obrajes -- Dogg, 591222421, Miraflores -- Kity, 591753159, Achumani -``` - -Genera una tupla anidada e imprime el resultado - -Ejemplo: -```bash -((Nombre, Telf, Dir), (Nombre, Telf, Dir), ...) -``` - ---- -6. De las tuplas de coordenadas - -`$(x1,y1) = (-20, -20) $` y `$ (x2,y2) = (40, 20)$` - -Encuentra las coordenadas del punto medio, almacena en una tupla e imprime el resultado - -`$(x,y)$` - ---- -7. Convertir y ejecutar el archivo de la "sesion08.py" a un archivo en jupyter notebook - ---- - - -
-
-
-
-
- -[![GitHub](../../content/github_logo.png) ](https://github.com/python-la-paz/python-study-group-fundamentals/tree/main/content/sesion08) - -Repositorio de la Sesión - ---- - -## Bibliografía y Referencias -- [Pythonlearn](https://do1.dr-chuck.com/pythonlearn/ES_es/pythonlearn.pdf) -- [Data Structures](https://docs.python.org/3/tutorial/datastructures.html) -- [Tuples and Sequences](https://docs.python.org/es/3/tutorial/datastructures.html#tuples-and-sequences) -- [Tuples](https://python-reference.readthedocs.io/en/latest/docs/tuple/) -- [Tuplas en Python](https://ellibrodepython.com/tuplas-python) -- [Listas, tuplas y cadenas](https://dcain.etsin.upm.es/~carlos/bookCNP/03.02_ListasTuplasCadenas.html) -- [Sequence Types — list, tuple, range](https://docs.python.org/3.9/library/stdtypes.html#sequence-types-list-tuple-range) -- [tuple.index](https://python-reference.readthedocs.io/en/latest/docs/tuple/lindex.html) -- [len()](https://python-reference.readthedocs.io/en/latest/docs/functions/len.html) -- [max()](https://python-reference.readthedocs.io/en/latest/docs/functions/max.html) -- [min()](https://python-reference.readthedocs.io/en/latest/docs/functions/min.html) -- [sum()](https://python-reference.readthedocs.io/en/latest/docs/functions/sum.html) -- [Common Sequence Operations](https://docs.python.org/3/library/stdtypes.html#common-sequence-operations) -- [Built-in Functions](https://python-reference.readthedocs.io/en/latest/docs/tuple/#functions) -- [Python Tutor](https://pythontutor.com/) \ No newline at end of file diff --git a/content/sesion08/img/01.png b/content/sesion08/img/01.png deleted file mode 100644 index 1ecf276..0000000 Binary files a/content/sesion08/img/01.png and /dev/null differ diff --git a/content/sesion08/img/02.png b/content/sesion08/img/02.png deleted file mode 100644 index d1d39f5..0000000 Binary files a/content/sesion08/img/02.png and /dev/null differ diff --git a/content/sesion08/img/03.png b/content/sesion08/img/03.png deleted file mode 100644 index 2c90d05..0000000 Binary files a/content/sesion08/img/03.png and /dev/null differ diff --git a/content/sesion08/img/04.png b/content/sesion08/img/04.png deleted file mode 100644 index 4c136ad..0000000 Binary files a/content/sesion08/img/04.png and /dev/null differ diff --git a/content/sesion08/img/05.png b/content/sesion08/img/05.png deleted file mode 100644 index eb5948d..0000000 Binary files a/content/sesion08/img/05.png and /dev/null differ diff --git a/content/sesion08/img/06.png b/content/sesion08/img/06.png deleted file mode 100644 index bcdaa4a..0000000 Binary files a/content/sesion08/img/06.png and /dev/null differ diff --git a/content/sesion08/img/07.png b/content/sesion08/img/07.png deleted file mode 100644 index b105b1e..0000000 Binary files a/content/sesion08/img/07.png and /dev/null differ diff --git a/content/sesion08/img/08.png b/content/sesion08/img/08.png deleted file mode 100644 index 55ed8a7..0000000 Binary files a/content/sesion08/img/08.png and /dev/null differ diff --git a/content/sesion08/img/09.png b/content/sesion08/img/09.png deleted file mode 100644 index da756c5..0000000 Binary files a/content/sesion08/img/09.png and /dev/null differ diff --git a/content/sesion08/img/10.png b/content/sesion08/img/10.png deleted file mode 100644 index ad83f86..0000000 Binary files a/content/sesion08/img/10.png and /dev/null differ diff --git a/content/sesion08/img/11.png b/content/sesion08/img/11.png deleted file mode 100644 index 965a60f..0000000 Binary files a/content/sesion08/img/11.png and /dev/null differ diff --git a/content/sesion08/img/12.png b/content/sesion08/img/12.png deleted file mode 100644 index a106552..0000000 Binary files a/content/sesion08/img/12.png and /dev/null differ diff --git a/content/sesion08/img/13.png b/content/sesion08/img/13.png deleted file mode 100644 index f564d58..0000000 Binary files a/content/sesion08/img/13.png and /dev/null differ diff --git a/content/sesion08/img/14.png b/content/sesion08/img/14.png deleted file mode 100644 index 511b2bd..0000000 Binary files a/content/sesion08/img/14.png and /dev/null differ diff --git a/content/sesion08/img/15.png b/content/sesion08/img/15.png deleted file mode 100644 index 09d8e5e..0000000 Binary files a/content/sesion08/img/15.png and /dev/null differ diff --git a/content/sesion08/img/16.png b/content/sesion08/img/16.png deleted file mode 100644 index 32edc8e..0000000 Binary files a/content/sesion08/img/16.png and /dev/null differ diff --git a/content/sesion08/img/17.png b/content/sesion08/img/17.png deleted file mode 100644 index a429ade..0000000 Binary files a/content/sesion08/img/17.png and /dev/null differ diff --git a/content/sesion08/img/18.png b/content/sesion08/img/18.png deleted file mode 100644 index a5fab5c..0000000 Binary files a/content/sesion08/img/18.png and /dev/null differ diff --git a/content/sesion08/img/19.png b/content/sesion08/img/19.png deleted file mode 100644 index 6d52102..0000000 Binary files a/content/sesion08/img/19.png and /dev/null differ diff --git a/content/sesion08/img/20.png b/content/sesion08/img/20.png deleted file mode 100644 index d8a7166..0000000 Binary files a/content/sesion08/img/20.png and /dev/null differ diff --git a/content/sesion08/img/21.png b/content/sesion08/img/21.png deleted file mode 100644 index fa09fad..0000000 Binary files a/content/sesion08/img/21.png and /dev/null differ diff --git a/content/sesion08/img/22.png b/content/sesion08/img/22.png deleted file mode 100644 index a16cb0b..0000000 Binary files a/content/sesion08/img/22.png and /dev/null differ diff --git a/content/sesion08/index.html b/content/sesion08/index.html deleted file mode 100644 index 6e786db..0000000 --- a/content/sesion08/index.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - Sesión 08 | Python Study Group | Fundamentals - - - - - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/content/sesion09/Readme.md b/content/sesion09/Readme.md deleted file mode 100644 index d8053d1..0000000 --- a/content/sesion09/Readme.md +++ /dev/null @@ -1,1040 +0,0 @@ - -![Python La paz](../Logo.png) - -
-
-
- -### Sesión 09 -### Estructuras de datos -### Listas ---- -##### Estructura de datos - -Una estructura de datos es una forma de organizar y almacenar datos - -De manera eficiente para su uso y manipulación - -Las más comunes son tuplas, listas, conjuntos y diccionarios - ---- -| Estructura | Características | Ejemplo | -| ------------------ | --------------------------------- | --------------------- | -| Tupla | Inmutable, ordenada, indexada | (1,2,3) | -| Lista | Mutable, ordenada, indexada | [1,2,3] | -| Conjunto | Mutable, no ordenado, no indexado | {1,2,3} | -| Diccionario | Mutable, ordenado, indexado | {'a':1, 'b':2, 'c':3} | - ---- -##### ¿Que es una lista? - -Una lista es una estructura de datos, así como una tupla y una cadena es una secuencia de valores - -Al igual que la tupla almacena objetos o items que pueden ser de cualquier tipo - ---- -Una lista es una secuencia de objetos **MUTABLES** - -Ordenados e indexados - ---- -- **Mutable**: Los elementos de una lista pueden ser modificados después de su creación -```python -lista = [1,2,3] -lista[0] = 4 -print (lista) # [4,2,3] -``` - ---- -- **Ordenada**: Los elementos tienen un orden definido y no cambian a no ser que sean reordenados explícitamente modificando la lista -```python -lista1 = [1,2,3] -lista2 = [3,2,1] -print (lista1 == lista2) # False -``` - ---- -- **Indexada**: Cada elemento tiene un índice asociado a su posición en la lista para acceder a él - -```python -lista = [1,2,3] -lista[0] # 1 -lista[1] # 2 -lista[2] # 3 -``` - ---- -##### ¿Cómo declarar una lista? - -En python se declara una lista utilizando corchetes `[]` y separando los elementos con comas `,` - -```python -mi_lista = [elemento1, elemento2, elemento3, ...] -``` -- `mi_lista` es el nombre de la variable - -- `elemento1, elemento2, elemento3` son los objetos que se almacenarán en la lista - ---- -También se puede declarar una lista utilizando la función `list()` - -Y mediante listas por comprensión - ---- -Crearemos un archivos para la sesion09.py en nuestro proyecto y empecemos a crear listas - ---- -Lista de enteros -```python -print ("Lista de enteros") -mi_lista = [1,2,3,4,5] -print (mi_lista) -``` - -![Lista Enteros](./img/01.png) - ---- -Lista de cadenas -```python -print ("Lista de cadenas") -mi_lista = ["hola", "mundo", "python"] -print (mi_lista) -``` -![Lista Cadenas](./img/02.png) - ---- -Lista mixta -```python -print ("Lista mixta") -mi_lista = [1, "hola", 3.14, "mundo", 5] -print (mi_lista) -``` - -![Lista Mixta](./img/03.png) - ---- -Lista vacía -```python -print ("Lista vacía") -mi_lista = [] -print (mi_lista) -``` -![Lista Vacía](./img/04.png) - ---- -Se usa la función `list()` para crear una lista a partir de una secuencia - -Su utilidad es convertir una tupla, cadena o conjunto en una lista - ---- -Lista a partir de una cadena -```python -print ("Lista a partir de una cadena") -mi_lista = list("hola mundo") -print (mi_lista) -``` - -![Lista a partir de una cadena](./img/05.png) - ---- -Lista a partir de una tupla -```python -print ("Lista a partir de una tupla") -mi_tupla = (1,2,3,4,5) -print (mi_tupla) -mi_lista = list(mi_tupla) -print (mi_lista) -``` - -![Lista a partir de una tupla](./img/06.png) - ---- -Una lista por comprensión es una forma de crear listas a partir de una expresión o secuencia - -Es una forma más compacta y eficiente de crear listas - ---- -```python -print ("Lista por comprensión") -mi_lista = [x for x in range(10)] -print (mi_lista) -``` - -![Lista por comprensión](./img/07.png) - ---- -##### Indexación y slicing - -Se puede acceder a los diferentes valores de la lista utilizando indexación - -Obtener solo una parte de la lista utilizando slicing - -Similar a las cadenas de texto y tuplas - ---- -Se accede a los elementos de la lista de forma positiva de izquierda a derecha - -Empezando en el índice 0 - -Hasta la `longitud-1` de la lista - -![Indexación positivo de una lista](./img/37.png) - ---- -Acceso utilizando índices positivos - -```python -print ("Indexación positivo de una lista") -lista = [1, "hola", 3.14, (1,2)] -print (lista[0], type(lista[0])) -print (lista[1], type(lista[1])) -print (lista[2], type(lista[2])) -print (lista[3], type(lista[3])) -``` - -![Indexación positivo de una lista](./img/08.png) - ---- -Se accede a los elementos de la lista de forma negativa de derecha a izquierda - -Empezando en el índice -1 - -Hasta la `-longitud` de la lista - -![Indexación negativo de una lista](./img/38.png) - ---- -Acceso utilizando índices negativos - -```python -print ("Indexación negativo de una lista") -lista = [1, "hola", 3.14, (1,2)] -print (lista[-1], type(lista[-1])) -print (lista[-2], type(lista[-2])) -print (lista[-3], type(lista[-3])) -print (lista[-4], type(lista[-4])) -``` - -![Indexación negativo de una lista](./img/09.png) - ---- -La indexación no se limita a obtener los valores de la lista - -También se puede modificar los valores de la lista original utilizando la indexación - -```python -print ("Modificación de una lista") -lista = [1, "hola", 3.14, (1,2)] -print (lista) -lista[0] = 2 -lista[1] = "mundo" -print (lista) -``` - -```text -[1, 'hola', 3.14, (1, 2)] -[2, 'mundo', 3.14, (1, 2)] -``` - ---- -El slicing se utiliza para obtener una porción de la lista - -Permite extraer una porción de la lista utilizando dos índices de inicio y fin - -El resultado es una nueva lista - ---- -La sintaxis para el slicing es - -![Slicing](./img/10.png) - -- `inicio` es el índice donde inicia (incluido) -- `fin` es el índice donde termina (excluido) -- `paso` es el incremento o decremento entre los índices (default 1) - ---- -Slicing positivo y negativo - -![Slicing](./img/39.png) - ---- -Slicing de una lista - -```python [1-3|4-5] -print ("Slicing de una lista") -lista = ["P", "y", "t", "h", "o", "n", "L", "a", "P", "a", "z"] -print (lista) -sub_lista = lista[2:7] -print (sub_lista) -print (type(sub_lista)) -``` - -![Slicing de una lista](./img/11.png) - ---- -Slicing con paso positivo - -```python [1-3|4-5] -print ("Slicing con paso positivo") -lista = ["P", "y", "t", "h", "o", "n", "L", "a", "P", "a", "z"] -print (lista) -sub_lista = lista[0:9:3] -print (sub_lista) -``` - -![Slicing con paso positivo](./img/12.png) - ---- -Slicing con paso negativo - -```python [1-3|4-5] -print ("Slicing con paso negativo") -lista = ["P", "y", "t", "h", "o", "n", "L", "a", "P", "a", "z"] -print (lista) -sub_lista = lista[8:2:-4] -print (sub_lista) -``` - -![Slicing con paso negativo](./img/13.png) - ---- -Slicing negativo con paso negativo - -```python [1-3|4-5] -print ("Slicing negativo con paso negativo") -lista = ["P", "y", "t", "h", "o", "n", "L", "a", "P", "a", "z"] -print (lista) -sub_lista = lista[-1:-8:-2] -print (sub_lista) -``` - -![Slicing negativo con paso negativo](./img/14.png) - ---- -Slicing negativo con paso positivo - -```python [1-3|4-5] -print ("Slicing negativo con paso positivo") -lista = ["P", "y", "t", "h", "o", "n", "L", "a", "P", "a", "z"] -print (lista) -sub_lista = lista[-8:-1:2] -print (sub_lista) -``` - -![Slicing negativo con paso positivo](./img/15.png) - ---- -##### Concatenación de listas - -Las listas se pueden concatenar utilizando el operador `+` - -El resultado es una nueva lista con los elementos de las listas originales - -`$ [a,b,c] + [d,e,f] = [a,b,c,d,e,f] $` - ---- -Concatenación de listas - -```python -print ("Concatenación de listas") -lista1 = [1,2,3] -lista2 = ["a","b","c"] -concatenar = lista1 + lista2 -print (lista1, lista2) -print (concatenar) -print (type(concatenar)) -``` - -![Concatenación de listas](./img/16.png) - ---- -##### Repetición de listas - -Las listas se pueden repetir utilizando el operador `*` y un número entero `n` - -El resultado es una nueva lista con los elementos de la lista original repetidos `n` veces - -`$ [a,b,c] * n = [a,b,c, ... a,b,c,] n veces $` - ---- -Repetición de listas - -```python -print ("Repetición de listas") -lista = [True, False] -repetir = lista * 3 -print (lista) -print (repetir) -print (type(repetir)) -``` - -![Repetición de listas](./img/17.png) - ---- -##### Métodos de las listas - -Las listas al ser mutables tiene una mayor cantidad de métodos que las tuplas - -- Métodos de búsqueda -- Métodos de adición -- Métodos de eliminación -- Métodos de ordenamiento -- Métodos de copia - ---- -Se utiliza la notación de punto `.` - -`lista.metodo()` - -`lista.metodo(valor)` - ---- -##### Métodos de búsqueda - -Los métodos de búsqueda nos permiten buscar información en la lista - -- `index()` -- `count()` - ---- -`index(valor)` recibe un valor y devuelve el índice de la primera aparición en la lista, si no existe lanza un error - -![Método index(valor)](./img/40.png) - ---- -`index(valor)` - -```python [1-2|3-4|5-6] -print ("Método index(valor)") -lista = [1,True,3.14,"hola",5] -valor = "hola" -print (valor, lista.index(valor)) -valor = 3.14 -print (valor, lista.index(valor)) -``` - -![Método index(valor)](./img/18.png) - ---- -`count(valor)` recibe un valor y devuelve el número de veces que aparece en la lista - -![Método count(valor)](./img/41.png) - ---- -`count(valor)` - -```python [1-2|3-4|5-6] -print ("Método count(valor)") -lista = [1,True,3.14,"hola",5, True, True, 3.140] -valor = True -print (valor, lista.count(valor)) -valor = 3.14 -print (valor, lista.count(valor)) -``` - -![Método count(valor)](./img/19.png) - ---- -##### Métodos de adición - -Los métodos de adición nos permiten agregar elementos a la lista - -- `insert()` -- `append()` -- `extend()` - -No retornan un valor, modifican la lista original - ---- -`insert(i, valor)` recibe un índice y un valor, inserta el valor en la posición del índice - -```python [1-3|4-5] -print ("Método insert(i, valor)") -lista = [1,2,3,4,5] -print (lista) -lista.insert(2, "OwO") -print (lista) -``` - -![Método insert(i, valor)](./img/20.png) - ---- -`append(valor)` recibe un valor y lo agrega al final de la lista - -```python [1-3|4-5] -print ("Método append(valor)") -lista = [1,2,3,4,5] -print (lista) -lista.append("(OwO=)") -print (lista) -``` - -![Método append(valor)](./img/21.png) - ---- -`extend(iterable)` recibe una secuencia y agrega sus elementos al final de la lista como otra lista, tupla, cadena - -```python [1-3|4-5|6-7|8-9] -print ("Método extend(iterable)") -lista = [1,2,3] -print (lista) -lista.extend(":3") -print (lista) -lista.extend(["(¬_¬ )", "(O_O=)"]) -print (lista) -lista.extend(("😅", "😎")) -print (lista) -``` - -![Método extend(iterable)](./img/22.png) - ---- -##### Métodos de eliminación - -Los métodos de eliminación nos permiten eliminar elementos de la lista - -- `remove()` -- `clear()` - -No retornan un valor, modifican la lista original - -- `pop()` - -Retorna el valor eliminado y modifica la lista original - ---- -`remove(valor)` recibe un valor y elimina la primera aparición de ese valor en la lista si no existe lanza un error - -![Método remove(valor)](./img/42.png) - ---- -`remove(valor)` - -```python [1-3|4-5] -print ("Método remove(valor)") -lista = [1,2,"UwU",4,5, "UwU"] -print (lista) -lista.remove("UwU") -print (lista) -``` - -![Método remove(valor)](./img/23.png) - ---- -`pop(i) o pop()` recibe un index o índice y elimina el elemento en esa posición - -Si no se especifica el índice elimina el último elemento - -![Método pop(i)](./img/43.png) - ---- -`pop(i) o pop()` - -```python [1-3|4-5|6-8] -print ("Método pop(i)") -lista = ["OwO",3,"UwU",5] -print (lista) -lista.pop(1) -print (lista) -print ("Método pop()") -lista.pop() -print (lista) -``` - -![Método pop(i)](./img/24.png) - ---- -`clear()` elimina todos los elementos de la lista dejándola -vacía - -```python [1-3|4-5] -print ("Método clear()") -lista = ["ewe","OwO","UwU"] -print (lista) -lista.clear() -print (lista) -``` - -![Método clear()](./img/25.png) - ---- -##### Métodos de ordenamiento - -Los métodos de reordenar nos permiten ordenar los elementos de la lista - -- `sort()` -- `reverse()` - -No retornan un valor, modifican la lista original - ---- -`sort()` ordena los elementos de la lista de menor a mayor - -```python [1-3|4-5] -print ("Método sort()") -lista = [3,1,5,2,4] -print (lista) -lista.sort() -print (lista) -``` - -![Método sort()](./img/26.png) - ---- -`sort(reverse=True)` ordena los elementos de la lista de mayor a menor - -```python [1-3|4-5] -print ("Método sort()") -lista = [3,1,5,2,4] -print (lista) -lista.sort(reverse=True) -print (lista) -``` - -![Método sort(reverse)](./img/27.png) - ---- -`reverse()` invierte el orden de los elementos de la lista - -```python [1-3|4-5] -print ("Método reverse()") -lista = [3,1,5,2,4] -print (lista) -lista.reverse() -print (lista) -``` - -![Método reverse()](./img/28.png) - ---- -##### Métodos de copia - -Los métodos de copia nos permiten copiar los elementos de la lista - -- `copy()` - ---- -Cuando se asigna una lista a otra variable se crea una referencia a la lista original - -NO se crea una copia de la lista, si se modifica esta se modifica la original - -```python [1-3|4-5|6-7] -print ("Asignación de lista") -lista = [1,2,3,4,5] -print (lista) -copia = lista -copia[0] = 6 -print (copia) -print (lista) -``` -```text -Asignación de lista -[1, 2, 3, 4, 5] -[6, 2, 3, 4, 5] -[6, 2, 3, 4, 5] -``` - ---- -Para crear una copia de la lista se debe utilizar el método `copy()` o el slicing `[:]` - -```python [1-3|4|5|6-7] -print ("Método copia con slicing") -lista = [1,2,3,4,5] -print (lista) -copia = lista[:] -copia[0] = 6 -print (copia) -print (lista) -``` -```text -Método copia con slicing -[1, 2, 3, 4, 5] -[6, 2, 3, 4, 5] -[1, 2, 3, 4, 5] -``` - ---- -`copy()` devuelve una copia de la lista es equivalente al slicing `[:]` - -```python [1-3|4-5|6] -print ("Método copy()") -lista = [3,1,5,2,4] -print (lista) -copia = lista.copy() -print (copia) -print (copia == lista) -``` - -![Método copy()](./img/29.png) - ---- -Método copia con slicing - -```python python [1-3|4|5|6-7] -print ("Método copia con slicing") -lista = [1,2,3,4,5] -print (lista) -copia = lista.copy() -copia[0] = 6 -print (copia) -print (lista) -``` - -```text -Método copia con slicing -[1, 2, 3, 4, 5] -[6, 2, 3, 4, 5] -[1, 2, 3, 4, 5] -``` - ---- -##### Funciones con listas - -Las listas interactúan con funciones propias de python que acepten secuencias de datos - -- `len()` -- `max()` -- `min()` -- `sum()` - -Existen otras funciones pueden encontrarse en la [documentación](https://docs.python.org/3/library/stdtypes.html#common-sequence-operations) y [funciones incorporadas](https://python-reference.readthedocs.io/en/latest/docs/list/#functions) - ---- -`len()` devuelve la longitud de la lista o el número de elementos que contiene - ---- -`len()` - -```python [1-3|4] -print ("Función len()") -lista = [1,True,3.14,"🐍",5] -print (lista) -print (len(lista)) -``` - -![Función len()](./img/30.png) - ---- -`max()` devuelve el valor máximo de la lista o el elemento más grande - -Si la lista contiene cadenas devuelve el valor máximo en orden alfabético - -Si la lista contiene enteros y flotantes devuelve el valor máximo numérico - ---- -`max()` - -```python [1-3|4|5-6|7] -print ("Función max()") -lista = [1,2,3,4,5] -print (lista) -print (max(lista)) -lista = ["a","b","c","d","e"] -print (lista) -print (max(lista)) -``` - -![Función max()](./img/31.png) - ---- -`min()` devuelve el valor mínimo de la lista o el elemento más pequeño - -Si la lista contiene cadenas devuelve el valor mínimo en orden alfabético - -Si la lista contiene enteros y flotantes devuelve el valor mínimo numérico - ---- -`min()` - -```python [1-3|4|5-6|7] -print ("Función min()") -lista = [1,2,3,4,5] -print (lista) -print (min(lista)) -lista = ["a","b","c","d","e"] -print (lista) -print (min(lista)) -``` - -![Función min()](./img/32.png) - ---- -`sum()` devuelve la suma de los elementos de la lista - -Se debe asegurar que los elementos de la lista sean numéricos - ---- -`sum()` - -```python [1-3|4] -print ("Función sum()") -lista = [1,2,3,4,5] -print (lista) -print (sum(lista)) -``` - -![Función sum()](./img/33.png) - ---- -##### Comparación de listas - -Podemos consultar si una lista contiene un elemento específico utilizando el operador `in`, `not in` - -Si una variable hace referencia a otra variable podemos utilizar el `is` , `is not`, para comparar si son la misma lista - ---- -`in` - `not in` - -```python [1-3|4-5|6-7|8] -print ("Comparación de listas") -lista = [1,2,3,4,5] -print (lista) -print (3 in lista) -print (6 in lista) -print (3 not in lista) -print (6 not in lista) -print ([1,2,3] in lista) -``` - -![Comparación de listas](./img/34.png) - ---- -`is` - `is not` - -```python [1-5|6|7|8] -print ("Comparación de listas") -lista1 = [1,2,3,4,5] -lista2 = [1,2,3,4,5] -lista3 = [1,2] -print (lista1, lista2, lista3) -print (lista1 is lista2) -print (lista1 is not lista2) -print (lista3 is lista1) -``` - -![Comparación de listas](./img/35.png) - ---- -##### Operadores de comparación - -Podemos comparar listas utilizando los operadores de comparación, estos comparan los elementos de las listas uno a uno - -- `==` - Igualdad -- `!=` - Desigualdad -- `>` - Mayor que -- `<` - Menor que -- `>=` - Mayor o igual que -- `<=` - Menor o igual que - ---- -`<` y `<=` -- Comienza comparando el primer elemento de cada lista -- Si son iguales pasa al siguiente elemento de cada lista -- Si el primer elemento de la primera lista es menor que el de la segunda lista, el resultado es `True` -- Si el primer elemento de la primera lista es mayor que el de la segunda lista el resultado es `False` - ---- -```python -print ("Menor y Menor Igual que") -print ([1,2,3] <= [1,2,4]) -print ([1,2,3] <= [1,2,2,2]) -print ([1,2,3] <= [2]) -print ([1,2,3] < [1,2,3]) -print ([1,2,3] <= [1,2,3]) -``` - -```text -Menor y Menor Igual que -True -False -True -False -True -``` - ---- -`>` y `>=` -- Comienza comparando el primer elemento de cada lista -- Si son iguales pasa al siguiente elemento de cada lista -- Si el primer elemento de la primera lista es mayor que el de la segunda lista, el resultado es `True` -- Si el primer elemento de la primera lista es menor que el de la segunda lista el resultado es `False` - ---- -```python -print ("Mayor y Mayor Igual que") -print ([1,2,3] >= [1,2,4]) -print ([1,2,3] >= [1,2,2,2]) -print ([1,2,3] >= [2]) -print ([1,2,3] > [1,2,3]) -print ([1,2,3] >= [1,2,3]) -``` - -```text -Mayor y Mayor Igual que -False -True -False -False -True -``` - ---- -`==` y `!=` -- Compara si los elementos de las listas son iguales -- Si todos los elementos son iguales el resultado es `True` -- Si al menos un elemento es diferente el resultado es `False` - ---- -```python -print ("Igual y Desigual que") -print ([1,2,3] == [1,2,3]) -print ([1,2,3] == [1,2,4]) -print ([1,2,3] != [1,2,3]) -print ([1,2,3] != [1,2,4]) -``` - -```text -Igual y Desigual que -True -False -False -True -``` - ---- -##### Listas anidadas - -Las listas anidadas son listas que contienen otras listas como elementos - -Se pueden crear listas anidadas de cualquier profundidad - ---- -Listas anidadas - -```python [1-4|5-7|8-10] -print ("Listas anidadas") -lista = [1,2,3,[4,5,6]] -print (lista) -print (type(lista)) -valor_lista = lista[3] -print (valor_lista) -print (type(valor_lista)) -valor = valor_lista[1] -print (valor) -print (type(valor)) -``` - -![Listas anidadas](./img/36.png) - ---- - - ---- -##### Commit -Commit de la sesión a nuestro repositorio - -```sh -git add . -git commit -m "Clase sesión 09" -git push -``` - ---- -##### Resumen Listas - -- Las listas son una estructura de datos iterable que almacena objetos o items -- Son mutables, ordenadas e indexadas -- Se declaran con corchetes y comas -- Acceder a los elementos con índices y slicing -- Concatenar y repetir listas con `+` y `*` - ---- -##### Resumen Listas -- Asignar múltiples valores a variables -- Tienen varios métodos - - `index()`, `count()` - - `insert()`, `append()`, `extend()` - - `remove()`, `pop()`, `clear()`, - - `sort()`, `reverse()`, - - `copy()` -- `len()`, `max()`, `min()`, `sum()` son compatibles -- Se puede anidar listas - ---- -##### Retos - -Crear una carpeta con el nombre "retos_sesion_09" en la cual por cada ejercicio debe crear un script de python - -```bash -# Ejemplo carpeta -psg-example/ - retos_sesion_09/ - ejercicio_01.py - ejercicio_02.py - ejercicio_03.py - ejercicio_04.py - sesion09.ipynb -``` - -Subir la carpeta a su repositorio en GitHub cuando termine los retos - ---- -1. Crear una lista con 5 números flotantes y 5 enteros y mostrar todos los elementos y sus tipos de datos utilizando sus índices - ---- -2. De la siguiente lista `[5,4,3,2,2,2,0,0,1,2]` obtener una sub lista inversa utilizando saltos de 3 en 3 - ---- -3. Crear una lista de personas con 10 nombres de personas - 1. Obtener una sub lista de 5 a 9 con saltos de 2 en 2 - 2. Buscar si existe el nombre "José" en la lista original - 3. Ordenar la sub lista alfabéticamente `a-z` - 4. Ordenar la lista original alfabéticamente descendente `z-a` - ---- -4. Una dulcería tiene 2 listas una con los productos y otra con los precios - 1. Agregar 2 productos nuevos al final de las listas - 2. Eliminar el producto con el nombre "Bon Bon Bum" de las listas - 3. ¿Cuánto cuesta el producto "Oreo" y "Chizitos"? - 4. ¿Cuál es el producto más caro y el más barato? - - > Parte 1/2 ---- -4. Una dulcería tiene 2 listas una con los productos y otra con los precios - 5. ¿Cuántos productos tienes en total? - 6. ¿Cuanto cuestan todos los productos? - 7. Ordena los productos y precios del más barato al más caro - 8. Eliminar todos los productos de las listas - - > Parte 2/2 ---- -5. Convertir y ejecutar el archivo de la "sesion09.py" a un archivo en jupyter notebook - ---- - - -
-
-
-
-
- -[![GitHub](../../content/github_logo.png) ](https://github.com/python-la-paz/python-study-group-fundamentals/tree/main/content/sesion09) - -Repositorio de la Sesión - ---- - -## Bibliografía y Referencias -- [Pythonlearn](https://do1.dr-chuck.com/pythonlearn/ES_es/pythonlearn.pdf) -- [List](https://python-reference.readthedocs.io/en/latest/docs/list/) -- [Listas por comprensión](https://www.analyticslane.com/2019/09/23/listas-por-comprension-en-python/) -- [Data Structures](https://docs.python.org/3/tutorial/datastructures.html#data-structures) -- [Google Python List](https://developers.google.com/edu/python/lists) -- [Built-in Python List](https://builtin.com/data-science/python-list) -- [Stdtypes Lists](https://docs.python.org/3/library/stdtypes.html#lists) -- [Indexing](https://python-reference.readthedocs.io/en/latest/docs/brackets/indexing.html) -- [Slicing](https://python-reference.readthedocs.io/en/latest/docs/brackets/slicing.html) -- [Concatenation](https://python-reference.readthedocs.io/en/latest/docs/operators/concatenation.html) -- [Remove](https://python-reference.readthedocs.io/en/latest/docs/list/remove.html) -- [Common Sequence Operations](https://docs.python.org/3/library/stdtypes.html#common-sequence-operations) diff --git a/content/sesion09/img/01.png b/content/sesion09/img/01.png deleted file mode 100644 index 4216d20..0000000 Binary files a/content/sesion09/img/01.png and /dev/null differ diff --git a/content/sesion09/img/02.png b/content/sesion09/img/02.png deleted file mode 100644 index 1dbba63..0000000 Binary files a/content/sesion09/img/02.png and /dev/null differ diff --git a/content/sesion09/img/03.png b/content/sesion09/img/03.png deleted file mode 100644 index acd7df4..0000000 Binary files a/content/sesion09/img/03.png and /dev/null differ diff --git a/content/sesion09/img/04.png b/content/sesion09/img/04.png deleted file mode 100644 index c51bc47..0000000 Binary files a/content/sesion09/img/04.png and /dev/null differ diff --git a/content/sesion09/img/05.png b/content/sesion09/img/05.png deleted file mode 100644 index 06beec0..0000000 Binary files a/content/sesion09/img/05.png and /dev/null differ diff --git a/content/sesion09/img/06.png b/content/sesion09/img/06.png deleted file mode 100644 index 65ac1ea..0000000 Binary files a/content/sesion09/img/06.png and /dev/null differ diff --git a/content/sesion09/img/07.png b/content/sesion09/img/07.png deleted file mode 100644 index 5ef2269..0000000 Binary files a/content/sesion09/img/07.png and /dev/null differ diff --git a/content/sesion09/img/08.png b/content/sesion09/img/08.png deleted file mode 100644 index fd394b4..0000000 Binary files a/content/sesion09/img/08.png and /dev/null differ diff --git a/content/sesion09/img/09.png b/content/sesion09/img/09.png deleted file mode 100644 index 8cc62b3..0000000 Binary files a/content/sesion09/img/09.png and /dev/null differ diff --git a/content/sesion09/img/10.png b/content/sesion09/img/10.png deleted file mode 100644 index c299953..0000000 Binary files a/content/sesion09/img/10.png and /dev/null differ diff --git a/content/sesion09/img/11.png b/content/sesion09/img/11.png deleted file mode 100644 index 9595da0..0000000 Binary files a/content/sesion09/img/11.png and /dev/null differ diff --git a/content/sesion09/img/12.png b/content/sesion09/img/12.png deleted file mode 100644 index df7f2e7..0000000 Binary files a/content/sesion09/img/12.png and /dev/null differ diff --git a/content/sesion09/img/13.png b/content/sesion09/img/13.png deleted file mode 100644 index 089d640..0000000 Binary files a/content/sesion09/img/13.png and /dev/null differ diff --git a/content/sesion09/img/14.png b/content/sesion09/img/14.png deleted file mode 100644 index e372f39..0000000 Binary files a/content/sesion09/img/14.png and /dev/null differ diff --git a/content/sesion09/img/15.png b/content/sesion09/img/15.png deleted file mode 100644 index 88603c7..0000000 Binary files a/content/sesion09/img/15.png and /dev/null differ diff --git a/content/sesion09/img/16.png b/content/sesion09/img/16.png deleted file mode 100644 index a80701a..0000000 Binary files a/content/sesion09/img/16.png and /dev/null differ diff --git a/content/sesion09/img/17.png b/content/sesion09/img/17.png deleted file mode 100644 index 04ab4ed..0000000 Binary files a/content/sesion09/img/17.png and /dev/null differ diff --git a/content/sesion09/img/18.png b/content/sesion09/img/18.png deleted file mode 100644 index 5a055b5..0000000 Binary files a/content/sesion09/img/18.png and /dev/null differ diff --git a/content/sesion09/img/19.png b/content/sesion09/img/19.png deleted file mode 100644 index 9bf7f13..0000000 Binary files a/content/sesion09/img/19.png and /dev/null differ diff --git a/content/sesion09/img/20.png b/content/sesion09/img/20.png deleted file mode 100644 index 34bd2d2..0000000 Binary files a/content/sesion09/img/20.png and /dev/null differ diff --git a/content/sesion09/img/21.png b/content/sesion09/img/21.png deleted file mode 100644 index a490055..0000000 Binary files a/content/sesion09/img/21.png and /dev/null differ diff --git a/content/sesion09/img/22.png b/content/sesion09/img/22.png deleted file mode 100644 index 447a949..0000000 Binary files a/content/sesion09/img/22.png and /dev/null differ diff --git a/content/sesion09/img/23.png b/content/sesion09/img/23.png deleted file mode 100644 index 5937fbf..0000000 Binary files a/content/sesion09/img/23.png and /dev/null differ diff --git a/content/sesion09/img/24.png b/content/sesion09/img/24.png deleted file mode 100644 index 0cbf0c6..0000000 Binary files a/content/sesion09/img/24.png and /dev/null differ diff --git a/content/sesion09/img/25.png b/content/sesion09/img/25.png deleted file mode 100644 index 049f43a..0000000 Binary files a/content/sesion09/img/25.png and /dev/null differ diff --git a/content/sesion09/img/26.png b/content/sesion09/img/26.png deleted file mode 100644 index fbaa1b0..0000000 Binary files a/content/sesion09/img/26.png and /dev/null differ diff --git a/content/sesion09/img/27.png b/content/sesion09/img/27.png deleted file mode 100644 index 7fcddfa..0000000 Binary files a/content/sesion09/img/27.png and /dev/null differ diff --git a/content/sesion09/img/28.png b/content/sesion09/img/28.png deleted file mode 100644 index 2f23f90..0000000 Binary files a/content/sesion09/img/28.png and /dev/null differ diff --git a/content/sesion09/img/29.png b/content/sesion09/img/29.png deleted file mode 100644 index 3394b89..0000000 Binary files a/content/sesion09/img/29.png and /dev/null differ diff --git a/content/sesion09/img/30.png b/content/sesion09/img/30.png deleted file mode 100644 index 143a9ff..0000000 Binary files a/content/sesion09/img/30.png and /dev/null differ diff --git a/content/sesion09/img/31.png b/content/sesion09/img/31.png deleted file mode 100644 index c5097e3..0000000 Binary files a/content/sesion09/img/31.png and /dev/null differ diff --git a/content/sesion09/img/32.png b/content/sesion09/img/32.png deleted file mode 100644 index 794c387..0000000 Binary files a/content/sesion09/img/32.png and /dev/null differ diff --git a/content/sesion09/img/33.png b/content/sesion09/img/33.png deleted file mode 100644 index b60b7a3..0000000 Binary files a/content/sesion09/img/33.png and /dev/null differ diff --git a/content/sesion09/img/34.png b/content/sesion09/img/34.png deleted file mode 100644 index 11f04be..0000000 Binary files a/content/sesion09/img/34.png and /dev/null differ diff --git a/content/sesion09/img/35.png b/content/sesion09/img/35.png deleted file mode 100644 index 4a1c913..0000000 Binary files a/content/sesion09/img/35.png and /dev/null differ diff --git a/content/sesion09/img/36.png b/content/sesion09/img/36.png deleted file mode 100644 index 7b83d37..0000000 Binary files a/content/sesion09/img/36.png and /dev/null differ diff --git a/content/sesion09/img/37.png b/content/sesion09/img/37.png deleted file mode 100644 index a5ba909..0000000 Binary files a/content/sesion09/img/37.png and /dev/null differ diff --git a/content/sesion09/img/38.png b/content/sesion09/img/38.png deleted file mode 100644 index 80bed01..0000000 Binary files a/content/sesion09/img/38.png and /dev/null differ diff --git a/content/sesion09/img/39.png b/content/sesion09/img/39.png deleted file mode 100644 index df87b3a..0000000 Binary files a/content/sesion09/img/39.png and /dev/null differ diff --git a/content/sesion09/img/40.png b/content/sesion09/img/40.png deleted file mode 100644 index 0772463..0000000 Binary files a/content/sesion09/img/40.png and /dev/null differ diff --git a/content/sesion09/img/41.png b/content/sesion09/img/41.png deleted file mode 100644 index d50b5d4..0000000 Binary files a/content/sesion09/img/41.png and /dev/null differ diff --git a/content/sesion09/img/42.png b/content/sesion09/img/42.png deleted file mode 100644 index 221e667..0000000 Binary files a/content/sesion09/img/42.png and /dev/null differ diff --git a/content/sesion09/img/43.png b/content/sesion09/img/43.png deleted file mode 100644 index c7677f7..0000000 Binary files a/content/sesion09/img/43.png and /dev/null differ diff --git a/content/sesion09/index.html b/content/sesion09/index.html deleted file mode 100644 index caf05cf..0000000 --- a/content/sesion09/index.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - Sesión 09 | Python Study Group | Fundamentals - - - - - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/content/sesion10/Readme.md b/content/sesion10/Readme.md deleted file mode 100644 index 95aa642..0000000 --- a/content/sesion10/Readme.md +++ /dev/null @@ -1,1173 +0,0 @@ - -![Python La paz](../Logo.png) - -
-
-
- -### Sesión 10 -### Estructura de datos -### Conjuntos - ---- -##### Estructura de datos - -Una estructura de datos es una forma de organizar y almacenar datos - -De manera eficiente para su uso y manipulación - -Las más comunes son tuplas, listas, conjuntos y diccionarios - ---- -| Estructura | Características | Ejemplo | -| ------------------ | --------------------------------- | --------------------- | -| Tupla | Inmutable, ordenada, indexada | (1,2,3) | -| Lista | Mutable, ordenada, indexada | [1,2,3] | -| Conjunto | Mutable, no ordenado, no indexado | {1,2,3} | -| Diccionario | Mutable, ordenado, indexado | {'a':1, 'b':2, 'c':3} | - ---- -¿Qué es un conjunto? - -Un conjunto es una estructura de datos, al igual que una lista o una tupla - -Al igual que las listas almacena objetos o items que puede ser de a cualquier tipo - ---- -Se llaman conjuntos porque en matemáticas un conjunto es una colección de elementos únicos sin orden definido - -Python adopta la misma definición de conjunto de matemáticas - ---- - -Un conjunto es una secuencia de objetos **MUTABLES** - -- **NO ordenados** -- **NO indexados** -- **NO duplicados** - ---- - -**Mutable**: Los elementos de un conjunto pueden ser modificados después de su creación - -```python [1-2|3-4] -conjunto = {'🍕','🍔','🍟','🌭'} -print(conjunto) # {'🍔', '🌭', '🍕', '🍟'} -conjunto.add('🥗') -print(conjunto) # {'🍔', '🍕', '🥗', '🍟', '🌭'} -``` - ---- -**NO ordenados**: Los elementos de un conjunto no tienen un orden especifico - -```python -conjunto = {'🍕','🍔','🍟','🌭'} -print(conjunto) # {'🍔', '🌭', '🍕', '🍟'} -``` - ---- -**NO indexados**: Los elementos de un conjunto no pueden ser accedidos por un índice - -```python -conjunto = {'🍕','🍔','🍟','🌭'} -print(conjunto[0]) # TypeError: 'set' object is not subscriptable -``` - ---- -**NO duplicados**: Los elementos de un conjunto no pueden ser duplicados - -```python -conjunto = {'🍕','🍔','🍟','🌭','🍕','🍟'} -print(conjunto) # {'🍕', '🍟', '🌭', '🍔'} -``` - ---- -##### Usos de los conjuntos - -- Análisis de texto eliminando palabras repetidas -- Gestión de inventarios -- Control de usuarios -- Control de permisos - ---- -##### ¿Cómo declarar un conjunto? - -En python se declara un conjunto utilizando llaves `{}` y separando los elementos con comas `,` - -```python -mi_conjunto = {elemento1, elemento2, elemento3, ...} -``` - -- mi_conjunto: Es el nombre del conjunto -- elemento1, elemento2, elemento3: Son los elementos del conjunto - ---- -También se puede declarar un conjunto utilizando la función `set()` - -Y declarar conjuntos utilizando conjuntos por comprensión - ---- -Crearemos un archivo con el nombre sesion10.py y empezaremos a crear conjuntos - ---- -Conjunto de enteros - -```python -print ("Conjunto de enteros") -conjunto = {1, 2, 3, 4, 5} -print(conjunto) -print(type(conjunto)) -``` - -![Conjunto de Enteros](./img/01.png) - ---- -Conjunto de cadenas - -```python -print ("Conjunto de cadenas") -conjunto = {'🍕','🍔','🍟','🌭'} -print(conjunto) -print(type(conjunto)) -``` - -![Conjunto de Cadenas](./img/02.png) - ---- -Conjunto mixto - -```python -print ("Conjunto mixto") -conjunto = {1, True, 3.14, '☕'} -print(conjunto) -print(type(conjunto)) -``` - -![Conjunto Mixto](./img/03.png) - ---- -Se utiliza la función `set()` para crear conjuntos vacíos o a partir de una secuencia - -Permite convertir secuencias como listas, tuplas, cadenas en conjuntos - ---- -Conjunto vacío - -```python -print ("Conjunto vacío") -conjunto = set() -print(conjunto) -print(type(conjunto)) -``` - -![Conjunto Vacío](./img/04.png) - ---- -Conjunto a partir de la cadena - -```python -print ("Conjunto a partir de la cadena") -cadena = 'Hola Mundo' -conjunto = set(cadena) -print(conjunto) -print(type(conjunto)) -``` - -![Conjunto a partir de la cadena](./img/05.png) - ---- -Conjunto a partir de una tupla - -```python -print ("Conjunto a partir de una tupla") -tupla = (1, 2, 3, 4, 5, 5) -conjunto = set(tupla) -print(conjunto) -print(type(conjunto)) -``` - -![Conjunto a partir de una tupla](./img/06.png) - ---- -Conjunto a partir de una lista -```python -print ("Conjunto a partir de una lista") -lista = [True, False, 0, 1] -conjunto = set(lista) -print(conjunto) -print(type(conjunto)) -``` - -![Conjunto a partir de una lista](./img/07.png) - ---- -Conjunto por comprensión - -```python -print ("Conjunto por comprensión") -conjunto = {x for x in '🍕🍔🍟🍕🍔🍟🍔🍟'} -print(conjunto) -print(type(conjunto)) -``` - -![Conjunto por comprensión](./img/08.png) - ---- -##### Indexación y Slicing - -Los conjuntos no soportan indexación ni slicing - -Porque no son ordenados ni indexados - -```python -conjunto = {1, 2, 3, 4, 5} -print(conjunto[0]) # TypeError: 'set' object is not subscriptable -``` - -```python -conjunto = {1, 2, 3, 4, 5} -print(conjunto[0:3]) # TypeError: 'set' object is not subscriptable -``` - ---- -##### Concatenación de conjuntos - -Los conjuntos no soportan la concatenación con el operador `+` - -```python -conjunto1 = {1, 2, 3} -conjunto2 = {4, 5, 6} -print(conjunto1 + conjunto2) -# TypeError: unsupported operand type(s) for +: 'set' and 'set' -``` - -##### Repetición con conjuntos - -Los conjuntos no soportan la repetición con el operador `*` - -```python -conjunto = {1, 2, 3} -print(conjunto * 3) -# TypeError: unsupported operand type(s) for *: 'set' and 'int' -``` - ---- -##### Métodos de los conjuntos - -Los conjuntos soportan métodos como: - -- Métodos de adición -- Métodos de eliminación -- Métodos de operaciones con conjuntos -- Métodos de asignación con operaciones -- Métodos de búsqueda -- Métodos de copia - ---- -Se utiliza la notación de punto `.` - -`conjunto.metodo()` - -`conjunto.metodo(valor)` - ---- -##### Métodos de adición - -Los métodos de adición permiten agregar elementos a un conjunto - -- `add()` -- `update()` - -No retorna ningún valor - ---- -`add(valor)` recibe un valor y lo agrega al conjunto si no existe - -```python [1-3|4-5] -print ("Método add()") -conjunto = {'🍕','🍔','🍟','🌭'} -print (conjunto) -conjunto.add('🥗') -print(conjunto) -``` - -![Método add()](./img/09.png) - ---- -`update(valores)` recibe una secuencia de valores y los agrega al conjunto si no existen - -```python [1-3|4-5|6-7|8-9|10-11] -print ("Método update()") -conjunto = {'🍕','🍔','🍟','🌭'} -print (conjunto) -conjunto.update(['🥤','🍦']) -print(conjunto) -conjunto.update('🍩🍪') -print(conjunto) -conjunto.update(('🍫','🍬')) -print(conjunto) -conjunto.update({'🍭','🍮'}) -print(conjunto) -``` - -![Método update()](./img/10.png) - ---- -##### Métodos de eliminación - -Los métodos de eliminación permiten eliminar elementos de un conjunto - -- `remove()` -- `discard()` -- `pop()` -- `clear()` - -Solo `pop()` retorna el elemento eliminado - ---- -`remove(valor)` recibe un valor y lo elimina del conjunto si existe, si no existe lanza un error - -```python [1-3|4-5|6-8] -print ("Método remove()") -conjunto = {'🍕','🍔','🍟','🌭'} -print (conjunto) -conjunto.remove('🍔') -print(conjunto) -# conjunto.remove('🍔') -# print(conjunto) -# Key Error: '🍔' -``` - -![Método remove()](./img/11.png) - ---- -`discard(valor)` recibe un valor y lo elimina del conjunto si existe, si no existe no lanza un error - -```python [1-3|4-5|6-7] -print ("Método discard()") -conjunto = {'🍕','🍔','🍟','🌭'} -print (conjunto) -conjunto.discard('🍔') -print(conjunto) -conjunto.discard('🍔') -print(conjunto) -``` - -![Método discard()](./img/12.png) - ---- -`pop()` elimina un elemento **aleatorio** del conjunto y lo retorna - -```python [1-3|4-5|6-7] -print ("Método pop()") -conjunto = {'🍕','🍔','🍟','🌭', '🥤','🍦'} -print (conjunto) -print(conjunto.pop()) -print(conjunto) -print(conjunto.pop()) -print(conjunto) -``` - -![Método pop()](./img/13.png) - ---- -`clear()` elimina todos los elementos del conjunto - -```python [1-3|4-5] -print ("Método clear()") -conjunto = {'🍕','🍔','🍟','🌭'} -print (conjunto) -conjunto.clear() -print(conjunto) -``` - -![Método clear()](./img/14.png) - ---- -##### Métodos de operaciones con conjuntos - -- `union()` : Unión de conjuntos -- `intersection()` : Intersección de conjuntos -- `difference()` : Diferencia de conjuntos -- `symmetric_difference()` : Diferencia simétrica de conjuntos - -Retornan un nuevo conjunto con el resultado de la operación - ---- -`union(conjunto)` recibe un conjunto y retorna la unión de ambos - -Contiene todos los elementos de ambos sin repetir - -##### `$A \cup B = \{x | x \in A \lor x \in B\}$` - -```python [1-4|5-6] -print ("Método union()") -conjunto1 = {'🍔','🍟', '🥤'} -conjunto2 = {'🍕','🍨','🥤'} -print (conjunto1, conjunto2) -union = conjunto1.union(conjunto2) -print(union) -``` - -![Método union()](./img/15.png) - ---- -`intersection(conjunto)` recibe un conjunto y retorna la intersección de ambos - -Contiene los elementos que están en ambos conjuntos - -##### `$A \cap B = \{x | x \in A \land x \in B\}$` - -```python [1-4|5-6] -print ("Método intersection()") -conjunto1 = {'🍔','🍟', '🥤'} -conjunto2 = {'🍕','🍨','🥤'} -print (conjunto1, conjunto2) -interseccion = conjunto1.intersection(conjunto2) -print(interseccion) -``` - -![Método intersection()](./img/16.png) - ---- -`difference(conjunto)` recibe un conjunto y retorna la diferencia de ambos conjuntos - -Los que están en el 1er conjunto pero no en el 2do - -##### `$A - B = \{x | x \in A \land x \notin B\}$` - -```python [1-4|5-6|7-8] -print ("Método difference()") -conjunto1 = {'🍔','🍟', '🥤'} -conjunto2 = {'🍕','🍨','🥤'} -print ("1:",conjunto1, "2:",conjunto2) -diferencia = conjunto1.difference(conjunto2) -print("1 y 2:",diferencia) -diferencia = conjunto2.difference(conjunto1) -print("2 y 1:",diferencia) -``` - -![Método difference()](./img/17.png) - ---- -`symmetric_difference(conjunto)` recibe un conjunto y retorna la diferencia simétrica de ambos - -Contiene los elementos que están en un conjunto o en el otro pero no en ambos - -##### `$A\bigtriangleup B=\{x | x \in A \land x \notin B \lor x \in B \land x \notin A\}$` - -```python [1-4|5-6] -print ("Método symmetric_difference()") -conjunto1 = {'🍔','🍟', '🥤'} -conjunto2 = {'🍕','🍨','🥤'} -print (conjunto1, conjunto2) -diferencia_simetrica = conjunto1.symmetric_difference(conjunto2) -print(diferencia_simetrica) -``` - -![Método symmetric_difference()](./img/18.png) - ---- -##### Métodos de asignación con operaciones - -Permiten realizar operaciones con conjuntos y asignar el resultado al conjunto inicial - -- `intersection_update()` : Intersección -- `difference_update()` : Diferencia -- `symmetric_difference_update()` : Diferencia simétrica - ---- -`intersection_update(conjunto)` recibe un conjunto y asigna al conjunto inicial la intersección de ambos conjuntos - -```python [1-4|5-6] -print ("Método intersection_update()") -conjunto1 = {'🍔','🍟', '🥤'} -conjunto2 = {'🍕','🍨','🥤'} -print (conjunto1, conjunto2) -conjunto1.intersection_update(conjunto2) -print(conjunto1) -``` - -![Método intersection_update()](./img/19.png) - ---- -`difference_update(conjunto)` recibe un conjunto y asigna al conjunto inicial la diferencia de ambos conjuntos - -```python [1-4|5-6] -print ("Método difference_update()") -conjunto1 = {'🍔','🍟', '🥤'} -conjunto2 = {'🍕','🍨','🥤'} -print ("1:",conjunto1, "2:",conjunto2) -conjunto1.difference_update(conjunto2) -print ("1:",conjunto1, "2:",conjunto2) -``` - -![Método difference_update()](./img/20.png) - ---- -`symmetric_difference_update(conjunto)` recibe un conjunto y asigna al conjunto inicial la diferencia simétrica de ambos conjuntos - -```python [1-4|5-6] -print ("Método symmetric_difference_update()") -conjunto1 = {'🍔','🍟', '🥤'} -conjunto2 = {'🍕','🍨','🥤'} -print (conjunto1, conjunto2) -conjunto1.symmetric_difference_update(conjunto2) -print(conjunto1) -``` - -![Método symmetric_difference_update()](./img/21.png) - ---- -##### Métodos de búsqueda - -Los métodos de búsqueda permiten buscar elementos en un conjunto - -- `issubset()` : Subconjunto -- `issuperset()` : Superconjunto -- `isdisjoint()` : Disjunto - -Retornan un valor booleano - ---- -`issubset(conjunto)` recibe una secuencia y retorna `True` si el conjunto es subconjunto del conjunto recibido - -```python [1-5|6-7|8-9] -print ("Método issubset()") -conjunto1 = {'🍔','🍟', '🥤'} -conjunto2 = {'🍕','🍨','🥤'} -conjunto3 = {'🍔','🍟'} -print (conjunto1, conjunto2,conjunto3) -# ¿El conjunto1 es subconjunto del conjunto2? -print(conjunto1.issubset(conjunto2)) -# ¿El conjunto3 es subconjunto del conjunto1? -print(conjunto3.issubset(conjunto1)) -``` - -![Método issubset()](./img/22.png) - ---- -`issuperset(conjunto)` recibe una secuencia y retorna `True` si el conjunto es superconjunto del conjunto recibido - -```python [1-5|6-7|8-9] -print ("Método issuperset()") -conjunto1 = {'🍔','🍟', '🥤'} -conjunto2 = {'🍕','🍨','🥤'} -conjunto3 = {'🍔','🍟'} -print (conjunto1, conjunto2,conjunto3) -# ¿El conjunto1 es superconjunto del conjunto2? -print(conjunto1.issuperset(conjunto2)) # C1 contiene a C2? -# ¿El conjunto1 es superconjunto del conjunto2? -print(conjunto1.issuperset(conjunto3)) # C1 contiene a C3? -``` - -![Método issuperset()](./img/23.png) - ---- -`isdisjoint(conjunto)` recibe un secuencia y retorna `True` si el conjunto no tiene elementos en común con el conjunto recibido - -```python [1-5|6-7|8-9] -print ("Método isdisjoint()") -conjunto1 = {'🍔','🍟', '🥤'} -conjunto2 = {'🍕','🍨'} -conjunto3 = {'🍔','🍟'} -print (conjunto1, conjunto2,conjunto3) -# ¿El conjunto1 no tiene elementos en común con el conjunto2? -print(conjunto1.isdisjoint(conjunto2)) -# ¿El conjunto1 no tiene elementos en común con el conjunto3? -print(conjunto1.isdisjoint(conjunto3)) -``` - -![Método isdisjoint()](./img/24.png) - ---- -##### Métodos de copia - -Los métodos de copia permiten copiar un conjunto - -- `copy()` - -Retorna un nuevo conjunto con los mismos elementos - ---- -Cuando se asigna un conjunto a una variable se asigna por referencia - -NO se crea una copia del conjunto sino una referencia al conjunto original - -```python [1-3|4-5] -print ("Asignación por referencia") -conjunto = {'🍕','🍔','🍟','🌭'} -print (conjunto) -copia = conjunto -copia.add('🥗') -print(conjunto) -print(copia) -``` - -![Asignación por referencia](./img/25.png) - ---- -Para crear una copia de un conjunto se utiliza el método `copy()` - -```python [1-3|4-5] -print ("Método copy()") -conjunto = {'🍕','🍔','🍟','🌭'} -print (conjunto) -copia = conjunto.copy() -copia.add('🥗') -print(conjunto) -print(copia) -``` - -![Método copy()](./img/26.png) - ---- -##### Funciones con conjuntos - -Los conjuntos interactúan con funciones propias de python que permiten secuencias - -- `len()` -- `max()` -- `min()` -- `sum()` - -Existen otras funciones pueden encontrarse en la [documentación](https://docs.python.org/3/library/stdtypes.html#set) y [funciones incorporadas](https://python-reference.readthedocs.io/en/latest/docs/sets/#functions) - ---- -`len(conjunto)` retorna la cantidad de elementos del conjunto - -```python -print ("Función len()") -conjunto = {'🍕','🍔','🍟','🌭'} -print (conjunto) -print(len(conjunto)) -``` - -![Función len()](./img/27.png) - ---- -`max(conjunto)` retorna el elemento mayor del conjunto - -Si el conjunto contiene cadenas retorna el elemento mayor en orden lexicográfico - -Si el conjunto contiene números retorna el valor mayor - ---- -`max(conjunto)` - -```python [1-4|5-7] -print ("Función max()") -conjunto = {1, 2, 3, 4, 5} -print (conjunto) -print (max(conjunto)) -conjunto = {'🍕','🍔','🍟','🌭'} -print (conjunto) -print(max(conjunto)) -``` - -![Función max()](./img/28.png) - ---- -`min(conjunto)` retorna el elemento menor del conjunto - -Si el conjunto contiene cadenas retorna el elemento menor en orden lexicográfico - -Si el conjunto contiene números retorna el valor menor - ---- -`min(conjunto)` - -```python [1-4|5-7] -print ("Función min()") -conjunto = {1, 2, 3, 4, 5} -print (conjunto) -print (min(conjunto)) -conjunto = {'🍨','🍔','🍟','🍕'} -print (conjunto) -print(min(conjunto)) -``` - -![Función min()](./img/29.png) - ---- -`sum(conjunto)` retorna la suma de los elementos del conjunto - -Solo si el conjunto contiene números - -```python [1-3|4] -print ("Función sum()") -conjunto = {1, 2, 3, 4, 5} -print (conjunto) -print (sum(conjunto)) -``` - -![Función sum()](./img/30.png) - ---- -##### Operadores con conjuntos - -Los conjuntos soportan operadores que permiten realizar operaciones - -- Operadores de adición -- Operadores de comparación -- Operadores para operaciones con conjuntos -- Operadores para asignación con operaciones - ---- -##### Operadores de adición - -Los operadores de adición permiten agregar elementos a un conjunto - -Similar al método `add()` - -- `|=` : Update - ---- -`|=` recibe un conjunto y agrega al conjunto inicial los elementos del conjunto recibido - -```python [1-3|4-6] -print ("Operador |=") -conjunto1 = {'🍔','🍟', '🥤'} -conjunto2 = {'🍕','🍨'} -print (conjunto1, conjunto2) -conjunto1 |= conjunto2 -print(conjunto1) -``` - -![Operador |=](./img/31.png) - ---- -##### Operadores de comparación - -Los operadores de comparación permiten comparar conjuntos - -- `==` : Igualdad -- `!=` : Desigualdad -- `<` : Es subconjunto y no igual -- `>` : Es superconjunto y no igual -- `<=` : Es subconjunto o igual -- `>=` : Es superconjunto o igual - ---- -`==` compara si dos conjuntos son iguales - -```python [1-5|6|7] -print ("Operador ==") -conjunto1 = {'🍔','🍟', '🥤'} -conjunto2 = {'🍔','🍟', '🥤'} -conjunto3 = {'🍕','🍨'} -print (conjunto1, conjunto2, conjunto3) -print(conjunto1 == conjunto2) -print(conjunto1 == conjunto3) -``` - -![Operador ==](./img/32.png) - ---- -`!=` compara si dos conjuntos son diferentes - -```python [1-5|6|7] -print ("Operador !=") -conjunto1 = {'🍔','🍟', '🥤'} -conjunto2 = {'🍔','🍟', '🥤'} -conjunto3 = {'🍕','🍨'} -print (conjunto1, conjunto2, conjunto3) -print(conjunto1 != conjunto2) -print(conjunto1 != conjunto3) -``` - -![Operador !=](./img/33.png) - ---- -`<` compara si un conjunto es subconjunto y no igual a otro - -```python [1-5|6|7] -print ("Operador <") -conjunto1 = {'🍔','🍟'} -conjunto2 = {'🍔','🍟', '🥤'} -conjunto3 = {'🍕','🍨'} -print (conjunto1, conjunto2, conjunto3) -print(conjunto1 < conjunto2) -print(conjunto1 < conjunto3) -``` - -![Operador <](./img/34.png) - ---- -`>` compara si un conjunto es superconjunto y no igual a otro - -```python [1-5|6|7] -print ("Operador >") -conjunto1 = {'🍔','🍟','🥤','🍕'} -conjunto2 = {'🍔','🍟', '🥤'} -conjunto3 = {'🍕','🍨'} -print (conjunto1, conjunto2, conjunto3) -print(conjunto1 > conjunto2) -print(conjunto1 > conjunto3) -``` - -![Operador >](./img/35.png) - ---- -`<=` compara si un conjunto es subconjunto o igual a otro - -```python [1-5|6|7] -print ("Operador <=") -conjunto1 = {'🍔','🍟'} -conjunto2 = {'🍔','🍟'} -conjunto3 = {'🍕','🍨'} -print (conjunto1, conjunto2, conjunto3) -print(conjunto1 <= conjunto2) -print(conjunto1 <= conjunto3) -``` - -![Operador <=](./img/36.png) - ---- -`>=` compara si un conjunto es superconjunto o igual a otro - -```python [1-5|6|7] -print ("Operador >=") -conjunto1 = {'🍔','🍟'} -conjunto2 = {'🍔','🍟'} -conjunto3 = {'🍕','🍨'} -print (conjunto1, conjunto2, conjunto3) -print(conjunto1 >= conjunto2) -print(conjunto1 >= conjunto3) -``` - -![Operador >=](./img/37.png) - ---- -##### Operadores para operaciones con conjuntos - -Los operadores para operaciones con conjuntos permiten realizar operaciones con conjuntos - -- `|` : Unión -- `&` : Intersección -- `-` : Diferencia -- `^` : Diferencia simétrica - ---- -`|` retorna la unión de dos conjuntos - -```python [1-4|5-6] -print ("Operador |") -conjunto1 = {'🍔','🍟', '🥤'} -conjunto2 = {'🍕','🍨','🥤'} -print (conjunto1, conjunto2) -union = conjunto1 | conjunto2 -print(union) -``` - -![Operador |](./img/38.png) - ---- -`&` retorna la intersección de dos conjuntos - -```python [1-4|5-6] -print ("Operador &") -conjunto1 = {'🍔','🍟', '🥤'} -conjunto2 = {'🍕','🍨','🥤'} -print (conjunto1, conjunto2) -interseccion = conjunto1 & conjunto2 -print(interseccion) -``` - -![Operador &](./img/39.png) - ---- -`-` retorna la diferencia de dos conjuntos - -```python [1-4|5-6|7-8] -print ("Operador -") -conjunto1 = {'🍔','🍟', '🥤'} -conjunto2 = {'🍕','🍨','🥤'} -print ("1:",conjunto1, "2:",conjunto2) -diferencia = conjunto1 - conjunto2 -print("1 - 2:",diferencia) -diferencia = conjunto2 - conjunto1 -print("2 - 1:",diferencia) -``` - -![Operador -](./img/40.png) - ---- -`^` retorna la diferencia simétrica de dos conjuntos - -```python [1-4|5-6] -print ("Operador ^") -conjunto1 = {'🍔','🍟', '🥤'} -conjunto2 = {'🍕','🍨','🥤'} -print (conjunto1, conjunto2) -diferencia_simetrica = conjunto1 ^ conjunto2 -print(diferencia_simetrica) -``` - -![Operador ^](./img/41.png) - ---- - -##### Operadores para asignación con operaciones - -Los operadores para asignación con operaciones permiten realizar operaciones con conjuntos y asignar el resultado al conjunto inicial - -- `|=` : Unión -- `&=` : Intersección -- `-=` : Diferencia -- `^=` : Diferencia simétrica - ---- -`|=` recibe un conjunto y agrega al conjunto inicial los elementos del conjunto recibido - -```python [1-3|4-6] -print ("Operador |= Unión") -conjunto1 = {'🍔','🍟', '🥤'} -conjunto2 = {'🍕','🍨','🥤'} -print (conjunto1, conjunto2) -conjunto1 |= conjunto2 -print(conjunto1) -``` - -![Operador |= Unión](./img/42.png) - ---- -`&=` recibe un conjunto y asigna al conjunto inicial la intersección de ambos conjuntos - -```python [1-3|4-6] -print ("Operador &= Intersección") -conjunto1 = {'🍔','🍟', '🥤'} -conjunto2 = {'🍕','🍨','🥤'} -print (conjunto1, conjunto2) -conjunto1 &= conjunto2 -print(conjunto1) -``` - -![Operador &= Intersección](./img/43.png) - ---- -`-=` recibe un conjunto y asigna al conjunto inicial la diferencia de ambos conjuntos - -```python [1-4|5-7|8-9] -print ("Operador -= Diferencia") -conjunto1 = {'🍔','🍟', '🥤'} -conjunto2 = {'🍕','🍨','🥤'} -print ("1:",conjunto1, "2:",conjunto2) -conjunto1 -= conjunto2 -print("1 - 2:",conjunto1) -conjunto1 = {'🍔','🍟', '🥤'} -conjunto2 -= conjunto1 -print("2 - 1:",conjunto2) -``` - -![Operador -= Diferencia](./img/44.png) - ---- -`^=` recibe un conjunto y asigna al conjunto inicial la diferencia simétrica de ambos conjuntos - -```python [1-3|4-6] -print ("Operador ^= Diferencia simétrica") -conjunto1 = {'🍔','🍟', '🥤'} -conjunto2 = {'🍕','🍨','🥤'} -print (conjunto1, conjunto2) -conjunto1 ^= conjunto2 -print(conjunto1) -``` - -![Operador ^= Diferencia simétrica](./img/45.png) - ---- -##### Conjuntos inmutables - -Los conjuntos inmutables son conjuntos que no pueden ser modificados después de su creación - -En python se declaran utilizando la función `frozenset()` - -```python -conjunto = frozenset({'🍔','🍕','🥗','🍟','🌭'}) -print(conjunto) -print(type(conjunto)) -``` - -![Conjunto Inmutable](./img/46.png) - ---- -Poseen los mismos métodos que los conjuntos mutables pero no poseen los métodos de adición, eliminación y asignaciones con operaciones - -```python -conjunto = frozenset({1, 2, 3, 4, 5}) -print(conjunto) -print(conjunto.add(6)) # AttributeError: 'frozenset' object has no attribute 'add' -print(conjunto.remove(1)) # AttributeError: 'frozenset' object has no attribute 'remove' -print(conjunto |= {6}) # SyntaxError: invalid syntax -``` - ---- -##### Conjuntos anidados - -Los conjuntos anidados son conjuntos que contienen otros conjuntos pero tienen que ser inmutables para ser anidados - - -```python -print ("Conjunto de conjuntos") -conjunto = {frozenset({'🍅','🍓','🍎'}), frozenset({'🍈','🍐','🍏'})} -print(conjunto) -print(type(conjunto)) -``` - -![Conjunto Anidado](./img/47.png) - ---- -Si se intenta anidar un conjunto mutable se lanza un error - -```python -print ("Conjunto de conjuntos") -conjunto = {{'🍅','🍓','🍎'}, {'🍈','🍐','🍏'}} #TypeError: unhashable type: 'set' -print(conjunto) -print(type(conjunto)) -``` - ---- -##### Commit - -Commit de la sesión a nuestro repositorio - -```bash -git add . -git commit -m "Clase sesión 10" -git push -``` - ---- -##### Resumen Conjuntos - -- Los conjuntos son colecciones desordenadas de elementos únicos -- Se declaran utilizando llaves `{}` y separando con comas `,` -- Se utiliza la función `set()` para crear conjuntos vacíos o a partir de una secuencia -- Se utiliza la función `frozenset()` para crear conjuntos inmutables - ---- -- Los conjuntos inmutables no se pueden modificar después de su creación -- Los conjuntos no soportan indexación ni slicing -- Los conjuntos no soportan la concatenación con el operador `+` ni la repetición con el operador `*` - ---- -- Los conjuntos soportan métodos de adición, eliminación - - `add()`, `update()` - - `remove()`, `discard()`, `pop()`, `clear()` -- Los conjuntos soportan métodos de operaciones con conjuntos - - `union()`, `intersection()`, `difference()`, `symmetric_difference()` - ---- -- Los conjuntos soportan métodos de asignación con operaciones - - `intersection_update()`, `difference_update()`, `symmetric_difference_update()` - ---- -- Los conjuntos soportan métodos de búsqueda - - `issubset()`, `issuperset()`, `isdisjoint()` -- Los conjuntos soportan métodos de copia - - `copy()` ---- - -- Los conjuntos soportan operadores - - Comparación: `==`, `!=`, `<`, `>`, `<=`, `>=` - - Operaciones: `|`, `&`, `-`, `^` - - Asignación: `|=`, `&=`, `-=`, `^=` - ---- -- Se pueden anidar conjuntos pero deben ser inmutables - ---- -##### Retos - -Crear una carpeta con el nombre "retos_sesion_10" en la cual por cada ejercicio debe crear un script de python - -```bash -# Ejemplo carpeta -psg-example/ - retos_sesion_10/ - ejercicio_01.py - ejercicio_02.py - ejercicio_03.py - ejercicio_04.py - sesion10.ipynb -``` - -Subir la carpeta a su repositorio en GitHub cuando termine los retos - ---- -1. Elimina los elementos de oficina repetidos de la cadena - -```python -📎📐📏✏️🖊️🖋️📎📌📏📇🗂️📁📌🗃️✏️📂🖇️ -``` - ---- -2. El dueño de una tienda de ropa deportiva ha comprado ropa formal y quiere abrir una nueva tienda que combine ambos estilos. -Crea un conjunto con las prendas de ambos tipos con las listas de prendas - -```python -["Short", "Playera", "Sudadera", "Tenis", "Short", "Calcetines"] -["Saco", "Corbata", "Pantalón de vestir", "Zapatos", "Calcetines"] -``` - ---- -3. Tienes dos listas: clientes que compraron en la tienda física y clientes que compraron online. - - -```python -tienda_fisica = ["Ana", "Luis", "Pedro", "María", "Juan"] -tienda_online = ["Pedro", "María", "Ana", "Carlos", "Laura"] -``` - -```markdown -a. Quiénes compraron en ambos canales. -b. Quiénes compraron solo en la tienda física. -c. Quiénes compraron solo online. -``` - ---- -4. Jane y Jhon llevan saliendo juntos por 4 semanas, cada vez que salen van a comer a un candy bar. Quieren saber que tan compatibles son viendo cuantos platos de comida tienen en común. A continuación tienes los postres que han ido pidiendo en cada salida: - -```text -Jane: Lemon Pie, Brownie, Tarta de Manzana, - Helado de Chocolate, Flan -Jhon: Carrot Cake, Croissant de Chocolate, - Lemon Pie, Tarta de Manzana, Pudding -``` - -```markdown -Si la cantidad de postres que tienen en común es mayor al 50% -entonces son compatibles, -de lo contrario quieren replantear su relación -``` - - ---- -5. Convertir y ejecutar el archivo de la "sesion10.py" a un archivo en jupyter notebook - ---- - - -
-
-
-
-
- -[![GitHub](../../content/github_logo.png) ](https://github.com/python-la-paz/python-study-group-fundamentals/tree/main/content/sesion10) - -Repositorio de la Sesión - ---- - -## Bibliografía y Referencias - -- [Sets](https://docs.python.org/3/tutorial/datastructures.html#sets) -- [Conjuntos Sets](https://recursospython.com/guias-y-manuales/conjuntos-sets/) -- [Sets](https://python-reference.readthedocs.io/en/latest/docs/sets/) -- [Stdtypes Sets](https://docs.python.org/3/library/stdtypes.html#set) -- [Sets Álgebra](https://asignatura.us.es/algbas/sets/) -- [Funciones Set](https://python-reference.readthedocs.io/en/latest/docs/sets/#functions) -- [Operadores Set](https://python-reference.readthedocs.io/en/latest/docs/sets/#relational-operators) -- [Frozenset](https://docs.python.org/3/library/stdtypes.html#frozenset) \ No newline at end of file diff --git a/content/sesion10/img/01.png b/content/sesion10/img/01.png deleted file mode 100644 index 7b9170b..0000000 Binary files a/content/sesion10/img/01.png and /dev/null differ diff --git a/content/sesion10/img/02.png b/content/sesion10/img/02.png deleted file mode 100644 index 5c4cef8..0000000 Binary files a/content/sesion10/img/02.png and /dev/null differ diff --git a/content/sesion10/img/03.png b/content/sesion10/img/03.png deleted file mode 100644 index 48ff46d..0000000 Binary files a/content/sesion10/img/03.png and /dev/null differ diff --git a/content/sesion10/img/04.png b/content/sesion10/img/04.png deleted file mode 100644 index 6615267..0000000 Binary files a/content/sesion10/img/04.png and /dev/null differ diff --git a/content/sesion10/img/05.png b/content/sesion10/img/05.png deleted file mode 100644 index 62794e2..0000000 Binary files a/content/sesion10/img/05.png and /dev/null differ diff --git a/content/sesion10/img/06.png b/content/sesion10/img/06.png deleted file mode 100644 index 7a5903b..0000000 Binary files a/content/sesion10/img/06.png and /dev/null differ diff --git a/content/sesion10/img/07.png b/content/sesion10/img/07.png deleted file mode 100644 index d47d806..0000000 Binary files a/content/sesion10/img/07.png and /dev/null differ diff --git a/content/sesion10/img/08.png b/content/sesion10/img/08.png deleted file mode 100644 index 7483f64..0000000 Binary files a/content/sesion10/img/08.png and /dev/null differ diff --git a/content/sesion10/img/09.png b/content/sesion10/img/09.png deleted file mode 100644 index f567ce8..0000000 Binary files a/content/sesion10/img/09.png and /dev/null differ diff --git a/content/sesion10/img/10.png b/content/sesion10/img/10.png deleted file mode 100644 index 72cc4e9..0000000 Binary files a/content/sesion10/img/10.png and /dev/null differ diff --git a/content/sesion10/img/11.png b/content/sesion10/img/11.png deleted file mode 100644 index 5212307..0000000 Binary files a/content/sesion10/img/11.png and /dev/null differ diff --git a/content/sesion10/img/12.png b/content/sesion10/img/12.png deleted file mode 100644 index ecbe582..0000000 Binary files a/content/sesion10/img/12.png and /dev/null differ diff --git a/content/sesion10/img/13.png b/content/sesion10/img/13.png deleted file mode 100644 index 1ba1bde..0000000 Binary files a/content/sesion10/img/13.png and /dev/null differ diff --git a/content/sesion10/img/14.png b/content/sesion10/img/14.png deleted file mode 100644 index fca3e46..0000000 Binary files a/content/sesion10/img/14.png and /dev/null differ diff --git a/content/sesion10/img/15.png b/content/sesion10/img/15.png deleted file mode 100644 index d55b193..0000000 Binary files a/content/sesion10/img/15.png and /dev/null differ diff --git a/content/sesion10/img/16.png b/content/sesion10/img/16.png deleted file mode 100644 index 6afdfaa..0000000 Binary files a/content/sesion10/img/16.png and /dev/null differ diff --git a/content/sesion10/img/17.png b/content/sesion10/img/17.png deleted file mode 100644 index 0edc0e0..0000000 Binary files a/content/sesion10/img/17.png and /dev/null differ diff --git a/content/sesion10/img/18.png b/content/sesion10/img/18.png deleted file mode 100644 index ac53e54..0000000 Binary files a/content/sesion10/img/18.png and /dev/null differ diff --git a/content/sesion10/img/19.png b/content/sesion10/img/19.png deleted file mode 100644 index df2a914..0000000 Binary files a/content/sesion10/img/19.png and /dev/null differ diff --git a/content/sesion10/img/20.png b/content/sesion10/img/20.png deleted file mode 100644 index 1dc0937..0000000 Binary files a/content/sesion10/img/20.png and /dev/null differ diff --git a/content/sesion10/img/21.png b/content/sesion10/img/21.png deleted file mode 100644 index 229a958..0000000 Binary files a/content/sesion10/img/21.png and /dev/null differ diff --git a/content/sesion10/img/22.png b/content/sesion10/img/22.png deleted file mode 100644 index a039394..0000000 Binary files a/content/sesion10/img/22.png and /dev/null differ diff --git a/content/sesion10/img/23.png b/content/sesion10/img/23.png deleted file mode 100644 index 9d24271..0000000 Binary files a/content/sesion10/img/23.png and /dev/null differ diff --git a/content/sesion10/img/24.png b/content/sesion10/img/24.png deleted file mode 100644 index 5519bc2..0000000 Binary files a/content/sesion10/img/24.png and /dev/null differ diff --git a/content/sesion10/img/25.png b/content/sesion10/img/25.png deleted file mode 100644 index 501a2e5..0000000 Binary files a/content/sesion10/img/25.png and /dev/null differ diff --git a/content/sesion10/img/26.png b/content/sesion10/img/26.png deleted file mode 100644 index 9800576..0000000 Binary files a/content/sesion10/img/26.png and /dev/null differ diff --git a/content/sesion10/img/27.png b/content/sesion10/img/27.png deleted file mode 100644 index ab447f8..0000000 Binary files a/content/sesion10/img/27.png and /dev/null differ diff --git a/content/sesion10/img/28.png b/content/sesion10/img/28.png deleted file mode 100644 index a8a9822..0000000 Binary files a/content/sesion10/img/28.png and /dev/null differ diff --git a/content/sesion10/img/29.png b/content/sesion10/img/29.png deleted file mode 100644 index 19f5deb..0000000 Binary files a/content/sesion10/img/29.png and /dev/null differ diff --git a/content/sesion10/img/30.png b/content/sesion10/img/30.png deleted file mode 100644 index faf7d05..0000000 Binary files a/content/sesion10/img/30.png and /dev/null differ diff --git a/content/sesion10/img/31.png b/content/sesion10/img/31.png deleted file mode 100644 index 4a3712a..0000000 Binary files a/content/sesion10/img/31.png and /dev/null differ diff --git a/content/sesion10/img/32.png b/content/sesion10/img/32.png deleted file mode 100644 index 50157ff..0000000 Binary files a/content/sesion10/img/32.png and /dev/null differ diff --git a/content/sesion10/img/33.png b/content/sesion10/img/33.png deleted file mode 100644 index 7607742..0000000 Binary files a/content/sesion10/img/33.png and /dev/null differ diff --git a/content/sesion10/img/34.png b/content/sesion10/img/34.png deleted file mode 100644 index 64d73da..0000000 Binary files a/content/sesion10/img/34.png and /dev/null differ diff --git a/content/sesion10/img/35.png b/content/sesion10/img/35.png deleted file mode 100644 index 1c6da64..0000000 Binary files a/content/sesion10/img/35.png and /dev/null differ diff --git a/content/sesion10/img/36.png b/content/sesion10/img/36.png deleted file mode 100644 index 295577f..0000000 Binary files a/content/sesion10/img/36.png and /dev/null differ diff --git a/content/sesion10/img/37.png b/content/sesion10/img/37.png deleted file mode 100644 index b04739d..0000000 Binary files a/content/sesion10/img/37.png and /dev/null differ diff --git a/content/sesion10/img/38.png b/content/sesion10/img/38.png deleted file mode 100644 index bbd0215..0000000 Binary files a/content/sesion10/img/38.png and /dev/null differ diff --git a/content/sesion10/img/39.png b/content/sesion10/img/39.png deleted file mode 100644 index e53d655..0000000 Binary files a/content/sesion10/img/39.png and /dev/null differ diff --git a/content/sesion10/img/40.png b/content/sesion10/img/40.png deleted file mode 100644 index 210bc36..0000000 Binary files a/content/sesion10/img/40.png and /dev/null differ diff --git a/content/sesion10/img/41.png b/content/sesion10/img/41.png deleted file mode 100644 index de5747b..0000000 Binary files a/content/sesion10/img/41.png and /dev/null differ diff --git a/content/sesion10/img/42.png b/content/sesion10/img/42.png deleted file mode 100644 index 902b911..0000000 Binary files a/content/sesion10/img/42.png and /dev/null differ diff --git a/content/sesion10/img/43.png b/content/sesion10/img/43.png deleted file mode 100644 index e1027a3..0000000 Binary files a/content/sesion10/img/43.png and /dev/null differ diff --git a/content/sesion10/img/44.png b/content/sesion10/img/44.png deleted file mode 100644 index 0d27118..0000000 Binary files a/content/sesion10/img/44.png and /dev/null differ diff --git a/content/sesion10/img/45.png b/content/sesion10/img/45.png deleted file mode 100644 index d223fde..0000000 Binary files a/content/sesion10/img/45.png and /dev/null differ diff --git a/content/sesion10/img/46.png b/content/sesion10/img/46.png deleted file mode 100644 index 8d1c121..0000000 Binary files a/content/sesion10/img/46.png and /dev/null differ diff --git a/content/sesion10/img/47.png b/content/sesion10/img/47.png deleted file mode 100644 index caafd07..0000000 Binary files a/content/sesion10/img/47.png and /dev/null differ diff --git a/content/sesion10/index.html b/content/sesion10/index.html deleted file mode 100644 index 086f1a1..0000000 --- a/content/sesion10/index.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - Sesión 10 | Python Study Group | Fundamentals - - - - - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/content/sesion11/Readme.md b/content/sesion11/Readme.md deleted file mode 100644 index 33c2e7d..0000000 --- a/content/sesion11/Readme.md +++ /dev/null @@ -1,808 +0,0 @@ - -![Python La paz](../Logo.png) - -
-
-
- -### Sesión 11 -### Estructura de datos -### Diccionarios - ---- -##### Estructura de datos - -Una estructura de datos es una forma de organizar y almacenar datos - -De manera eficiente para su uso y manipulación - -Las más comunes son tuplas, listas, conjuntos y diccionarios - ---- -| Estructura | Características | Ejemplo | -| ------------------ | --------------------------------- | --------------------- | -| Tupla | Inmutable, ordenada, indexada | (1,2,3) | -| Lista | Mutable, ordenada, indexada | [1,2,3] | -| Conjunto | Mutable, no ordenado, no indexado | {1,2,3} | -| Diccionario | Mutable, ordenado, indexado | {'a':1, 'b':2, 'c':3} | - ---- -¿Qué es un diccionario? - ---- -Es una estructura de datos que permite almacenar pares de elementos clave-valor - -Al igual que las listas y las tuplas, los diccionarios son colecciones de elementos - ---- -Se llaman diccionarios porque funcionan de manera similar a un diccionario de palabras - -- La palabra es la clave -- El significado es el valor - ---- - -Un diccionario es una secuencia de objetos **MUTABLES** - -- **Ordenado** -- **Indexado por claves** -- **Reescribe duplicados** - ---- - -**Mutable**: Los elementos de un diccionario pueden ser modificados después de su creación - -```python [1-2|3-4] -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -print(diccionario) # {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -diccionario['perro'] = '🐩' -print(diccionario) # {'perro': '🐩', 'gato': '🐱', 'ave': '🐦'} -``` - ---- -**Ordenados**: Los elementos de un diccionario mantienen el orden de inserción de los elementos - -```python [1-2|3-4] -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -print(diccionario) # {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -``` - ---- -**Indexado por claves**: Los elementos de un diccionario son indexados por claves - -```python -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -print(diccionario['perro']) # 🐶 -print(diccionario['gato']) # 🐱 -``` - ---- -**Reescribe duplicados**: Los diccionarios no permiten claves duplicadas se reescribe el valor de la clave - -```python -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦', 'perro': '🐩'} -print(diccionario) # {'perro': '🐩', 'gato': '🐱', 'ave': '🐦'} -``` - ---- -##### Usos de los diccionarios - -- Almacenar información estructurada -- Guardar configuraciones y traducciones -- Recuperar información de bases de datos -- Describir objetos - ---- -##### ¿Cómo declarar un diccionario? - -En python se declara utilizando llaves `{}` - -Separando los pares clave-valor con comas `,` - -Separando la clave del valor con dos puntos `:` - ---- -```python -mi_diccionario = {'clave1': 'valor1', - 'clave2': 'valor2', - 'clave3': 'valor3', ... } -``` - -- mi_diccionario: Es el nombre de la variable que almacena el diccionario -- clave1, clave2, clave3: Son las claves del diccionario -- valor1, valor2, valor3: Son los valores del diccionario -- `'clave1':'valor1'`: Son los pares clave-valor unidos por dos puntos `:` - ---- -También se puede declarar un diccionario utilizando la función `dict()` - -Y declarar diccionario utilizando diccionarios por comprensión - ---- -Crearemos un archivo con el nombre sesion11.py - -Empezaremos a crear diccionarios - ---- -Diccionario de clave entera y valor entero - -```python -print ("Diccionario de clave entera y valor entero") -diccionario = {1: 10, 2: 20, 3: 30} -print(diccionario) -print(type(diccionario)) -``` - -![Diccionario de Enteros](./img/01.png) - ---- -Diccionario de clave entero y valor cadena - -```python -print ("Diccionario de clave entero y valor cadena") -diccionario = {1: 'uno', 2: 'dos', 3: 'tres'} -print(diccionario) -print(type(diccionario)) -``` - -![Diccionario de Entero y Cadena](./img/02.png) - ---- -Diccionario de clave cadena y valor entero - -```python -print ("Diccionario de clave cadena y valor entero") -diccionario = {'uno': 1, 'dos': 2, 'tres': 3} -print(diccionario) -print(type(diccionario)) -``` - -![Diccionario de Cadena y Entero](./img/03.png) - ---- -Diccionario de clave cadena y valor cadena - -```python -print ("Diccionario de clave cadena y valor cadena") -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -print(diccionario) -print(type(diccionario)) -``` - -![Diccionario de Cadena y Cadena](./img/04.png) - ---- -Diccionario mixto - -```python -print ("Diccionario mixto") -diccionario = {1:"ID-XXXXX", "edad": 3, 'animal': '🐶' , ("John","Doe"): 6917222722, "salvaje": False} -print(diccionario) -print(type(diccionario)) -``` - -![Diccionario Mixto](./img/05.png) - -Las claves pueden ser de cualquier tipo de dato incluido tuplas y conjuntos inmutables - -No puede ser listas, conjuntos ni otros diccionarios - ---- -Se utiliza la función `dict()` para crear diccionarios vacíos o a partir de secuencias - -Permite convertir secuencias como listas, tuplas, conjuntos en diccionarios las secuencias deben tener pares clave-valor - ---- -Diccionario vacío, se declara con llaves `{}` o con la función `dict()` - -Es la razón por la que no se usa `{}` para crear un conjunto vacío - -Los diccionarios nacieron antes que los conjuntos - ---- -Para mantener la consistencia y claridad y coherencia - -Se mantuvo la sintaxis de los diccionarios vacíos con `{}` - ---- -```python [1-4|5-7] -print ("Diccionario vacío") -diccionario = {} -print(diccionario) -print(type(diccionario)) -diccionario = dict() -print(diccionario) -print(type(diccionario)) -``` - -![Diccionario Vacío](./img/06.png) - ---- -Diccionario a partir de una lista anidada - -Necesita que la lista tenga elementos pares - -```python -print ("Diccionario a partir de una lista") -lista = [['perro', '🐶'] , ['gato','🐱'] , ['ave','🐦']] -print(lista) -diccionario = dict(lista) -print(diccionario) -print(type(diccionario)) -``` - -![Diccionario a partir de una lista](./img/07.png) - ---- -Diccionario a partir de una tupla - -Necesita que la tupla tenga elementos pares - -```python -print ("Diccionario a partir de una tupla de tuplas") -tupla = (('perro', '🐶') , ('gatos','🐱') , ('ave',['🐦','🦅'])) -print(tupla) -diccionario = dict(tupla) -print(diccionario) -print(type(diccionario)) -``` - -![Diccionario a partir de una tupla](./img/08.png) - ---- -Diccionario mediante comprensión - -```python -print ("Diccionario mediante comprensión") -diccionario = {animal:animal*3 for animal in '🐶🐱🐹🐰'} -print(diccionario) -print(type(diccionario)) -``` - -![Diccionario mediante comprensión](./img/09.png) - ---- -##### Indexación y Slicing - -Los diccionarios poseen indexación por clave - -No se puede acceder a los elementos de un diccionario por posición - -Si se puede acceder a los elementos de un diccionario por clave - -No se puede realizar slicing en un diccionario - - ---- -Un diccionario es una colección de pares clave-valor - -![Diccionario](./img/10.png) - ---- -Accedemos a los elementos de un diccionario por clave - -```python -print ("Acceder mediante clave") -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -print(diccionario) -print(diccionario['perro'],type(diccionario['perro'])) -print(diccionario['gato'],type(diccionario['gato'])) -print(diccionario['ave'],type(diccionario['ave'])) -``` - -![Acceder mediante clave](./img/11.png) - ---- -El acceso no solo nos permite obtener el valor de la clave - -Sino que también nos permite modificar el valor de la clave - ---- -Cambiar el valor de un clave -```python -print ("Cambiar el valor de una clave") -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -print(diccionario) -diccionario['perro'] = '🐩' -print(diccionario) -``` - -![Cambiar el valor de una clave](./img/12.png) - ---- -Si la clave no existe, se crea un nuevo par clave-valor - -```python -print ("Crear un nuevo par clave-valor") -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -print(diccionario) -diccionario['pez'] = '🐠' -print(diccionario) -``` - -![Crear un nuevo par clave-valor](./img/13.png) - ---- -Para eliminar un par clave-valor se utiliza la palabra reservada `"del"` - -```python -print ("Eliminar un par clave-valor") -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -print(diccionario) -del diccionario['ave'] -print(diccionario) -``` - -![Eliminar un par clave-valor](./img/14.png) - ---- -No se puede modificar la clave son inmutables y únicas - -Se puede reasignar la clave creando un nuevo par clave-valor y eliminando el anterior - -```python -print ("Modificar la clave") -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -print(diccionario) -diccionario['perrito'] = diccionario['perro'] -del diccionario['perro'] -print(diccionario) -``` - -![Modificar la clave](./img/15.png) - ---- -##### Concatenación de diccionarios - -No se puede concatenar diccionarios con el operador `+` - -```python -print ("Concatenar diccionarios") -diccionario1 = {'perro': '🐶', 'gato': '🐱'} -diccionario2 = {'ave': '🐦', 'pez': '🐠'} -concatenado = diccionario1 + diccionario2 # TypeError: unsupported operand type(s) for +: 'dict' and 'dict' -``` - -##### Repetición de diccionarios - -No se puede repetir diccionarios con el operador `*+*` - -```python -print ("Repetir diccionarios") -diccionario = {'perro': '🐶', 'gato': '🐱'} -repetido = diccionario * 3 # TypeError: unsupported operand type(s) for *: 'dict' and 'int' -``` - ---- -##### Métodos de los diccionarios - -Los diccionarios poseen los siguientes métodos: - -- Métodos de acceso -- Métodos de adición -- Métodos de eliminación -- Métodos de copia - ---- -Se utiliza la notación de punto `.` - -`diccionario.metodo()` - -`diccionario.metodo(valor)` - ---- -##### Métodos de acceso - -Nos permiten obtener información del diccionario - -- `get()` -- `items()` -- `keys()` -- `values()` - ---- -`get(clave)`: Recibe una clave y retorna el valor del par clave-valor, si la clave no existe retorna `None` - -```python [1-3|4-5|6-7] -print ("Método get(clave)") -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -print (diccionario) -perro = diccionario.get('perro') -print(perro, type(perro)) -pez = diccionario.get('pez') -print(pez, type(pez)) -``` - -![Método get(clave)](./img/16.png) - ---- -`items()`: Retorna una lista de tuplas con los pares clave-valor, se puede iterar para obtener los pares clave-valor - -```python [1-3|4-5|6-8] -print ("Método items()") -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -print(diccionario) -items = diccionario.items() -print(items, type(items)) -items = list(items) # Convertir a lista -print(items, type(items)) -print(items[0], type(items[0])) -``` - -![Método items()](./img/17.png) - ---- -`keys()`: Retorna una lista con las claves del diccionario, se puede iterar para obtener las claves - -```python [1-3|4-5|6-8] -print ("Método keys()") -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -print(diccionario) -keys = diccionario.keys() -print(keys, type(keys)) -keys = list(keys) # Convertir a lista -print(keys, type(keys)) -print(keys[0], type(keys[0])) -``` - -![Método keys()](./img/18.png) - ---- -`values()`: Retorna una lista con los valores del diccionario, se puede iterar para obtener los valores - -```python [1-3|4-5|6-8] -print ("Método values()") -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -print(diccionario) -values = diccionario.values() -print(values, type(values)) -values = list(values) # Convertir a lista -print(values, type(values)) -print(values[0], type(values[0])) -``` - -![Método values()](./img/19.png) - ---- -##### Métodos de adición - -Nos permiten agregar elementos al diccionario - -- `update()` - ---- -`update(diccionario)`: Recibe un diccionario y agrega los pares clave-valor al diccionario, si la clave ya existe reescribe el valor - -```python [1-3|4-5] -print ("Método update(diccionario)") -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -print(diccionario) -diccionario.update({'pez': '🐠', 'perro': '🐩'}) -print(diccionario) -``` - -![Método update(diccionario)](./img/20.png) - ---- -`update(clave=valor)`: Recibe claves y valores, agrega el par clave-valor al diccionario, si la clave ya existe reescribe el valor - -```python [1-3|4-5] -print ("Método update(clave=valor)") -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -print(diccionario) -diccionario.update(pez='🐠', perro='🐩') -print(diccionario) -``` - -![Método update(clave=valor)](./img/21.png) - ---- -##### Métodos de eliminación - -Permiten eliminar elementos del diccionario - -- `clear()` -- `pop()` -- `popitem()` - ---- -`clear()`: Elimina todos los elementos del diccionario - -```python [1-3|4-5] -print ("Método clear()") -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -print(diccionario) -diccionario.clear() -print(diccionario) -``` - -![Método clear()](./img/22.png) - ---- -`pop(clave)`: Recibe una clave y elimina el par clave-valor del diccionario, retorna el valor de la clave - -```python [1-3|4-6] -print ("Método pop(clave)") -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -print(diccionario) -gato = diccionario.pop('gato') -print(gato, type(gato)) -print(diccionario) -``` - -![Método pop(clave)](./img/23.png) - ---- -`popitem()`: Elimina el último par clave-valor del diccionario, retorna el par clave-valor, si el diccionario está vacío retorna un error - -```python [1-3|4-6|7-8] -print ("Método popitem()") -diccionario = {'perro': '🐶', 'gato': '🐱'} -print(diccionario) -par = diccionario.popitem() -print(par, type(par)) -print(diccionario) -# par = diccionario.popitem() -# print(par, type(par)) # KeyError: 'popitem(): dictionary is empty' -``` - -![Método popitem()](./img/24.png) - ---- -##### Métodos de copia - -Permiten copiar el diccionario con una nueva referencia de memoria - -- `copy()` - ---- -Cuando se asigna un diccionario a una nueva variable se asigna por referencia - -NO se crea un dict nuevo sino una referencia al original - -```python [1-3|4-5|6-8] -print ("Asignación por referencia") -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -print(diccionario) -copia = diccionario -print(copia) -copia['ave'] = '🦅' -print(diccionario) -print(copia) -``` - -![Asignación por referencia](./img/25.png) - ---- -Para crear una copia del diccionario se utiliza el método `copy()` - -```python [1-3|4-5|6-8] -print ("Método copy()") -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -print(diccionario) -copia = diccionario.copy() -print(copia) -copia['ave'] = '🦅' -print(diccionario) -print(copia) -``` - -![Método copy()](./img/26.png) - ---- -##### Funciones con diccionarios - -Los diccionarios interactúan con funciones propias de python - -- `len()` -- `in` / `not in` -- `iter()` - -Existen otras funciones pueden encontrarse en la [documentación](https://docs.python.org/3/library/stdtypes.html#typesmapping) - ---- -`len(diccionario)`: Retorna la cantidad de pares clave-valor del diccionario - -```python [1-3|4-5] -print ("Función len()") -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -print(diccionario) -longitud = len(diccionario) -print(longitud) -``` - -![Función len()](./img/27.png) - ---- -`in` / `not in`: Verifica si una clave existe en el diccionario - -```python [1-3|4-5|6-8] -print ("Función in / not in") -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -print(diccionario) -existe = 'perro' in diccionario -print(existe, type(existe)) -no_existe = 'pez' not in diccionario -print(no_existe, type(no_existe)) -``` - -![Función in / not in](./img/28.png) - ---- -`iter(diccionario.items)`: Recibe items del diccionario y retorna un iterador - -```python [1-3|4-5|6-7|8-9|10-11] -print ("Función iter()") -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': '🐦'} -print(diccionario) -iterador = iter(diccionario.items()) -print(type(iterador)) -siguiente = next(iterador) -print(siguiente, type(siguiente)) -siguiente = next(iterador) -print(siguiente, type(siguiente)) -siguiente = next(iterador) -print(siguiente, type(siguiente)) -``` - -![Función iter()](./img/29.png) - ---- -##### Diccionarios anidados - -Los diccionarios pueden contener otros diccionarios - -```python [1-3|4-5|6-7|8-9] -print ("Diccionarios anidados") -diccionario = {'perro': '🐶', 'gato': '🐱', 'ave': {'pajaro': '🐦', 'aguila': '🦅'}} -print(diccionario) -aves = diccionario['ave'] -print(aves) -ave = aves['pajaro'] -print(ave) -ave = aves['aguila'] -print(ave) -``` - -![Diccionarios anidados](./img/30.png) - ---- - - ---- -##### Commit - -Commit de la sesión a nuestro repositorio - -```bash -git add . -git commit -m "Clase sesión 11" -git push -``` - ---- -##### Resumen Diccionarios - -- Los diccionarios son una estructura de datos que permite almacenar pares clave-valor -- Los diccionarios son mutables, ordenados, indexados por claves y reescriben duplicados -- Se declaran con llaves `{}` o con la función `dict()` - ---- -- Se accede a los elementos por clave -- Se modifican los elementos por clave -- Se eliminan los elementos por clave - ---- -- Se acceden a los elementos con los métodos `get()`, `items()`, `keys()` y `values()` -- Se añaden a los diccionarios con el método `update()` - ---- -- Se eliminan elementos con los métodos `clear()`, `pop()` y `popitem()` -- Se copian con el método `copy()` - ---- -- Los diccionarios interactúan con funciones propias de python como `len()`, `in` / `not in` y `iter()` -- Los diccionarios pueden contener otros diccionarios -- Pueden almacenar cualquier tipo de dato - ---- -##### Retos - -Crear una carpeta con el nombre "retos_sesion_11" en la cual por cada ejercicio debe crear un script de python - -```bash -# Ejemplo carpeta -psg-example/ - retos_sesion_11/ - ejercicio_01.py - ejercicio_02.py - ejercicio_03.py - ejercicio_04.py - ejercicio_05.py - sesion11.ipynb -``` - -Subir la carpeta a su repositorio en GitHub cuando termine los retos - ---- -1. Utiliza un diccionario para almacenar información de un animal marino de un acuario, registra información como especie, habitat, dieta, estado de salud, edad y en un set los nombre de los responsables de su cuidado - ---- -2. Crea un diccionario de alimentos y que animales domésticos lo consumen, por ejemplo -```python -{"carne" : ["gato", "perro"], "zanahoria" : ["conejo"] } -``` - - - Añade al diccionario 4 alimentos más, usando `update(clave=valor)` - - Existe en el diccionario de alimentos la comida 'trigo'? - - Elimina la comida 'zanahoria' del diccionario de alimentos - ---- -3. Crea un diccionario con la siguiente tupla de especies animales - -```python -(('canino', '🐶') , ('felino','🐱') , ('aves',['🐦','🦅'])) -``` - - - Del diccionario obtén y elimina el valor de la clave 'aves' - - Modifica el valor de la clave 'felino' por '🐈' - - Cambia la clave canino por caninos y su valor por ['🐶','🐕'] - ---- -4. Gestión de hábitats en peligro: Crea un diccionario que asocie especies animales en peligro de extinción con información sobre sus hábitats amenazados, lo que permite priorizar la protección de áreas críticas para la supervivencia de estas especies - -```python -{"polo norte" : { - "especies": {"oso polar", "morsa", "ballena"} - }, "amazonas" : { - "especies": {"tigre", "mono", "guacamayo"} - } -} -``` - ---- - - Añade al diccionario 2 habitats más usando update() con 2 especies cada uno - - Existe en el diccionario el habitat 'amazonas'? - - Añade al amazonas la especie 'anaconda' - ---- -5. Eres NOE y tienes que guardar dos animales de cada especie en un arca, crea un diccionario con las especies - -```python -{"🐶" : 2, "🐱" : 2, "🐯" : 2, "🐵" : 2, "🦄" : 0, "🦒" : 1} -``` - ---- - - Añade al arca 3 especies más usando update() - - Toma lista de los animales en el arca iterando el diccionario - - Existe en el arca la especie 'dragon' 🐲? - - Elimina la especie unicornio del arca - - Modifica el valor de la especie jirafa por 2 - - Vacía el arca después del diluvio - ---- -6. Convertir y ejecutar el archivo de la "sesion11.py" a un archivo en jupyter notebook - ---- - - -
-
-
-
-
- -[![GitHub](../../content/github_logo.png) ](https://github.com/python-la-paz/python-study-group-fundamentals/tree/main/content/sesion11) - -Repositorio de la Sesión - ---- - -## Bibliografía y Referencias - -- [Python Learn](https://do1.dr-chuck.com/pythonlearn/ES_es/pythonlearn.pdf) -- [Datastructures Dictionaries](https://docs.python.org/3/tutorial/datastructures.html#dictionaries) -- [Stdtypes Typesmapping](https://docs.python.org/3/library/stdtypes.html#typesmapping) -- [Dictionary](https://www.programiz.com/python-programming/dictionary) -- [Python Dict](https://cs.stanford.edu/people/nick/py/python-dict.html) -- [Python Dictionaries](https://www.dataquest.io/blog/python-dictionaries/) \ No newline at end of file diff --git a/content/sesion11/img/01.png b/content/sesion11/img/01.png deleted file mode 100644 index ec519f0..0000000 Binary files a/content/sesion11/img/01.png and /dev/null differ diff --git a/content/sesion11/img/02.png b/content/sesion11/img/02.png deleted file mode 100644 index bb4bff6..0000000 Binary files a/content/sesion11/img/02.png and /dev/null differ diff --git a/content/sesion11/img/03.png b/content/sesion11/img/03.png deleted file mode 100644 index 68b94dd..0000000 Binary files a/content/sesion11/img/03.png and /dev/null differ diff --git a/content/sesion11/img/04.png b/content/sesion11/img/04.png deleted file mode 100644 index 3262df7..0000000 Binary files a/content/sesion11/img/04.png and /dev/null differ diff --git a/content/sesion11/img/05.png b/content/sesion11/img/05.png deleted file mode 100644 index 11d6bf4..0000000 Binary files a/content/sesion11/img/05.png and /dev/null differ diff --git a/content/sesion11/img/06.png b/content/sesion11/img/06.png deleted file mode 100644 index 777add6..0000000 Binary files a/content/sesion11/img/06.png and /dev/null differ diff --git a/content/sesion11/img/07.png b/content/sesion11/img/07.png deleted file mode 100644 index ac763f8..0000000 Binary files a/content/sesion11/img/07.png and /dev/null differ diff --git a/content/sesion11/img/08.png b/content/sesion11/img/08.png deleted file mode 100644 index 7eb0229..0000000 Binary files a/content/sesion11/img/08.png and /dev/null differ diff --git a/content/sesion11/img/09.png b/content/sesion11/img/09.png deleted file mode 100644 index 9afe530..0000000 Binary files a/content/sesion11/img/09.png and /dev/null differ diff --git a/content/sesion11/img/10.png b/content/sesion11/img/10.png deleted file mode 100644 index fd82d1d..0000000 Binary files a/content/sesion11/img/10.png and /dev/null differ diff --git a/content/sesion11/img/11.png b/content/sesion11/img/11.png deleted file mode 100644 index 2258f21..0000000 Binary files a/content/sesion11/img/11.png and /dev/null differ diff --git a/content/sesion11/img/12.png b/content/sesion11/img/12.png deleted file mode 100644 index 6b18f63..0000000 Binary files a/content/sesion11/img/12.png and /dev/null differ diff --git a/content/sesion11/img/13.png b/content/sesion11/img/13.png deleted file mode 100644 index c8ed654..0000000 Binary files a/content/sesion11/img/13.png and /dev/null differ diff --git a/content/sesion11/img/14.png b/content/sesion11/img/14.png deleted file mode 100644 index da153c5..0000000 Binary files a/content/sesion11/img/14.png and /dev/null differ diff --git a/content/sesion11/img/15.png b/content/sesion11/img/15.png deleted file mode 100644 index 32c82f5..0000000 Binary files a/content/sesion11/img/15.png and /dev/null differ diff --git a/content/sesion11/img/16.png b/content/sesion11/img/16.png deleted file mode 100644 index 056b119..0000000 Binary files a/content/sesion11/img/16.png and /dev/null differ diff --git a/content/sesion11/img/17.png b/content/sesion11/img/17.png deleted file mode 100644 index ae23064..0000000 Binary files a/content/sesion11/img/17.png and /dev/null differ diff --git a/content/sesion11/img/18.png b/content/sesion11/img/18.png deleted file mode 100644 index fed6d49..0000000 Binary files a/content/sesion11/img/18.png and /dev/null differ diff --git a/content/sesion11/img/19.png b/content/sesion11/img/19.png deleted file mode 100644 index 13337fe..0000000 Binary files a/content/sesion11/img/19.png and /dev/null differ diff --git a/content/sesion11/img/20.png b/content/sesion11/img/20.png deleted file mode 100644 index 1039309..0000000 Binary files a/content/sesion11/img/20.png and /dev/null differ diff --git a/content/sesion11/img/21.png b/content/sesion11/img/21.png deleted file mode 100644 index cde555f..0000000 Binary files a/content/sesion11/img/21.png and /dev/null differ diff --git a/content/sesion11/img/22.png b/content/sesion11/img/22.png deleted file mode 100644 index f06eab7..0000000 Binary files a/content/sesion11/img/22.png and /dev/null differ diff --git a/content/sesion11/img/23.png b/content/sesion11/img/23.png deleted file mode 100644 index 952f8d1..0000000 Binary files a/content/sesion11/img/23.png and /dev/null differ diff --git a/content/sesion11/img/24.png b/content/sesion11/img/24.png deleted file mode 100644 index 843565b..0000000 Binary files a/content/sesion11/img/24.png and /dev/null differ diff --git a/content/sesion11/img/25.png b/content/sesion11/img/25.png deleted file mode 100644 index ce0786f..0000000 Binary files a/content/sesion11/img/25.png and /dev/null differ diff --git a/content/sesion11/img/26.png b/content/sesion11/img/26.png deleted file mode 100644 index da9c8bf..0000000 Binary files a/content/sesion11/img/26.png and /dev/null differ diff --git a/content/sesion11/img/27.png b/content/sesion11/img/27.png deleted file mode 100644 index d71fa0f..0000000 Binary files a/content/sesion11/img/27.png and /dev/null differ diff --git a/content/sesion11/img/28.png b/content/sesion11/img/28.png deleted file mode 100644 index b62733a..0000000 Binary files a/content/sesion11/img/28.png and /dev/null differ diff --git a/content/sesion11/img/29.png b/content/sesion11/img/29.png deleted file mode 100644 index 7532c0a..0000000 Binary files a/content/sesion11/img/29.png and /dev/null differ diff --git a/content/sesion11/img/30.png b/content/sesion11/img/30.png deleted file mode 100644 index e2b28fb..0000000 Binary files a/content/sesion11/img/30.png and /dev/null differ diff --git a/content/sesion11/index.html b/content/sesion11/index.html deleted file mode 100644 index 22d4296..0000000 --- a/content/sesion11/index.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - Sesión 11 | Python Study Group | Fundamentals - - - - - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/content/sesion12/Readme.md b/content/sesion12/Readme.md deleted file mode 100644 index 891d6f4..0000000 --- a/content/sesion12/Readme.md +++ /dev/null @@ -1,1094 +0,0 @@ - -![Python La paz](../Logo.png) - -
-
-
- -### Sesión 12 -### Estructura de control de flujo -### Sentencias condicionales - ---- -##### Estructura de control - -En un programa las estructuras de control son el orden en el que se ejecutan las instrucciones - -Python soporta las siguientes estructuras de control - -- Secuencial o lineal -- Selección o condicionales -- Repetición o ciclos - ---- - -##### Secuencial o lineal - -Es la ejecución de las instrucciones en el orden en el que se escriben - -```python [1|2|3] -primero = 1 -segundo = 2 -tercero = 3 -``` - ---- -El problema con la secuencialidad es que no siempre queremos que las instrucciones se ejecuten en el orden en el que se escriben - -Para eso existen las estructuras de control de selección y repetición - ---- - -Hasta el momento hemos visto sólo ejecución secuencial de instrucciones en Python - ---- -##### Selección o condicionales - -Las estructuras de selección o condicionales permiten ejecutar un bloque de código si se cumple una condición - ---- -Permite a los programas tomar decisiones y ejecutar diferentes acciones dependiendo de las condiciones - ---- -En Python se utilizan las siguientes condicionales - -- `if` -- `else` -- `if` anidado -- `elif` - ---- -Crearemos un archivo con el nombre sesion12.py - -Empezaremos a escribir condicionales - ---- -##### if - -La sentencia `if` permite ejecutar un bloque de código si se cumple una condición - -La condición tiene que ser un booleano - ---- -Visualmente - -![Condicional IF](./img/IF-W.gif) - ---- -##### Como se declara un `if` - -`if` tiene la siguiente estructura - -```python -if condicion: - print ("Cumple") -``` - -- `if`, es la palabra reservada -- `condicion`, es una expresión evaluada con `True` o `False` -- `:`, es el delimitador de la condición -- `print ("Cumple")`, es el bloque de código con indentación que se ejecuta si la condición es `True` - ---- -En Python la estructura de un condicional `if` es la siguiente - -```python -print ("Inicio") -condicion = True -if condicion: - # Bloque de código - print ("Cumple condición") -print ("Fin") -``` - -```python -Inicio -Cumple condición -Fin -``` - ---- -Ejemplo: -Dado un número, imprimir si es par - -```python [1-2|3|4|5] -print ("Inicio") -numero = 4 -if numero % 2 == 0: # Si el módulo de 2 es 0 - print ("El número es par") -print ("Fin") -``` - -```text -Inicio -El número es par -Fin -``` - ---- -##### if-else - -La sentencia `else` permite ejecutar un bloque de código si no se cumple la condición del `if` - -Si la condición es `True` se ejecuta el bloque de código del `if` - -Si la condición es `False` se ejecuta el bloque de código del `else` - ---- -Visualmente - -![Condicional IF-ELSE](./img/IF-ELSE-W.gif) - ---- -Como se declara un `if-else` - -`if-else` tiene la siguiente estructura - -```python -if condicion: - print ("Cumple") -else: - print ("No cumple") -``` -- `if` - `else`, son palabras reservadas -- `condicion`, es una expresión `True` o `False` -- `:`, es el delimitador en `if` y `else` -- `print ("Cumple")`, bloque por `True` -- `print ("No cumple")`, bloque por `False` - - ---- -En Python la estructura de un condicional `if-else` es la siguiente - -```python -print ("Inicio") -condicion = False -if condicion: - # Bloque de código - print ("Cumple condición") -else: - # Bloque de código - print ("No cumple condición") -print ("Fin") -``` - -```text -Inicio -No cumple condición -Fin -``` ---- -Ejemplo: -Dado un número, imprimir si es par o impar - -```python [1-2|3-4|5-6|7] -print ("Inicio") -numero = 3 -if numero % 2 == 0: # Si el módulo de 2 es 0 - print ("El número es par") -else: - print ("El número es impar") -print ("Fin") -``` - -```text -Inicio -El número es impar -Fin -``` - ---- -##### if-anidado - -La sentencia `if` anidado permite ejecutar un bloque de código si se cumple una condición - -Dentro del bloque de código del `if-else` se puede anidar otro `if-else` de manera ilimitada - ---- -Visualmente - -![Condicional IF-ELSE](./img/IF-ANIDADO-W.gif) - ---- -Como se declara un `if-anidado` - -`if-anidado` tiene la siguiente estructura - -```python -if condicion_1: - print ("Cumple 1") - if condicion_2: - print ("Cumple 2") - else: - print ("No cumple 2") -else: - print ("No cumple 1") -``` - -- `if`, `else`, son palabras reservadas -- `condicion_1`, `condicion_2`, son expresiones -- `:`, es el delimitador en `if` y `else` -- La indentación incrementa en cada nivel de anidación - ---- -En Python la estructura de un condicional `if-anidado` es la siguiente - -```python -print ("Inicio Anidado") -condicion_1 = True -condicion_2 = False -if condicion_1: - print ("Cumple condición 1") - if condicion_2: - print ("Cumple condición 2") - else: - print ("No cumple condición 2") -else: - print ("No cumple condición 1") -print ("Fin") -``` - -```text -Inicio Anidado -Cumple condición 1 -No cumple condición 2 -Fin -``` - ---- -Ejemplo: Dado un número, imprimir si es par, impar o cero - -```python [1-2|3-7|4-5|6-7|8-9|10] -print ("Inicio Par, Impar o Cero") -numero = 0 -if numero > 0 or numero < 0: - if numero % 2 == 0: # Si el módulo de 2 es 0 - print ("El número es par") - else: - print ("El número es impar") -else: - print ("El número es cero") -print ("Fin") -``` - -```text -Inicio Par, Impar o Cero -El número es cero -Fin -``` - ---- -Una desventaja de los condicionales anidados es que pueden ser difíciles de leer y entender - -Tener una indentación excesiva puede hacer que el código no sea optimo - ---- -En Python existe una estructura de control que permite simplificar los condicionales anidados - -Se llama `elif` - ---- -##### elif - -La sentencia `elif` es la abreviatura de `else if` - -Permite ejecutar un bloque de código si no se cumple la condición del `if` y sí cumple una nueva condición - ---- -Visualmente - -![Condicional ELIF](./img/ELIF-W.gif) - ---- -Como se declara un `elif` - -`elif` tiene la siguiente estructura - -```python -if condicion_1: - print ("Cumple 1") -elif condicion_2: - print ("Cumple 2") -else: - print ("No cumple 1 ni 2") -``` - -- `if`, `elif`, `else`, son palabras reservadas -- `condicion_1`, `condicion_2`, son expresiones -- `:`, es el delimitador en `if`, `elif` y `else` -- La indentación solo incrementa en el primer nivel - ---- -En Python la estructura de un condicional `elif` es la siguiente - -```python [1-3|4-5|6-7|8-9|10] -print ("Inicio ELIF") -condicion_1 = False -condicion_2 = True -if condicion_1: - print ("Cumple condición 1") -elif condicion_2: - print ("Cumple condición 2") -else: - print ("No cumple condición 1 ni 2") -print ("Fin") -``` - -```text -Inicio ELIF -Cumple condición 2 -Fin -``` - ---- -Ejemplo: Dado un número, imprimir si es positivo, negativo o cero - -```python -print ("Inicio Positivo, Negativo o Cero") -numero = -1 -if numero > 0: - print ("El número es positivo") -elif numero < 0: - print ("El número es negativo") -else: - print ("El número es cero") -``` - -```text -Inicio Positivo, Negativo o Cero -El número es negativo -``` - ---- -Existe una forma de compactar una condicional en una sola línea - -Se llama operador ternario - ---- -##### Operador ternario - -El operador ternario es una forma de compactar una condicional en una sola línea - -Como su nombre lo indica, tiene tres partes - -```python -resultado = verdadero if condicion else falso -``` - -- Condición -- Resultado verdadero si es `True` -- Resultado falso si es `False` - ---- -En Python la estructura de un operador ternario es la siguiente - -```python -print ("Inicio Ternario") -condicion = True -resultado = "Cumple" if condicion else "No cumple" -print (resultado) -print ("Fin") -``` - -```text -Inicio Ternario -Cumple -Fin -``` - ---- -Ejemplo: Dado un número, imprimir si es par o impar - -```python -print ("Inicio Ternario Par, Impar") -numero = 3 -resultado = "El número es par" if numero % 2 == 0 else "El número es impar" -print (resultado) -print ("Fin") -``` - -```text -Inicio Ternario Par, Impar -El número es impar -Fin -``` - ---- -##### Truthiness - -¿Qué es Truthiness? - ---- -Es un término que se utiliza para describir el valor de verdad de un objeto - -En Python, todos los objetos tienen un valor de verdad - ---- -Hay valores que se consideran `True` - -y otros que se consideran `False` - ---- -En enteros - -- `0` es `False` -- `1` es `True` -- `-1` es `True` - -Todos los números enteros positivos y negativos son `True` excepto `0` - -`$x \in \mathbb{Z} \land x \neq 0$` - ---- -Se puede utilizar un entero como condición - -Introducir dos números enteros y dividirlos - -```python [1-3|4|5|5-8|9] -print ("Truthiness Enteros") -dividendo = int(input("Dividendo: ")) -divisor = int(input("Divisor: ")) -print (dividendo,divisor) -if divisor: #divisor != 0 - print (dividendo / divisor) -else: - print ("No se puede dividir entre cero") -print ("Fin") -``` - -```text -Truthiness Enteros -Dividendo: 10 -Divisor: 0 -10 0 -No se puede dividir entre cero -Fin -``` - ---- -En los flotantes - -- `0.0` es `False` -- `1.0` es `True` -- `-1.0` es `True` - -Todos los números flotantes positivos y negativos son `True` excepto `0.0` - -`$x \in \mathbb{R} \land x \neq 0.0$` - ---- -Se puede utilizar un flotante como condición - -Introducir dos números flotantes y dividirlos - -```python [1-3|4|5|5-8|9] -print ("Truthiness Flotantes") -dividendo = float(input("Dividendo: ")) -divisor = float(input("Divisor: ")) -print (dividendo,divisor) -if divisor: #divisor != 0.0 - print (dividendo / divisor) -else: - print ("No se puede dividir entre cero") -print ("Fin") -``` - -```text -Truthiness Flotantes -Dividendo: 10.5 -Divisor: 0.5 -10.0 0.5 -21.0 -Fin -``` - ---- -En las cadenas - -- `""` es `False` -- `" "` es `True` -- `"hola"` es `True` -- `"0"` es `True` - -Todas las cadenas no vacías son `True` - -Las cadenas vacías son `False` - ---- -Se puede utilizar una cadena como condición - -Introducir una cadena y verificar si es vacía - -```python [1-3|4|5|5-8|9] -print ("Truthiness Cadenas") -cadena = input("Cadena: ") -print (cadena) -if cadena: # len(cadena) != 0 or cadena != "" - print ("La cadena no está vacía") -else: - print ("La cadena está vacía") -print ("Fin") -``` - -```text -Truthiness Cadenas -Cadena: 🐍 -🐍 -La cadena no está vacía -Fin -``` - ---- -En las tuplas - -- `()` es `False` -- `(0,)` es `True` -- `("0",)` es `True` -- `("♎",)` es `True` - -Todas las tuplas no vacías son `True` - -Las tuplas vacías son `False` - ---- -Se puede utilizar una tupla como condición - -Introducir una tupla y verificar si es vacía - -```python [1-3|4|5|5-8|9] -print ("Truthiness Tuplas") -tupla = tuple(input("Tupla: ")) -print (tupla) -if tupla: # len(tupla) != 0 or tupla != () - print ("La tupla no está vacía") -else: - print ("La tupla está vacía") -print ("Fin") -``` - -```text -Truthiness Tuplas -Tupla: ♈♉♊♋ -('♈', '♉', '♊', '♋') -La tupla no está vacía -Fin -``` - ---- -En las listas - -- `[]` es `False` -- `[0]` es `True` -- `[""]` es `True` -- `["♎"]` es `True` - -Todas las listas no vacías son `True` - -Las listas vacías son `False` - ---- -Se puede utilizar una lista como condición - -Introducir una lista y verificar si es vacía - -```python [1-3|4|5|5-8|9] -print ("Truthiness Listas") -lista = list(input("Lista: ")) -print (lista) -if lista: # len(lista) != 0 or lista != [] - print ("La lista no está vacía") -else: - print ("La lista está vacía") -print ("Fin") -``` - -```text -Truthiness Listas -Lista: ♌♍♎♏ -['♌', '♍', '♎', '♏'] -La lista no está vacía -Fin -``` - ---- -En conjuntos - -- `set()` es `False` -- `{0}` es `True` -- `{"0"}` es `True` -- `{"♎"}` es `True` - -Todos los conjuntos no vacíos son `True` - -Los conjuntos vacíos son `False` - ---- -Se puede utilizar un conjunto como condición - -Introducir un conjunto y verificar si es vacío - -```python [1-3|4|5|5-8|9] -print ("Truthiness Conjuntos") -conjunto = set(input("Conjunto: ")) -print (conjunto) -if conjunto: # len(conjunto) != 0 or conjunto != set() - print ("El conjunto no está vacío") -else: - print ("El conjunto está vacío") -print ("Fin") -``` - -```text -Truthiness Conjuntos -Conjunto: ♐♑♒♓ -{'♐', '♑', '♒', '♓'} -El conjunto no está vacío -Fin -``` - ---- -En diccionarios - -- `{}` es `False` -- `{'': ''}` es `True` -- `{"0":0}` es `True` -- `{"♎":"Libra"}` es `True` - -Todos los diccionarios no vacíos son `True` - -Los diccionarios vacíos son `False` - ---- -Se puede utilizar un diccionario como condición - -Introducir la clave y un valor y verificar si es vacío - -```python [1-4|5-6|7|8-11|12] -print ("Truthiness Diccionarios") -diccionario = {} -clave = input("Clave: ") -valor = input("Valor: ") -if clave: - diccionario = {clave:valor} -print (diccionario) -if diccionario: # diccionario != {} - print ("El diccionario no está vacío") -else: - print ("El diccionario está vacío") -print ("Fin") -``` - -```text -Truthiness Diccionarios -Clave: ♈ -Valor: Aries -{'♈': 'Aries'} -El diccionario no está vacío -Fin -``` - ---- -None es un valor especial en Python - -- `None` es `False` - -`None` es un valor especial que representa la ausencia de un valor - ---- -Se puede utilizar `None` como condición - -Introducir un valor y verificar si es `None` - -```python [1-3|4-7|8] -print ("Truthiness None") -valor = None -print (valor, type(valor)) -if valor: # valor != None - print ("El valor no es None") -else: - print ("El valor es None") -print ("Fin") -``` - -```text -Truthiness None -None -El valor es None -Fin -``` - ---- -Con operadores ternarios es bastante útil para asignar valores a variables - -```python [1-3|4-6|7-9] -entero = int(input("Entero: ")) -resultado = "Diferente de 0" if entero else "Igual a 0" -print (resultado) -flotante = float(input("Flotante: ")) -resultado = "Diferente de 0.0" if flotante else "Igual a 0.0" -print (resultado) -cadena = input("Cadena: ") -resultado = "No está vacía" if cadena else "Está vacía" -print (resultado) -``` - -```text -Entero: 0 -Igual a 0 -Flotante: 0.0 -Igual a 0.0 -Cadena: -Está vacía -``` - ---- -##### Ejemplos de usos - ---- -Tienes un dispositivo que mide la temperatura y si la temperatura es mayor a 30°C enciende un ventilador y si es menor a 20°C lo apaga - -3 minutos - - - ---- -```python [1|2-3|4-5] -temperatura = float(input("Temperatura: ")) -if temperatura > 30: - print ("Encender ventilador") -elif temperatura < 20: - print ("Apagar ventilador") -``` - -```text -Temperatura: 35 -Encender ventilador -``` - -```text -Temperatura: 15 -Apagar ventilador -``` - -```text -Temperatura: 25 -``` - ---- -Tienes una cesta de frutas y quieres saber si tienes manzanas, si hay manzanas las cuentas y si no hay compras dos manzanas - -3 minutos - - - ---- -Con solo un if -```python [1-2|3-4|5-7] -cesta = ['🍎','🍑','🍓','🍉'] -print (cesta) -if '🍎' in cesta: - print (f"Hay {cesta.count('🍎')} manzanas") -else: - cesta.extend(['🍎','🍎']) - print (cesta) -``` - -```text -['🍎', '🍑', '🍓', '🍉'] -Hay 1 manzanas -``` - ---- -Con operador ternario -```python [1-2|3|4-5] -cesta = ['🍑','🍓','🍉'] -print (cesta) -resultado = f"Hay {cesta.count('🍎')} manzanas" if '🍎' in cesta else cesta.extend(['🍎','🍎']) -print (resultado) -print (cesta) -``` - -```text -['🍑', '🍓', '🍉'] -None -['🍑', '🍓', '🍉', '🍎', '🍎'] -``` - ---- -En un diccionario tienes almacenado un animal y quieres saber si es un mamífero -```python -animal = {'especie':'🐶', 'nombre': 'Firulais', 'mamifero': True} -``` - -2 minutos - - - ---- -```python -animal = {'especie':'🐶', 'nombre': 'Firulais', 'mamifero': True} -print (animal) -if animal.get('mamifero'): # animal['mamifero'] - print ("Es un mamífero") -else: - print ("No es un mamífero") -``` - -```text -{'especie': '🐶', 'nombre': 'Firulais', 'mamifero': True} -Es un mamífero -``` - ---- -Dado dos conjuntos, verificar si tienen elementos en común y mostrarlos y si no, unirlos - -```python -{'⚽','🏀','🏐'} , {'🏈','🏉','🏓'} -``` - -3 minutos - - - ---- -```python -conjunto_1 = {'⚽','🏀','🏐'} -conjunto_2 = {'🏈','🏉','🏓'} -print (conjunto_1, conjunto_2) -if conjunto_1.isdisjoint(conjunto_2): # len(conjunto_1.intersection(conjunto_2)) == 0 - conjunto_1.update(conjunto_2) - print (conjunto_1) -else: - print ("Tienen elementos en común") - print (conjunto_1.intersection(conjunto_2)) -``` - -```text -{'⚽', '🏀', '🏐'} {'🏈', '🏉', '🏓'} -{'⚽', '🏀', '🏐', '🏈', '🏉', '🏓'} -``` - -```text -{'⚽', '🏀', '🏐'} {'🏈', '🏉', '🏓', '🏀'} -Tienen elementos en común -{'🏀'} -``` - ---- -Validar si un correo electrónico es válido usando input - -- ✅: `mail@domain.com`, `ma.il@domain.com` -- ❌: `mail@domain`, `maildomain.com`, `@.` -- ❌: `mail@@domain.com`, `mail@.com` - -5 minutos - - - ---- -Solución anidada - -```python [1|2|3|4|5|2-14] -correo = input("Correo: ") -if "@" in correo and "." in correo and correo.count("@") == 1: - if correo.find("@") < correo.rfind(".") and correo.find("@") > 0 and correo.rfind(".") < len(correo) - 1: - if correo.rfind(".") - correo.find("@") > 1: - if correo.find(".") - correo.find("@") > 1: - print ("El correo es válido") - else: - print ("El correo no es válido") - else: - print ("El correo no es válido") - else: - print ("El correo no es válido") -else: - print ("El correo no es válido") -``` - -```text -Correo: mail@domain -El correo no es válido -``` - ---- -Solución con elif - -```python [1|2-3|4-5|6-7|8-9|10-11] -correo = input("Correo: ") -if "@" not in correo or "." not in correo or correo.count("@") != 1: - print("El correo no es válido") -elif correo.find("@") >= correo.rfind(".") or correo.find("@") == 0 or correo.rfind(".") == len(correo) - 1: - print("El correo no es válido") -elif correo.rfind(".") - correo.find("@") <= 1: - print("El correo no es válido") -elif correo.find(".") - correo.find("@") == 1: - print("El correo no es válido") -else: - print("El correo es válido") -``` - -```text -Correo: a.b@c.d -El correo es válido -``` - - - - - ---- -##### Commit - -Commit de la sesión a nuestro repositorio - -```bash -git add . -git commit -m "Clase sesión 12" -git push -``` - ---- -##### Resumen Sentencias condicionales - -- Las estructuras de control permiten tomar decisiones o repetir instrucciones -- Las sentencias condicionales permiten ejecutar un bloque de código si se cumple una condición -- Las condicionales en Python son - `if`, `else`, `elif` - ---- -- Las condicionales reciben una expresión que se evalúa como `True` o `False` -- Se pueden anidar condicionales -- Existe el operador ternario para simplificar condicionales - ---- -- El operador ternario se compone de tres partes `"verdadero if condicion else falso"` -- Truthiness es el valor de verdad de un objeto -- Se puede utilizar un objeto como condición - ---- -- `0`, `0.0`, `""`, `()`, `[]`, `{}`, `set()`, `None` son `False` -- None es un valor especial en Python que representa la ausencia de un valor - ---- - -![IF](./img/IF-W.gif) -![IF-ELSE](./img/IF-ELSE-W.gif) - ---- -![IF-ANIDADO](./img/IF-ANIDADO-W.gif) -![ELIF](./img/ELIF-W.gif) - ---- -##### Retos - -Crear una carpeta con el nombre "retos_sesion_12" en la cual por cada ejercicio debe crear un script de python - -```bash -# Ejemplo carpeta -psg-example/ - retos_sesion_12/ - ejercicio_01.py - ejercicio_02.py - ejercicio_03.py - ejercicio_04.py - ejercicio_05.py - ejercicio_06.py - sesion12.ipynb -``` - -Subir la carpeta a su repositorio en GitHub cuando termine los retos - ---- -1. Crear un script que pida un número entero y verifique si es múltiplo de 5 usando operador ternario. - ---- -2. Tienes una app para gestionar tareas de 4 usuarios, para acceder los usuarios deben iniciar sesión con un nombre de usuario y una contraseña introducidos por teclado. - -- Define los siguientes usuarios y contraseñas utilizando la estructura de datos mas adecuada. - -```python - -```text -Usuario: admin, Contraseña: admin123 -Usuario: user1, Contraseña: user123 -Usuario: user2, Contraseña: user123 -Usuario: user3, Contraseña: user123 -``` ---- -- Verifica si el usuario inició sesión para acceder a la app y muestra el mensaje `Acceso Aprobado`, caso contrario muestra el mensaje de error `Acceso Denegado`. - ---- -3. Jhon colecciona autos a escala 1:64, tiene los siguientes autos - -```python -{'Ferrari', 'Lamborghini', 'Porsche', 'Bugatti', 'McLaren'} -``` - -Jess tambien colecciona autos a escala 1:64, tiene los siguientes autos - -```python -{'Ferrari', 'Lamborghini', 'Tesla', 'Ford', 'Chevrolet'} -``` - -¿Que autos tienen en común ambos coleccionistas?, ¿Cuáles son los autos en común? - ---- -4. Una tienda ofrece descuentos a sus clientes, si el cliente tiene una edad mayor a 60 años y tiene una compra mayor a 1000, se le aplica un descuento del 20%, si el cliente tiene una edad entre 18 y 60 años y tiene una compra mayor a 500 se le aplica un descuento del 10%, si no cumple ninguna condición se le aplica un descuento del 2% - ---- -5. Tienes una app para gestionar contactos, cada contacto tiene un nombre y un número de teléfono, si el contacto tiene un número de teléfono válido (11 dígitos incluyendo el código de país) y un nombre valido se guarda en la lista de contactos y muestra el mensaje `Contacto guardado`, caso contrario se muestra el mensaje de error `Datos incorrectos`. ---- -- El nombre y el numero de teléfono se ingresan por teclado -- Verifica si el el numero de teléfono es válido -- Verifica si el nombre válido usando truthiness -``` text: -Nombre: Juan Perez -Teléfono: +591123456789 -------------- -Contacto guardado - -Nombre: -Teléfono: +123456789 -------------- -Datos incorrectos -``` - ---- -6. Crea una calculadora por consola que realice las operaciones de suma, resta, multiplicación y división. Las operaciones se ingresan por teclado separadas por comas en el siguiente formato: - - numero1, número2, operación - - ejemplo: `10, 5, +` - -verifica si la operación solicitada es válida y muestra el resultado - - -```text -Operación: 10, 5, + -------------- -Resultado: 15 -``` - ---- -7. Convertir y ejecutar el archivo de la "sesion12.py" a un archivo en Jupyter Notebook - ---- - - -
-
-
-
-
- -[![GitHub](../../content/github_logo.png) ](https://github.com/python-la-paz/python-study-group-fundamentals/tree/main/content/sesion12) - -Repositorio de la Sesión - ---- - -## Bibliografía y Referencias - -- [Python Learn](https://do1.dr-chuck.com/pythonlearn/ES_es/pythonlearn.pdf) -- [If statements](https://docs.python.org/3/tutorial/controlflow.html#if-statements) -- [Compound statements - IF](https://docs.python.org/3/reference/compound_stmts.html#if) -- [Control flow statements in Python](https://www.educative.io/answers/what-are-control-flow-statements-in-python) -- [Truthiness](https://www.pythonmorsels.com/truthiness/) -- [Truthy and Falsy values in Python](https://www.freecodecamp.org/news/truthy-and-falsy-values-in-python/) \ No newline at end of file diff --git a/content/sesion12/img/ELIF-W.gif b/content/sesion12/img/ELIF-W.gif deleted file mode 100644 index d1fd1ed..0000000 Binary files a/content/sesion12/img/ELIF-W.gif and /dev/null differ diff --git a/content/sesion12/img/IF-ANIDADO-W.gif b/content/sesion12/img/IF-ANIDADO-W.gif deleted file mode 100644 index 63c0de8..0000000 Binary files a/content/sesion12/img/IF-ANIDADO-W.gif and /dev/null differ diff --git a/content/sesion12/img/IF-ELSE-W.gif b/content/sesion12/img/IF-ELSE-W.gif deleted file mode 100644 index d80779c..0000000 Binary files a/content/sesion12/img/IF-ELSE-W.gif and /dev/null differ diff --git a/content/sesion12/img/IF-W.gif b/content/sesion12/img/IF-W.gif deleted file mode 100644 index 6b625c9..0000000 Binary files a/content/sesion12/img/IF-W.gif and /dev/null differ diff --git a/content/sesion12/index.html b/content/sesion12/index.html deleted file mode 100644 index d0ddd64..0000000 --- a/content/sesion12/index.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - Sesión 12 | Python Study Group | Fundamentals - - - - - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/content/sesion13/Readme.md b/content/sesion13/Readme.md deleted file mode 100644 index 4d37e0a..0000000 --- a/content/sesion13/Readme.md +++ /dev/null @@ -1,1127 +0,0 @@ - -![Python La paz](../Logo.png) - -
-
-
- - -### Sesión 13 -### Estructura de control de flujo -### Sentencias iterativas - ---- -##### Estructura de control - -En un programa las estructuras de control son el orden en el que se ejecutan las instrucciones - -Python soporta las siguientes estructuras de control - -- Secuencial o lineal -- Selección o condicionales -- Repetición o ciclos - ---- - -##### Secuencial o lineal - -Es la ejecución de las instrucciones en el orden en el que se escriben - -```python [1|2|3] -primero = 1 -segundo = 2 -tercero = 3 -``` - ---- -El problema con la secuencialidad es que no siempre queremos que las instrucciones se ejecuten en el orden en el que se escriben - -Para eso existen las estructuras de control de selección y repetición - ---- - -Hasta el momento hemos visto ejecución secuencial y condicionales - ---- -##### Repetición o ciclos - -Los ciclos son estructuras de control que permiten ejecutar un bloque de código varias veces de manera consecutiva - ---- -Permite a los programas ejecutar una secuencia de instrucciones varias veces - ---- -En Python existen dos tipos de ciclos - -- Ciclo `for` -- Ciclo `while` - ---- -Crearemos un archivo con el nombre sesion13.py - -Empezaremos a escribir ciclos - ---- -##### For - -El ciclo `for` es un ciclo que se ejecuta un número determinado de veces - -En el caso de los for se recorre una secuencia de elementos - -Se puede recorrer un rango de números - -o listas, tuplas, diccionarios, etc. - ---- -Visualmente - -![Ciclo FOR](./img/FOR-W.gif) - ---- -Para utilizar rango de números primero veremos la función `range()` - -```python -range(5) -``` -```text -range(0, 5) -``` - ---- -Range es una función que genera una secuencia inmutable de números - -```python -range(5) -``` -```text -0, 1, 2, 3, 4 -``` - ---- -Recibe tres argumentos - -- Inicio (por defecto 0 e Inclusivo) -- Fin (Obligatorio y Exclusivo) -- Paso (por defecto 1) - -```python -range(1, 10, 2) -``` -```text -1, 3, 5, 7, 9 -``` - ---- -Puede haber rangos negativos - -```python -range(10, 0, -1) -``` -```text -10, 9, 8, 7, 6, 5, 4, 3, 2, 1 -``` - ---- -Podemos convertir el rango en una lista - -```python -print(list(range(5))) -``` -```text -[0, 1, 2, 3, 4] -``` - -No es necesario convertirlo a lista para usarlo en un ciclo `for` - ---- -Son útiles para iterar sobre una secuencia de números - ---- -##### Como se declara un `for` con `range` - -`for` tiene la siguiente estructura - -```python -for variable in range(inicio, fin, paso): - print(variable) -``` - -- `for` es la palabra reservada -- `variable` es la variable que se usará para iterar -- `in` es palabra reservada de pertenencia -- `range(inicio, fin, paso)` es la secuencia de números -- `:` es el delimitador de inicio del ciclo -- `print(variable)` es el código a ejecutar posee un nivel de indentación - ---- -Cuando iteramos el nombre de la variable puede ser cualquier nombre - -Es común usar `i` que es la abreviatura de índice o iterador - -Cuando se itera más de una lista se puede usar `i`, `j`, `k` - ---- -Las variables definidas en el ciclo `for` existen dentro del ciclo - -NO se recomienda usarlas fuera del ciclo - -Es una mala práctica usar la variable del ciclo fuera del ciclo - -```python -for i in range(5): - print(i) -print(i) -``` - -```text -0 -1 -2 -3 -4 -4 -``` - ---- -En python la estructura de control `for` es la siguiente - -```python -print ("Inicio") -for i in range(5): # rango (0,5,1) - print(i) -print ("Fin") -``` - -```text -Inicio -0 -1 -2 -3 -4 -Fin -``` - ---- -Ejemplo 1, sumar los números del 1 al 10 de 2 en 2 - -```python [1-2|3-4|5] -print ("Ejemplo 1") -suma = 0 -for i in range(1, 11, 2): # 1, 3, 5, 7, 9 - suma = suma + i #suma += i -print(suma) -``` - -```text -Ejemplo 1 -25 -``` - ---- -Ejemplo 2, crear un árbol de navidad de 6 niveles - -```python [1|2-3] -print ("Ejemplo 2") -for i in range(0, 6): - print(" "*(5-i) + "*"*i*2+"*") -``` - -```text -Ejemplo 2 - * - *** - ***** - ******* - ********* -*********** -``` - ---- -Ejemplo 3, crear una serie de números cuadrados del 1 al 10 - -```python [1|2-3] -print ("Ejemplo 3") -for i in range(1, 11): - print(i**2, end=" ") -``` - -```text -Ejemplo 3 -1 4 9 16 25 36 49 64 81 100 -``` - ---- -Ejemplo 4, crear una lista de números pares del 1 al 10 - -```python [1-2|3-4|5] -print ("Ejemplo 4") -pares = [] -for i in range(0, 11, 2): - pares.append(i) -print(pares) -``` - -```text -Ejemplo 4 -[0, 2, 4, 6, 8, 10] -``` - ---- -Visualmente - - - ---- -Ejercicio 1, imprimir los 10 primeros de la serie números cúbicos - -2 minutos - - - ---- - -```python -print ("Ejercicio 1") -for i in range(1, 11): - print(i**3, end=" ") -``` - -```text -Ejercicio 1 -1 8 27 64 125 216 343 512 729 1000 -``` - ---- -##### Como se declara un `for` con secuencias - -La estructura de control `for` también puede iterar sobre secuencias - -- Listas -- Tuplas -- Diccionarios -- Cadenas de texto - ---- -`for` tiene la siguiente estructura - -```python -for variable in secuencia: - print(variable) -``` - -- `for` es la palabra reservada -- `variable` es el nombre de la variable que se usará para iterar -- `in` es la palabra reservada de pertenencia -- `secuencia` es la secuencia de elementos -- `:` es el delimitador de inicio del ciclo -- `print(variable)` es el código a ejecutar posee un nivel de indentación - ---- -Cuando se itera sobre una secuencia es común nombrar las variables con nombres que representen el elemento - -```python -for fruta in ['🍎','🍌','🍇','🍉']: - print(fruta) -``` - -```text -🍎 -🍌 -🍇 -🍉 -``` - ---- -Ejemplo 5, imprimir los elementos de una lista fiestas - -```python [1-2|3-4] -print ("Ejemplo 5") -fiesta = ['🎄','🎆','🎁','🎊','✨','🧨'] -for objeto in fiesta: - print(objeto) -``` - -```text -Ejemplo 5 -🎄 -🎆 -🎁 -🎊 -✨ -🧨 -``` - -Al iterar una lista se obtiene los elementos de la lista - ---- -Ejemplo 6, imprimir los elementos de una tupla de frutas separados por coma - -```python [1-2|3-4] -print ("Ejemplo 6") -frutas = ('🍅','🍇','🍈','🍉','🍊') -for fruta in frutas: - print(fruta, end=", ") -``` - -```text -Ejemplo 6 -🍅, 🍇, 🍈, 🍉, 🍊, -``` - -Al iterar una tupla se obtiene los elementos - ---- -Ejemplo 7, imprimir los elementos de un diccionario - -```python [1-2|3-4] -print ("Ejemplo 7") -frutas = {'🍅':'Tomate','🍇':'Uva','🍈':'Melón','🍉':'Sandía','🍊':'Naranja'} -for clave in frutas: - print(clave, frutas[clave]) -``` - -```text -Ejemplo 7 -🍅 Tomate -🍇 Uva -🍈 Melón -🍉 Sandía -🍊 Naranja -``` - -Al iterar un diccionario devuelve las claves - ---- - -Ejemplo 8, imprimir los elementos del ciclo de vida de un pollo con flechas - -```python [1-2|3-4] -print ("Ejemplo 8") -ciclo_vida = '🥚🐣🐥🐤🐔🍗' -for etapa in ciclo_vida: - print(etapa, end="->") -``` - -```text -Ejemplo 8 -🥚->🐣->🐥->🐤->🐔->🍗-> -``` - ---- -Se puede recorrer elementos con indexación como listas y tuplas de 3 formas - -- Mediante `in` como pertenencia -- Mediante `len()` y `range()` -- Mediante `enumerate()` - ---- -Mediante `in` - -Ejemplo 9, Listar los elementos de la siguiente serie ['🐶','🐱','🐰','🐭'] - -```python [1-2|3-4] -print ("Ejemplo 9") -animales = ['🐶','🐱','🐰','🐭'] -for animal in animales: - print(animal) -``` - -```text -Ejemplo 9 -🐶 -🐱 -🐰 -🐭 -``` - ---- -Mediante `len()` y `range()` - -Ejemplo 10, Listar los elementos de la siguiente serie ['🐶','🐱','🐰','🐭'] - -```python [1-2|3-4] -print ("Ejemplo 10") -animales = ['🐶','🐱','🐰','🐭'] -for i in range(len(animales)): - print(animales[i]) -``` - -```text -Ejemplo 10 -🐶 -🐱 -🐰 -🐭 -``` - ---- -Mediante `enumerate()` - -Primero veremos la función `enumerate()` - -Es una función que devuelve un objeto enumerado que contiene pares de índices y valores como tuplas - -```python -enumerate(['🐶','🐱','🐰','🐭']) -``` -```text -(0, '🐶'), (1, '🐱'), (2, '🐰'), (3, '🐭') -``` - -Nos permite recorrer una secuencia y obtener el índice y el valor en cada iteración - ---- -Ejemplo 11, Listar los elementos de la siguiente serie ['🐶','🐱','🐰','🐭'] - -```python [1-2|3-4] -print ("Ejemplo 11") -animales = ['🐶','🐱','🐰','🐭'] -for i, animal in enumerate(animales): - print(i, animal, animales[i]) -``` - -```text -Ejemplo 11 -0 🐶 🐶 -1 🐱 🐱 -2 🐰 🐰 -3 🐭 🐭 -``` - ---- -Ejercicio 2, imprimir la cantidad de veces los elementos de la cadena '⚽🏀🏐🎱' de acuerdo a su posición más 1 - -```text -⚽ -🏀🏀 -🏐🏐🏐 -🎱🎱🎱🎱 -``` - -3 minutos - - - ---- - -```python -print ("Ejercicio 2") -esferas = '⚽🏀🏐🎱' -for i, esfera in enumerate(esferas): - print(esfera*(i+1)) -``` - -```text -Ejercicio 2 -⚽ -🏀🏀 -🏐🏐🏐 -🎱🎱🎱🎱 -``` - ---- -##### While - -El ciclo `while` es un ciclo que se ejecuta mientras una condición sea verdadera - -Es como un ciclo `for` pero no se sabe cuantas veces se ejecutará - -Similar a un `if` pero se ejecuta varias veces - ---- -Visualmente - -![Ciclo WHILE](./img/WHILE-W.gif) - ---- -La estructura de control `while` es la siguiente - -```python -while condicion: - print("Código a ejecutar") -``` - -- `while` es la palabra reservada -- `condicion` es la expresión que se evaluará tiene que ser `True` o `False` -- `:` es el delimitador de inicio del ciclo -- `print("Código a ejecutar")` es el código a ejecutar posee un nivel de indentación -- `condicion` se evalúa en cada iteración - ---- -Ejemplo 12, imprimir los números mientras sean menores o igual a 5 empezando desde 0 - -```python [1-2|3|4|5] -print ("Ejemplo 12") -i = 0 -while i <= 5: - print(i) - i += 1 -``` - -```text -Ejemplo 12 -0 -1 -2 -3 -4 -5 -``` - ---- -Ejemplo 13, sumar los números mientras no se ingrese por teclado el número 0 - -```python [1-3|4|5-6|7] -print ("Ejemplo 13") -suma = 0 -numero = int(input("Ingrese un número: ")) -while numero != 0: - suma += numero - numero = int(input("Ingrese un número: ")) -print(suma) -``` - -```text -Ejemplo 13 -Ingrese un número: 5 -Ingrese un número: 3 -Ingrese un número: 2 -Ingrese un número: 0 -10 -``` - ---- -Ejercicio 3, Ingresa un número por teclado y genera un contador hasta 0, si el número es negativo no hace nada - -2 minutos - - - ---- -```python [1-2|3-5] -print ("Ejercicio 3") -numero = int(input("Ingrese un número: ")) -while numero >= 0: - print(numero) - numero -= 1 -``` - -```text -Ejercicio 3 -Ingrese un número: 5 -5 -4 -3 -2 -1 -0 -``` - ---- -##### Break - -La sentencia `break` es una palabra reservada que se usa para salir de un ciclo - ---- - -Termina el ciclo actual y ejecuta la siguiente instrucción después del ciclo - -Es útil para salir de un ciclo cuando se cumple una condición antes de que termine el ciclo - - ---- -Ejemplo 14, De la siguiente lista de frutas imprimir los elementos hasta que se encuentre un gusano `🐛` con `for` - -```python [1-2|3|4-6|7] -frutas = ['🍎','🍌','🍇','🍉','🍊','🐛','🍋','🍍'] -print ("Ejemplo 14") -for fruta in frutas: - if fruta == '🐛': - break - print(fruta) -print ("Fin") -``` - -```text -Ejemplo 14 -🍎 -🍌 -🍇 -🍉 -🍊 -Fin -``` - ---- -Con `while` - -```python [1-3|4|5-6|7] -frutas = ['🍎','🍌','🍇','🍉','🍊','🐛','🍋','🍍'] -print ("Ejemplo 14") -i = "" -while i != '🐛': - i = frutas.pop(0) - print(i) -print ("Fin") -``` - -```text -Ejemplo 14 -🍎 -🍌 -🍇 -🍉 -🍊 -🐛 -Fin -``` - ---- -##### Ciclos infinitos - -Un ciclo infinito es un ciclo que no tiene una condición de salida - -Se ejecuta indefinidamente hasta que se detiene manualmente con `Ctrl+C` - -o mediante un `break` - ---- -Se puede usar para ejecutar tareas en segundo plano - -Un mal uso de un ciclo infinito puede hacer que el programa se bloquee - ---- -Ejemplo 15, Crear un ciclo infinito que imprima un contador incremental - -```python [1-2|3|4-5] -print ("Ejemplo 15") -contador = 0 -while True: - print(contador) - contador += 1 -``` - -```text -Ejemplo 15 -0 -1 -2 -... -37310 -... -Ctrl+C -Traceback (most recent call last): - File "", line 2, in -KeyboardInterrupt -``` - ---- -Ejemplo 16, Crear un ciclo infinito que pida una cadena de texto la ponga en mayúsculas y la imprima hasta que se ingrese la palabra `salir` - -```python [1|2|3-6|7] -print ("Ejemplo 16") -while True: - texto = input("Ingrese un texto: ") - if texto == 'salir': - break - print(texto.upper()) -print ("Fin") -``` - -```text -Ejemplo 16 -Ingrese un texto: Python -PYTHON -Ingrese un texto: La Paz -LA PAZ -Ingrese un texto: salir -Fin -``` - ---- -Ejercicio 4, Crear un ciclo infinito que reciba un número por teclado y verifique si es par o impar hasta que se ingrese el número 0 - -3 minutos - - - ---- -```python -print ("Ejercicio 4") -while True: - numero = int(input("Ingrese un número: ")) - if numero == 0: - break - print ("Par" if numero % 2 == 0 else "Impar") -``` - -```text -Ejercicio 4 -Ingrese un número: 5 -Impar -Ingrese un número: 4 -Par -Ingrese un número: 0 -``` - ---- -##### Estructuras por comprensión - -Las Estructuras por comprensión son una forma de crear estructuras de manera concisa utilizando una sola línea de código - -Utiliza la estructura de un ciclo `for` y se puede agregar condicionales - -Se puede crear listas, tuplas, diccionarios y conjuntos - ---- -Estructura de una lista por comprensión - -```python -[expresion for variable in secuencia] -``` - -- `expresion` es la expresión que se evaluará -- `for` es la palabra reservada -- `variable` es el nombre de la variable que se usará para iterar -- `in` es la palabra reservada de pertenencia -- `secuencia` es la secuencia de elementos -- `[` y `]` son los delimitadores de la lista - ---- -Estructura de una lista por comprensión y condicional - -```python -[expresion for variable in secuencia if condicion] -``` - -- `expresion` es la expresión que se evaluará -- `for` es la palabra reservada -- `variable` es el nombre de la variable que se usará para iterar -- `in` es la palabra reservada de pertenencia -- `secuencia` es la secuencia de elementos -- `if` es la palabra reservada de condición -- `condicion` es la expresión que se evaluará -- `[` y `]` son los delimitadores de la lista - ---- -Ejemplo 17, Crear una lista de los números pares del 2 al 10 - -```python [1|2|3] -print ("Ejemplo 17") -pares = [i for i in range(2, 11, 2)] -print(pares) -``` - -```text -Ejemplo 17 -[2, 4, 6, 8, 10] -``` - ---- -Ejemplo 18, Crear una lista de los números pares del 2 al 10 con condicional - -```python [1|2|3] -print ("Ejemplo 18") -pares = [i for i in range(2, 11) if i % 2 == 0] -print(pares) -``` - -```text -Ejemplo 18 -[2, 4, 6, 8, 10] -``` - ---- -Ejemplo 19, Crear un diccionario números 2 al 10 donde si es par vale "Par" y si es impar valga "Impar" - -```python [1|2|3] -print ("Ejemplo 19") -pares = {i: "Par" if i % 2 == 0 else "Impar" for i in range(2, 11)} -print(pares) -``` - -```text -Ejemplo 19 -{2: 'Par', 3: 'Impar', 4: 'Par', 5: 'Impar', - 6: 'Par', 7: 'Impar', 8: 'Par', 9: 'Impar', 10: 'Par'} -``` - ---- -Ejercicio 5, Crear una tupla de los números impares del 1 al 10 usando una tupla por comprensión - -2 minutos - - - ---- -```python -print ("Ejercicio 5") -impares = tuple(i for i in range(1, 11) if i % 2 != 0) -print(impares) -``` - -```text -Ejercicio 5 -(1, 3, 5, 7, 9) -``` - ---- -##### Ciclos anidados - -Son ciclos dentro de otros ciclos - -Se pueden anidar ciclos `for` y `while` - ---- -Visualmente - -![Ciclo ANIDADO](./img/ANIDADO-W.gif) - - ---- -Ejemplo 20, Imprimir las tablas de multiplicar del 1 y 2 - -```python [1|2-3|4-5] -print ("Ejemplo 20") -for i in range(1, 3): - print(f"Tabla del {i}") - for j in range(1, 11): - print(f"{i} x {j} = {i*j}") -``` - -```text -Tabla del 1 -1 x 1 = 1 -1 x 2 = 2 -1 x 3 = 3 -1 x 4 = 4 -1 x 5 = 5 -1 x 6 = 6 -1 x 7 = 7 -1 x 8 = 8 -1 x 9 = 9 -1 x 10 = 10 -Tabla del 2 -2 x 1 = 2 -2 x 2 = 4 -2 x 3 = 6 -2 x 4 = 8 -2 x 5 = 10 -2 x 6 = 12 -2 x 7 = 14 -2 x 8 = 16 -2 x 9 = 18 -2 x 10 = 20 -``` - ---- -Ejemplo 21, Introducir un número por teclado y crear una tabla de multiplicar de ese número del 1 al 10, si se ingresa 0 termina el programa - -```python [1|2|3|4-5|6|7-8|9] -print ("Ejemplo 21") -while True: - numero = int(input("Ingrese un número: ")) - if numero == 0: - break - print(f"Tabla del {numero}") - for i in range(1, 11): - print(f"{numero} x {i} = {numero*i}") -print ("Fin") -``` - -```text -Ejemplo 21 -Ingrese un número: 5 -Tabla del 5 -5 x 1 = 5 -... -5 x 10 = 50 -Ingrese un número: 0 -Fin -``` - ---- -Una matriz es una lista de listas que se puede recorrer con ciclos anidados - -Las matrices nos sirven para representar datos en dos dimensiones - -Son útiles para representar tablas, imágenes, mapas, etc. - ---- - -```python -matriz = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] -for fila in matriz: - for columna in fila: - print(columna, end=" ") - print() -``` - -```text -1 2 3 -4 5 6 -7 8 9 -``` - ---- -Ejemplo 22, Introducir un número por teclado y crear una matriz nxn con la letra X - -```python -print ("Ejemplo 22") -n = int(input("Ingrese un número: ")) -matriz = [['X' for i in range(n)] for j in range(n)] -for fila in matriz: - for columna in fila: - print(columna, end=" ") - print() -print (matriz) -``` - -```text -Ejemplo 22 -Ingrese un número: 5 -X X X X X -X X X X X -X X X X X -X X X X X -X X X X X -[['X', 'X', 'X', 'X', 'X'], ['X', 'X', 'X', 'X', 'X'], ['X', 'X', 'X', 'X', 'X'], ['X', 'X', 'X', 'X', 'X'], ['X', 'X', 'X', 'X', 'X']] -``` - ---- -Ejercicio 6, Crear una matriz ingresando un número por teclado para el tamaño de la matriz y en cada posición colocar una tupla con (i, j) - -4 minutos - - - ---- -```python -print ("Ejercicio 6") -n = int(input("Ingrese un número: ")) -matriz = [[(j, i) for i in range(n)] for j in range(n)] -for fila in matriz: - for columna in fila: - print(columna, end=" ") - print() -print (matriz) -``` - -```text -Ejercicio 6 -Ingrese un número: 4 -(0, 0) (0, 1) (0, 2) (0, 3) -(1, 0) (1, 1) (1, 2) (1, 3) -(2, 0) (2, 1) (2, 2) (2, 3) -(3, 0) (3, 1) (3, 2) (3, 3) -[[(0, 0), (0, 1), (0, 2), (0, 3)], [(1, 0), (1, 1), (1, 2), (1, 3)], [(2, 0), (2, 1), (2, 2), (2, 3)], [(3, 0), (3, 1), (3, 2), (3, 3)]] -``` - ---- -##### Resumen Sentencias iterativas - -- Las estructuras de control permiten tomar decisiones o repetir instrucciones -- Las sentencias iterativas son ciclos que permiten repetir instrucciones -- Los ciclos `for` se utilizan para recorrer secuencias -- Los ciclos `while` se utilizan para repetir instrucciones mientras una condición sea verdadera - ---- -- La sentencia `break` se utiliza para salir de un ciclo -- `range()` se utiliza para generar una secuencia de números -- Se puede recorrer mediante rangos o secuencias -- Las listas por comprensión son una forma de crear listas de manera concisa - ---- -- `enumerate()` se utiliza para obtener el índice y el valor de una secuencia -- `enumerate()` devuelve un objeto enumerado que contiene pares de índices y valores como tuplas - ---- -- Los ciclos anidados son ciclos dentro de otros ciclos -- Las matrices son listas de listas que se pueden recorrer con ciclos anidados -- Los ciclos infinitos son ciclos que no tienen una condición de salida -- Los ciclos infinitos se pueden detener con `break` o `Ctrl+C` - ---- -- Las variables definidas en un ciclo existen dentro del ciclo -- No se recomienda usar las variables del ciclo fuera del ciclo - ---- - -![Ciclo FOR](./img/FOR-W.gif) -![Ciclo WHILE](./img/WHILE-W.gif) -![Ciclo ANIDADO](./img/ANIDADO-W.gif) - ---- -##### Retos - -Crear una carpeta con el nombre "retos_sesion_13" en la cual por cada ejercicio debe crear un script de python - -```bash -# Ejemplo carpeta -psg-example/ - retos_sesion_13/ - ejercicio_01.py - ejercicio_02.py - ejercicio_03.py - ejercicio_04.py - ejercicio_05.py - ejercicio_06.py - ejercicio_07.py - sesion13.ipynb -``` - -Subir la carpeta a su repositorio en GitHub cuando termine los retos - ---- -1. Imprimir los 20 primeros números de la sucesión de Lucas. - ---- -1. Imprimir los 20 primeros números que sean múltiplos de 2 y 5. - ---- -1. De la siguiente tupla de estudiantes, imprime las felicitaciones a los estudiantes que aprobaron el curso con una nota mayor o igual a 51 - -```python -estudiantes = [('Miguel', 51), ('Daniel', 80), ('Virginia', 90), ('Franco', 40), ('Flabio', 30)] -``` - ---- -1. Crea un ciclo infinito que reciba una frase por teclado y verifique si la frase es palíndromo. La ejecución termina si la frase ingresada contiene la palabra `salir` - ---- -5. Imprimir un tablero de ajedrez de 8x8 con los caracteres `#` y `*` - ---- -1. Crea un ciclo infinito que reciba un número por teclado y verifique si el número es múltiplo de 7. La ejecución termina si se ingresa el número 0 - ---- -7. Crear una serie de números del 1 al 100, si el número es divisible entre 5 imprimir `Fizz`, si el número es divisible entre 7 imprimir `Buzz`, si el número es divisible entre 5 y 7 imprimir `FizzBuzz` - ---- -8. Convertir y ejecutar el archivo de la "sesion13.py" a un Jupyter Notebook - ---- - - -
-
-
-
-
- -[![GitHub](../../content/github_logo.png) ](https://github.com/python-la-paz/python-study-group-fundamentals/tree/main/content/sesion13) - -Repositorio de la Sesión - ---- - -## Bibliografía y Referencias - -- [Python Learn](https://do1.dr-chuck.com/pythonlearn/ES_es/pythonlearn.pdf) -- [Range](https://docs.python.org/3/library/stdtypes.html#range) -- [For Statements](https://docs.python.org/3/tutorial/controlflow.html#for-statements) -- [While](https://docs.python.org/3/tutorial/controlflow.html#the-range-function) -- [While Reference](https://docs.python.org/3/reference/compound_stmts.html#while) -- [Enumerate](https://docs.python.org/3/library/functions.html#enumerate) -- [Break](https://docs.python.org/3/reference/simple_stmts.html#the-break-statement) diff --git a/content/sesion13/img/ANIDADO-W.gif b/content/sesion13/img/ANIDADO-W.gif deleted file mode 100644 index e37d2b8..0000000 Binary files a/content/sesion13/img/ANIDADO-W.gif and /dev/null differ diff --git a/content/sesion13/img/FOR-W.gif b/content/sesion13/img/FOR-W.gif deleted file mode 100644 index a235cad..0000000 Binary files a/content/sesion13/img/FOR-W.gif and /dev/null differ diff --git a/content/sesion13/img/WHILE-W.gif b/content/sesion13/img/WHILE-W.gif deleted file mode 100644 index f1286ae..0000000 Binary files a/content/sesion13/img/WHILE-W.gif and /dev/null differ diff --git a/content/sesion13/index.html b/content/sesion13/index.html deleted file mode 100644 index 1957c14..0000000 --- a/content/sesion13/index.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - Sesión 13 | Python Study Group | Fundamentals - - - - - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/content/sesion14/Readme.md b/content/sesion14/Readme.md deleted file mode 100644 index d80dd12..0000000 --- a/content/sesion14/Readme.md +++ /dev/null @@ -1,1375 +0,0 @@ - -![Python La paz](../Logo.png) - -
-
-
- - -### Sesión 14 -### Funciones -### Bloques de código - ---- -##### ¿Qué es una función? - ---- -Una función es un bloque de código que realiza una tarea específica - -Se le asigna un nombre y se puede llamar en cualquier parte del programa - -Solo se ejecuta cuando se llama por su nombre - ---- -Permite dividir un programa en bloques de código más pequeños - -Facilita la lectura y mantenimiento del código - -Permite reutilizar el código - ---- -Visualmente - -![FUNCIÓN DEVOLVER](./img/FUNCION-DEVOLVER-W.gif) -![FUNCIÓN LLAMAR](./img/FUNCION-LLAMAR-W.gif) - ---- -Hasta el momento hemos utilizado algunas funciones como - -- `print()` -- `input()` -- `len()` -- `max()` -- `min()` -- `sum()` -- `range()` -- `enumerate()` - ---- -También hemos utilizado funciones dentro de tipos y estructuras de datos con notación de punto - -- `append()` -- `remove()` -- `sort()` -- `upper()` -- `lower()` - ---- -##### ¿Cómo se declara una función? - -Para definir un bloque de código como función se utiliza la palabra reservada `def` - -```python -def nombre_funcion(): - print ("Bloque de código") -``` - -- `def` es la palabra reservada -- `nombre_funcion` es el nombre de la función -- `()` son los paréntesis que pueden contener parámetros -- `:` es el delimitador de inicio del bloque de código -- `print` es el código a ejecutar -- Posee un nivel de indentación - ---- -Una función puede recibir argumentos de entrada - -Una función puede no devolver ningún valor - -Una función puede devolver un valor o varios valores - ---- -Para devolver un valor se utiliza la palabra reservada `return` seguida del valor a devolver - -```python -def nombre_funcion(): - return "Bloque de código" -``` - ---- -Se llama a una función utilizando su nombre seguido de paréntesis y los argumentos si los tiene - -```python -def nombre_funcion(): - print ("Bloque de código") - -nombre_funcion() -print (type(nombre_funcion)) -``` - -```text -Bloque de código - -``` - ---- -##### Funciones según PEP-8 - -- Los nombres de las funciones deben ser en minúsculas y separados por guiones bajos -- Los nombres de las funciones deben ser descriptivos - ---- -##### Ejecución de una función - ---- -Crearemos un archivo con el nombre sesion14.py - -Empezaremos a escribir funciones - ---- - -Las funciones se deben definir antes de ser llamadas - -```python [1-2|4] -def nombre_funcion(): - print ("Bloque de código") - -nombre_funcion() -``` - -```text -Bloque de código -``` -Se genera un error si se llama a una función que no ha sido definida - -```python [1|3-4] -nombre_funcion() - -def nombre_funcion(): - print ("Bloque de código") -``` - -```text -NameError: name 'nombre_funcion' is not defined -``` - - ---- -##### Funciones sin argumentos y sin retorno - -- No esta definido ningún parámetro -- No recibe argumentos de entrada -- No devuelve ningún valor - -```python [1-2|4] -def funcion(): - print ("Bloque de código") - -funcion() -``` - -```text -Bloque de código -``` - ---- -Ejemplo 1, Crear una función para imprimir una lista de 10 números pares y llamarla dos veces - -```python [1-2|3-5|7-9] -print ("Ejemplo 1") -print ("1. Definir función") -def imprimir_pares(): - pares = [i for i in range(0, 21, 2)] - print (pares) - -print ("2. Llamar función") -imprimir_pares() -imprimir_pares() -``` - -```text -Ejemplo 1 -1. Definir función -2. Llamar función -[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20] -[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20] -``` - ---- -Ejercicio 1, crear una función que imprima un mensaje de bienvenida del siguiente conjunto de forma aleatoria - -```python -mensajes = {"Bienvenido al Python Study Group 🐍", -"¡Hola y bienvenido al Python Study Group! ✨", -"Hola, aprendamos Python juntos 🐍"} -``` - -2 minutos - - - ---- -Solución 1 - -```python -def bienvenida(): - mensajes = {"Bienvenido al Python Study Group 🐍", - "¡Hola y bienvenido al Python Study Group! ✨", - "Hola, aprendamos Python juntos 🐍"} - print (mensajes.pop()) - -bienvenida() -``` - -```text -Bienvenido al Python Study Group 🐍 -``` - ---- -##### Funciones sin argumentos y con un retorno - -- No esta definido ningún parámetro -- No recibe argumentos de entrada -- Devuelve un valor - -```python [1-2|4-5] -def funcion(): - return "Bloque de código" - -resultado = funcion() -print (resultado) -``` - -```text -Bloque de código -``` - ---- -Ejemplo 2, Crear una función que devuelva un saludo en diferentes idiomas - -```python [1-2|3-5|7-9] -print ("Ejemplo 2") -print ("1. Definir función") -def saludo(): - saludos = {"Hola", "Hello", "Bonjour", "Ciao"} - return saludos.pop() - -print ("2. Llamar función") -resultado = saludo() -print (resultado) -``` - -```text -Ejemplo 2 -1. Definir función -2. Llamar función -Bonjour -``` - ---- -Ejercicio 2, Devolver una fruta aleatoria del siguiente conjunto - -```python -frutas = {'🍅','🍌','🍎','🍇','🍉'} -``` - -2 minutos - - - ---- -Solución 2 - -```python -def devolver_fruta(): - frutas = {'🍅','🍌','🍎','🍇','🍉'} - return frutas.pop() - -fruta = devolver_fruta() -print (fruta) -``` - -```text -🍎 -🍇 -``` - ---- -##### Funciones sin argumentos y con múltiple retorno - -- No recibe argumentos de entrada -- Devuelve múltiples valores -- Devuelve una tupla en Python - -```python -def funcion(): - return "Bloque", "de", "código" - -resultado = funcion() -print (resultado) -``` - -```text -('Bloque', 'de', 'código') -``` - ---- -Ejemplo 3, Crear una función que devuelva un saludo en dos idiomas - -```python [1-2|3-6|8-10] -print ("Ejemplo 3") -print ("1. Definir función") -def saludo(): - saludos_es = {"Hola", "Holi", "Buenos días"} - saludos_en = {"Hello", "Hi", "Good morning"} - return saludos_es.pop(), saludos_en.pop() - -print ("2. Llamar función") -resultado = saludo() -print (resultado) -``` - -```text -Ejemplo 3 -1. Definir función -2. Llamar función -('Hola', 'Good morning') -``` - ---- -Ejercicio 3, Devolver una fruta y un color aleatorio de los siguientes conjuntos - -```python -frutas = {'🍅','🍌','🍎','🍇','🍉'} -colores = {'🔴','🟠','🟡','🟢','🔵'} -``` - -2 minutos - - - ---- -Solución 3 - -```python -def devolver_fruta_color(): - frutas = {'🍅','🍌','🍎','🍇','🍉'} - colores = {'🔴','🟠','🟡','🟢','🔵'} - return frutas.pop(), colores.pop() - -fruta, color = devolver_fruta_color() -print (fruta, color) -``` - -```text -🍎 🔵 -``` - ---- -##### Funciones con un argumento y sin retorno - -- Tiene definido un parámetro de entrada -- Recibe un argumento de entrada -- No devuelve ningún valor - -```python -def funcion(parametro): - print (parametro) - -funcion("Bloque de código") #1 Argumento -``` - -```text -Bloque de código -``` - -El parámetro es una variable de la función puede ser de cualquier tipo - -Números, cadenas, listas, diccionarios, tuplas, conjuntos, etc. - ---- -Ejemplo 4, Crear una función que imprima el cuadrado de un número - -```python [1-2|3-4|6-8] -print ("Ejemplo 4") -print ("1. Definir función") -def cuadrado(numero): - print (numero**2) - -print ("2. Llamar función") -cuadrado(5) -cuadrado(10) -``` - -```text -Ejemplo 4 -1. Definir función -2. Llamar función -25 -100 -``` - ---- -Ejercicio 4, Crear una función que imprima el mensaje de bienvenida de acuerdo al un idioma enviado como argumento, si no existe imprimir un mensaje por defecto - -```python -mensajes = {"es":"Bienvenido al Python Study Group 🐍", -"en": "Hello and welcome to the Python Study Group! ✨", -} -``` - -2 minutos - - - ---- -Solución 4 - -```python -def bienvenida(idioma): - mensajes = { - "es":"Bienvenido al Python Study Group 🐍", - "en": "Hello and welcome to the Python Study Group! ✨", - } - print (mensajes.get(idioma, "¡Hola!")) - -bienvenida("es") -bienvenida("en") -bienvenida("fr") -``` - -```text -Bienvenido al Python Study Group 🐍 -Hello and welcome to the Python Study Group! ✨ -¡Hola! -``` - ---- -##### Funciones con múltiples argumentos y sin retorno - -- Tiene definido múltiples parámetros de entrada -- Recibe múltiples argumentos de entrada separados por coma -- No devuelve ningún valor -- Los argumentos son variables de la función -- El orden de los argumentos debe coincidir con los parámetros - -```python -def funcion(param1, param2, ..., paramN): - print (param1, param2, ..., paramN) - -funcion("Bloque", "de", "código") -``` - -```text -Bloque de código -``` - -Los parámetros definidos pueden ser de cualquier tipo y cantidad - ---- -Ejemplo 5, Crear una función que reciba una cadena y un entero y repita la cadena el número de veces - -```python [1-2|3-4|6-7] -print ("Ejemplo 5") -print ("1. Definir función") -def repetir(cadena, veces): - print (cadena*veces) - -print ("2. Llamar función") -repetir("✨🎉", 10) -``` - -```text -Ejemplo 5 -1. Definir función -2. Llamar función -✨🎉✨🎉✨🎉✨🎉✨🎉✨🎉✨🎉✨🎉✨🎉✨🎉✨🎉 -``` - ---- -Ejercicio 5, Crear una función que reciba una lista de animales, un entero e imprima una lista con los animales repetidos el número de veces - -```python -# Entrada -animales = ['🐶','🐱','🐭','🐹','🐰'] -# Salida -animales = ['🐶🐶🐶', '🐱🐱🐱', '🐭🐭🐭', '🐹🐹🐹', '🐰🐰🐰'] -``` - -2 minutos - - - ---- -Solución 5 - -```python -def repetir_animales(animales, veces): - lista = [animal*veces for animal in animales] - print (lista) - -animales = ['🐶','🐱','🐭','🐹','🐰'] -repetir_animales(animales, 3) - -print (resultado) -``` - -```text -['🐶🐶🐶', '🐱🐱🐱', '🐭🐭🐭', '🐹🐹🐹', '🐰🐰🐰'] -``` - ---- -##### Funciones con múltiples argumentos y con un retorno - -- Tiene definido múltiples parámetros de entrada -- Recibe múltiples argumentos de entrada separados por coma -- Devuelve un valor -- El orden de los argumentos debe coincidir con los parámetros - -```python -def funcion(param1, param2, paramN): - return param1 - -resultado = funcion("Bloque", "de", "código") -print (resultado) -``` - -```text -'Bloque' -``` - ---- -Ejemplo 6, Crear una función que reciba dos números y devuelva una lista con la suma, resta, multiplicación y división de los números - -```python [1-2|3-8|10-12] -print ("Ejemplo 6") -print ("1. Definir función") -def operaciones(numero1, numero2): - suma = numero1 + numero2 - resta = numero1 - numero2 - multiplicacion = numero1 * numero2 - division = numero1 / numero2 - return [suma, resta, multiplicacion, division] - -print ("2. Llamar función") -resultado = operaciones(10, 5) -print (resultado) -``` - -```text -Ejemplo 6 -1. Definir función -2. Llamar función -[15, 5, 50, 2.0] -``` - ---- -Ejercicio 6, Crear una función que reciba dos enteros y una cadena devolver el resultado de la operación de los números según la cadena puede ser suma, resta, multiplicación o división - -3 minutos - - - ---- -Solución 6 - -```python -def operacion(numero1, numero2, operacion): - if operacion == "suma": - return numero1 + numero2 - elif operacion == "resta": - return numero1 - numero2 - elif operacion == "multiplicacion": - return numero1 * numero2 - elif operacion == "division": - return numero1 / numero2 - else: - return "Operación no válida" - -resultado = operacion(10, 5, "suma") -print (resultado) -``` - -```text -15 -``` - ---- -##### Funciones con múltiples argumentos y con múltiple retorno - -- Tiene definido múltiples parámetros de entrada -- Recibe múltiples argumentos de entrada separados por coma -- Devuelve múltiples valores -- Devuelve una tupla en Python - -```python -def funcion(param1, param2, ..., paramN): - return param1, param2, ..., paramN - -resultado = funcion("Bloque", "de", "código") -print (resultado) -``` - -```text -('Bloque', 'de', 'código') -``` - ---- -Ejemplo 7, Crear una función que reciba dos números y devuelva la suma, resta, multiplicación y división de los dos números - -```python [1-2|3-9|11-13] -print ("Ejemplo 7") -print ("1. Definir función") -def operaciones(numero1, numero2): - suma = numero1 + numero2 - resta = numero1 - numero2 - multiplicacion = numero1 * numero2 - division = numero1 / numero2 - return suma, resta, multiplicacion, division - -print ("2. Llamar función") -suma, resta, multiplicacion, division = operaciones(10, 5) -print (suma, resta, multiplicacion, division) -``` - -```text -Ejemplo 7 -1. Definir función -2. Llamar función -15 5 50 2.0 -``` - ---- -Ejercicio 7, Crear una juego de piedra papel o tijera, donde reciba dos jugadas por teclado - -y devuelva las jugadas y el resultado, si ingresa salir terminar el juego - -3 minutos - - - ---- -Solución 7 - -```python -def jugar_piedra_papel_tijera(jugada1, jugada2): - if jugada1 == jugada2: - resultado = "Empate" - elif jugada1 == "piedra" and jugada2 == "tijera": - resultado = "Jugador 1 gana" - elif jugada1 == "papel" and jugada2 == "piedra": - resultado = "Jugador 1 gana" - elif jugada1 == "tijera" and jugada2 == "papel": - resultado = "Jugador 1 gana" - else: - resultado = "Jugador 2 gana" - return jugada1, jugada2, resultado - -while True: - jugador1 = input("Jugador 1: ") - if jugador1 == "salir": - break - jugador2 = input("Jugador 2: ") - if jugador2 == "salir": - break - resultado = jugar_piedra_papel_tijera(jugador1, jugador2) - print (resultado) -``` - -```text -Jugador 1: piedra -Jugador 2: papel -('piedra', 'papel', 'Jugador 2 gana') -Jugador 1: salir -``` - ---- -##### Variables globales y locales - -- Las variables globales son accesibles desde cualquier parte del programa -- Las variables locales son accesibles solo dentro de un bloque de código como una función -- Si hay una variable local y una global con el mismo nombre, la variable local tendrá prioridad donde está definida - ---- - -```python -variable_global = "Variable global" - -def funcion(): - variable_local = "Variable local" - print ("✨",variable_global) - print ("✨",variable_local) - -funcion() -print ("🎈",variable_global) -print ("🎈",variable_local) -``` - -```text -✨ Variable global -✨ Variable local -🎈 Variable global -NameError: name 'variable_local' is not defined -``` - ---- -Prioridad - -```python -variable = "Variable global" -print ('0.',variable) - -def funcion(): - variable = "Variable local" - print ('1.',variable) - -funcion() -print ('2.',variable) -``` - -```text -0. Variable global -1. Variable local -2. Variable global -``` - ---- -Ejemplo 8, De la siguiente lista de números obtener el mayor y menor número con una función - -```python -numeros = [10, 5, 20, 15, 25, 30] #Global - -def mayor_menor(): #No recibe argumentos - mayor = max(numeros) #Local - menor = min(numeros) #Local - return mayor, menor #Devuelve dos valores - -resultado = mayor_menor() -print (resultado) -``` - -```text -(30, 5) -``` - ---- -Ejercicio 8, De la siguiente cadena global convertir en formato título y contar las vocales `aeiou` con una función - -```python -cadena = "python es un lenguaje de programación" -``` - -2 minutos - - - ---- -Solución 8 - -```python -def formato_vocales(): - titulo = cadena.title() - vocales = sum([1 for letra in titulo if letra in "aeiou"]) - return titulo, vocales - -cadena = "python es un lenguaje de programación" -resultado = formato_vocales() - -print (resultado) -``` - -```text -('Python Es Un Lenguaje De Programación', 10) -``` - ---- -##### Args y Kwargs - -- `*args` es una lista de parámetros sin clave -- `**kwargs` es un diccionario de parámetros con clave - ---- -##### Args - -- Los argumentos utilizando `*args` son enviados como una tupla -- Los `*args` se escriben después de los parámetros de la función -- Se utiliza cuando no se sabe la cantidad de argumentos que se enviarán -- Pueden ser iterados - ---- -Estructura de `*args` - - -```python -def funcion(*args): - print (args) - print (type(args)) - -funcion("Bloque", "de", "código") -``` - -```text -('Bloque', 'de', 'código') -``` - ---- -Ejemplo 9 Crear una función que reciba un número y una cantidad de cadenas, concatene las cadenas y la devuelva repetida N veces - -```python [1-2|3-7|9-11] -print ("Ejemplo 9") -print ("1. Definir función") -def concatenar(numero, *cadenas): - concatenado = "" - for cadena in cadenas: - concatenado += cadena - return concatenado*numero - -print ("2. Llamar función") -resultado = concatenar(3, "🍎", "🍌", "🍍") -print (resultado) -``` - -```text -Ejemplo 9 -1. Definir función -2. Llamar función -'🍎🍌🍍🍎🍌🍍🍎🍌🍍' -``` - ---- -Ejercicio 9, Crear una función que reciba N objetos y genere una tupla y una lista con los objetos usando `*args` - -```python -1, 1.1, True, "🍎" -``` - -2 minutos - - - ---- -Solución 9 - -```python -def tupla_lista(*args): - tupla = tuple(args) - lista = list(args) - return tupla, lista - -lista, tupla = tupla_lista(1, 1.1, True, "🍎") - -print (lista) -print (tupla) -``` - -```text -[1, 1.1, True, '🍎'] -(1, 1.1, True, '🍎') -``` - ---- -##### Kwargs - -- Los argumentos utilizando `**kwargs` son enviados como un diccionario -- Los `**kwargs` se escriben después de los parámetros de la función -- Se utiliza cuando no se sabe la cantidad de argumentos que se enviarán con clave -- Pueden ser iterados -- Se accede a los valores con la clave del diccionario - ---- -Estructura de `**kwargs` - -```python -def funcion(**kwargs): - print (kwargs) - print (type(kwargs)) - -funcion(nombre="Jhon", apellido="Doe", genero="M") -``` - -```text -{'nombre': 'Jhon', 'apellido': 'Doe', 'genero': 'M'} - -``` - ---- -Ejemplo 10, Crear una función que reciba los datos de una persona y devuelva un mensaje con los datos - -```python [1-2|3-7|8-10] -print ("Ejemplo 10") -print ("1. Definir función") -def datos_persona(**datos): - mensaje = "" - for clave, valor in datos.items(): - mensaje += f"{str(clave).title()}: {str(valor).upper()}\n" - return mensaje -print ("2. Llamar función") -resultado = datos_persona(nombre="Jhon", apellido="Doe", edad=20, boliviano=True) -print (resultado) -``` - -```text -Ejemplo 10 -1. Definir función -2. Llamar función -Nombre: JHON -Apellido: DOE -Edad: 20 -Boliviano: TRUE -``` - ---- -Ejercicio 10, Crea un simulador de lavar platos con una función que reciba los objetos a lavar y el tiempo de lavado de cada objeto devuelva un mensaje con los objetos lavados y el tiempo total de lavado - -```text -Plato: 5 minutos, Vaso: 3 minutos, Tenedor: 1 minuto, Cuchara: 0.5 minutos -``` - -3 minutos - - - ---- -Solución 10 - -```python -def lavar(**objetos): - tiempo_total = 0 - mensaje = "" - for objeto, tiempo in objetos.items(): - tiempo_total += tiempo - mensaje += f"{objeto}: {tiempo} minutos\n" - mensaje += f"Tiempo total: {tiempo_total} minutos" - return mensaje - -resultado = lavar(plato=5, vaso=3, tenedor=1, cuchara=0.5) -print (resultado) -``` - -```text -plato: 5 minutos -vaso: 3 minutos -tenedor: 1 minutos -cuchara: 0.5 minutos -Tiempo total: 9.5 minutos -``` - ---- -##### Documentación de funciones - -Es importante documentar las funciones para que otros programadores puedan entender su funcionamiento - ---- -- Se puede documentar una función con un comentario de varias líneas -- Se accede con la función `.__doc__` - ---- -Documentación de una función - -```python -def funcion(): - """ - Documentación aquí - """ - print ("Bloque de código") -``` - -- `def funcion():` es la definición de la función -- `"""` es el inicio de la documentación -- `Documentación aquí` es el texto de la documentación -- `"""` es el fin de la documentación -- `print` es el bloque de código indentado - ---- -Acceso a la documentación con `.__doc__` - -```python -print ("Acceso a la documentación") -def funcion(): - """ - Documentación aquí - """ - print ("Bloque de código") -print (funcion.__doc__) -print ("Fin de la ejecución") -``` - -```text -Acceso a la documentación - - Documentación aquí - -Fin de la ejecución -``` - ---- -##### Llamado de funciones dentro de funciones - -- Se pueden llamar funciones dentro de otras funciones -- Se utiliza para dividir una función en bloques de código más pequeños -- Se puede llamar una función dentro de un bucle o condicional - ---- -Visualmente - -![FUNCIÓN ANIDADA](./img/FUNCION-ANIDADA-W.gif) - ---- -Ejemplo 11, Crear tres funciones una principal que reciba un número y dos funciones anidadas que devuelvan el cuadrado y el cubo del número - -```python [1-2|3-6|8-10|12-14|16-19] -print ("Ejemplo 11") -print ("1. Definir función Principal") -def principal(numero): - cuadrado = cuadrado_numero(numero) - cubo = cubo_numero(numero) - return cuadrado, cubo - -print ("2. Definir función Cuadrado") -def cuadrado_numero(numero): - return numero**2 - -print ("3. Definir función Cubo") -def cubo_numero(numero): - return numero**3 - -print ("4. Llamar función Principal") -numero = 5 -resultado = principal(numero) -print (numero, resultado) -``` - ---- -```text -Ejemplo 11 -1. Definir función Principal -2. Definir función Cuadrado -3. Definir función Cubo -4. Llamar función Principal -5 (25, 125) -``` - ---- -Ejercicio 11, Crear funciones de limpieza de una cadena para obtener las letras y convertir todo en mayúsculas crea funciones de limpieza y función una principal - -```python -cadena = "Python es un lenguaje de programación 🎈. Feliz Aprendizaje el 2025" -``` - -3 minutos - - - ---- -Solución 11 - -```python -def limpiar_letras(cadena): - """ - Elimina los números de una cadena y espacios - """ - return "".join([letra for letra in cadena if letra.isalpha()]) -def limpiar_mayusculas(cadena): - """ - Convierte una cadena en mayúsculas - """ - return cadena.upper() - -def limpiar(cadena): - cadena = limpiar_letras(cadena) - cadena = limpiar_mayusculas(cadena) - return cadena - -cadena = "Python es un lenguaje de programación 🎈. Feliz Aprendizaje el 2025" -resultado = limpiar(cadena) -print (cadena) -print (resultado) -``` - -```text -Python es un lenguaje de programación 🎈. Feliz Aprendizaje el 2025 -PYTHONESUNLENGUAJEDEPROGRAMACIÓNFELIZAPRENDIZAJEEL -``` - ---- -##### Funciones Recursivas - -- Una función recursiva es una función que se llama a sí misma -- Se utiliza para reprocesar un bloque de código -- Se debe tener un caso base para evitar un bucle infinito - ---- -Se utiliza para resolver problemas matemáticos, grafos, árboles, etc. - ---- -Visualmente - -![FUNCIÓN RECURSIVA](./img/FUNCION-RECURSIVA-W.gif) - ---- -Estructura de una función recursiva - -```python -def funcion_recursiva(valor): - if caso_base: - return valor - else: - return funcion_recursiva(valor) -``` -- `def funcion_recursiva(valor):` es la definición de la función -- `if caso_base:` es la condición para terminar la recursividad -- `return valor` es el valor a devolver -- `else:` es el bloque de código recursivo -- `return funcion_recursiva(valor)` es la llamada recursiva - ---- -Ejemplo 12, Crear una función recursiva para obtener el 10 número par - -```python [1-2|3-7|7|9-11] -print ("Ejemplo 12") -print ("1. Definir función") -def numero_par(numero): - if numero == 0: - return 0 - else: - return numero_par(numero-1) + 2 - -print ("2. Llamar función") -resultado = numero_par(10) -print (resultado) -``` - -```text -Ejemplo 12 -1. Definir función -2. Llamar función -20 -``` - -```text -2,4,6,8,10,12,14,16,18,[20] -``` - ---- - - ---- -Ejercicio 12, Crear una función recursiva para obtener el factorial de un número - -`$5! = 5*4*3*2*1 = 120$` - -2 minutos - - - ---- -Solución 12 - -```python -def factorial(numero): - if numero == 0: - return 1 - else: - return numero*factorial(numero-1) - -resultado = factorial(5) -print (resultado) -``` - -```text -120 -``` - ---- -##### Funciones anónimas o lambda - -- Una función anónima es una función sin nombre -- Se utiliza para funciones pequeñas y simples -- Se utiliza para funciones que se van a pasar como argumento -- Se realiza en una sola línea -- se puede asignar a una variable - ---- -Se recomienda utilizar para funciones pequeñas y simples - -Según PEP-8 no se recomienda utilizar lambda sino crear una función definida - -Se puede utilizar en funciones como `map`, `filter`, `reduce`, `sorted`, etc. para procesar datos - ---- -Estructura de una función anónima - -```python -lambda argumento: expresión -``` -- `lambda` es la palabra reservada -- `argumento` es el argumento de la función -- `:` es el delimitador de la expresión -- `expresión` es el bloque de código - ---- -Ejemplo 13, Crear una función anónima para obtener el cuadrado de un número - -```python -print ("Ejemplo 13") -cuadrado = lambda numero: numero**2 -resultado = cuadrado(5) -print (resultado) -resultado = cuadrado(10) -print (resultado) -``` - -```text -25 -100 -``` - ---- -Ejercicio 13, Crear una función anónima para obtener de una cadena las letras solo los alfanuméricos y convertir en mayúsculas - -```python -cadena = "Python es un lenguaje de programación" -``` - -2 minutos - - - ---- -Solución 13 - -```python -cadena = "Python es un lenguaje de programación" -limpiar = lambda cadena: "".join([letra for letra in cadena if letra.isalnum()]).upper() -resultado = limpiar(cadena) -print (cadena) -print (resultado) -``` - -```text -Python es un lenguaje de programación -PYTHONESUNLENGUAJEDEPROGRAMACIÓN -``` - ---- -##### Resumen - -- Las funciones son bloques de código que se pueden reutilizar -- Se definen con la palabra reservada `def` -- Se llaman después de ser definidas -- Una función puede definirse con o sin parámetros -- Una función puede recibir o no argumentos - ---- -- Una función puede devolver un valor o no devolver un valor -- Puede haber funciones con multiples argumentos y múltiples retornos -- Existen variables globales y locales en las funciones - ---- -- Las variables locales tienen prioridad sobre las globales -- Existen `*args` y `**kwargs` en funciones para recibir múltiples argumentos -- `*args` es una tupla de argumentos sin clave -- `**kwargs` es un diccionario de argumentos con clave - ---- -- Se puede llamar funciones dentro de funciones -- Existen funciones recursivas que se llaman a sí mismas -- Las funciones anónimas o lambda son funciones sin nombre -- Lambdas se utilizan para funciones pequeñas y simples - ---- -- Se pueden documentar las funciones con `"""documentación"""` -- Se puede acceder a la documentación con `.__doc__` - ---- - -![FUNCIÓN DEVOLVER](./img/FUNCION-DEVOLVER-W.gif) -![FUNCIÓN LLAMAR](./img/FUNCION-LLAMAR-W.gif) - ---- -![FUNCIÓN ANIDADA](./img/FUNCION-ANIDADA-W.gif) -![FUNCIÓN RECURSIVA](./img/FUNCION-RECURSIVA-W.gif) - - ---- -##### Retos - -Crear una carpeta con el nombre "retos_sesion_14" en la cual por cada ejercicio debe crear un script de python - -```bash -# Ejemplo carpeta -psg-example/ - retos_sesion_14/ - ejercicio_01.py - ejercicio_02.py - ejercicio_03.py - ejercicio_04.py - ejercicio_05.py - ejercicio_06.py - ejercicio_07.py - sesion14.ipynb -``` - -Subir la carpeta a su repositorio en GitHub cuando termine los retos - ---- -1. Crea una funcion que reciba una lista de calificaciones y devuelva el promedio de las mismas. Las calificaciones son: 50, 75, 80, 91, 70 - ---- -2. Crear una función que reciba dos números y una operación (suma, resta, multiplicación, división) y devuelva el resultado de la operación - -Ejemplo: `calcular(10, 5, "+")` debe devolver `15` - ---- -3. Crear una función recursiva para obtener el N-esimo número de la serie de Lucas - ---- -4. Crear una función anónima para obtener el valor absoluto de un número. - ---- -5. Crear una función que reciba una cadena y devuelva la cantidad de vocales que tiene. - ---- -6. Crear una función que reciba una lista de números y devuelva una lista con los números pares y otra lista con los números impares - ---- -7. Tres en Raya: -- Crear una función que reciba una jugada en cada ejecución -- Cuando la jugada se completa se debe mostrar el tablero -- El tablero debe ser una lista de listas -- El juego termina cuando un jugador gana o hay un empate -- Si una casilla ya está ocupada, se debe pedir una nueva jugada -- Se debe mostrar a quién le toca jugar, si a "X" o "O" - ---- - -Ejemplo: -```text -tres_en_raya("X", 0, 0) - -[['X', ' ', ' '], - [' ', ' ', ' '], - [' ', ' ', ' ']] - -Juega "O" -``` - ---- -1. Convertir y ejecutar el archivo de la "sesion14.py" a un Jupyter Notebook - ---- - - -
-
-
-
-
- -[![GitHub](../../content/github_logo.png) ](https://github.com/python-la-paz/python-study-group-fundamentals/tree/main/content/sesion14) - -Repositorio de la Sesión - ---- - -## Bibliografía y Referencias - -- [Python Learn](https://do1.dr-chuck.com/pythonlearn/ES_es/pythonlearn.pdf) -- [Built in Functions](https://docs.python.org/3/library/functions.html#built-in-functions) -- [Lambda](https://docs.python.org/3/reference/expressions.html#lambda) -- [Control de flujo](https://docs.python.org/3/tutorial/controlflow.html#defining-functions) -- [Documentación](https://docs.python.org/3/tutorial/controlflow.html#documentation-strings) -- [Glosario Parameter](https://docs.python.org/3/glossary.html#term-parameter) -- [Glosario Argument](https://docs.python.org/3/glossary.html#term-argument) -- [FAQ Param VS Arg](https://docs.python.org/3/faq/programming.html#faq-argument-vs-parameter) -- [Python Tutor](https://pythontutor.com/) \ No newline at end of file diff --git a/content/sesion14/img/FUNCION-ANIDADA-W.gif b/content/sesion14/img/FUNCION-ANIDADA-W.gif deleted file mode 100644 index 05bd92b..0000000 Binary files a/content/sesion14/img/FUNCION-ANIDADA-W.gif and /dev/null differ diff --git a/content/sesion14/img/FUNCION-DEVOLVER-W.gif b/content/sesion14/img/FUNCION-DEVOLVER-W.gif deleted file mode 100644 index b901f62..0000000 Binary files a/content/sesion14/img/FUNCION-DEVOLVER-W.gif and /dev/null differ diff --git a/content/sesion14/img/FUNCION-LLAMAR-W.gif b/content/sesion14/img/FUNCION-LLAMAR-W.gif deleted file mode 100644 index 0187115..0000000 Binary files a/content/sesion14/img/FUNCION-LLAMAR-W.gif and /dev/null differ diff --git a/content/sesion14/img/FUNCION-RECURSIVA-W.gif b/content/sesion14/img/FUNCION-RECURSIVA-W.gif deleted file mode 100644 index f14fdb4..0000000 Binary files a/content/sesion14/img/FUNCION-RECURSIVA-W.gif and /dev/null differ diff --git a/content/sesion14/index.html b/content/sesion14/index.html deleted file mode 100644 index 8414c0f..0000000 --- a/content/sesion14/index.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - Sesión 14 | Python Study Group | Fundamentals - - - - - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/content/sesion15/Readme.md b/content/sesion15/Readme.md deleted file mode 100644 index 64662a7..0000000 --- a/content/sesion15/Readme.md +++ /dev/null @@ -1,748 +0,0 @@ - -![Python La paz](../Logo.png) - -
-
-
- -### Sesión 15 -### Errores y Excepciones -### Try - Except - ---- -No podemos controlar lo que un usuario ingresa por lo que debemos anticipar los que pueden ocurrir - ---- -##### ¿Qué es un error? - ---- -Un error es una situación que se produce cuando una instrucción no puede ejecutarse correctamente. - -En Python, un error puede ser un error de sintaxis o un error de excepción - ---- -Un error de sintaxis se produce cuando Python no puede interpretar nuestro código - -Generalmente porque hemos escrito mal alguna parte del código - -```python -print("Hola Mundo) -``` - -```text -line 1 - print("Hola Mundo) - ^ -SyntaxError: unterminated string literal (detected at line 1) -``` - ---- -##### ¿Qué es una excepción? - -Una excepción es un error que ocurre durante la ejecución de un programa - -Cuando se produce una excepción, el programa se detiene y muestra un mensaje de error - ---- -La mayoría de las excepciones son ya gestionadas por Python - -Aveces es necesario gestionar las excepciones nosotros mismos - ---- -En Python las excepciones se pueden manejar para evitar que el programa se detenga inesperadamente - ---- -Visualmente - -![Excepciones](./img/EXCEPCION-W.gif) - - ---- -##### Estructura de una excepción Simple - -```python -try: - # Código que puede lanzar una excepción -except Exception as e: - # Código que se ejecuta si se produce una excepción -# Código que se ejecuta siempre fuera del bloque try-except -``` - -- `try`: Bloque de código que puede lanzar una excepción posee indentación -- `except`: Bloque de código que se ejecuta si se produce una excepción -- `Exception as e`: Captura la excepción y la almacena en la variable `e` - ---- - -Ejemplo 1, División por cero - -```python [1|2|3|4] -print ("Inicio Ejemplo 1") -x = 1 / 0 -print (x) -print ("Fin Ejemplo 1") -``` - -```text -Inicio Ejemplo 1 -ERROR! -Traceback (most recent call last): - File "", line 2, in -ZeroDivisionError: division by zero -``` - ---- -Ejemplo 1, División por cero - -```python [1|2-4|5-6|7] -print ("Inicio Ejemplo 1") -try: - x = 1 / 0 - print (x) -except Exception as e: - print("💀 Error:", e, type(e)) -print ("Fin Ejemplo 1") -``` - -```text -Inicio Ejemplo 1 -💀 Error: division by zero -Fin Ejemplo 1 -``` - ---- -Ejercicio 1, Crear un programa que solicite dos números y realice la división de ambos números -Si hay un error mostrar un mensaje de error -El programa se detiene si se ingresa "salir" - -2 minutos - - - ---- -Solución Ejercicio 1 - -```python -while True: - try: - num1 = input("Ingrese el primer número: ") - if num1 == "salir": - break - num2 = input("Ingrese el segundo número: ") - if num2 == "salir": - break - num1 = float(num1) - num2 = float(num2) - print("Resultado:", num1 / num2) - except Exception as e: - print("💀 Error:", e) -``` - -```text -Ingrese el primer número: 1 -Ingrese el segundo número: 0 -ERROR! -💀 Error: float division by zero -Ingrese el primer número: salir -``` - ---- -##### Tipos de excepciones - -Algunos tipos de excepciones son: - -- ZeroDivisionError: Se produce cuando se intenta dividir por cero -- NameError: Se produce cuando no se encuentra una variable -- TypeError: Se produce cuando se intenta realizar una operación no permitida - ---- -- ValueError: Se produce cuando se intenta realizar una operación con un valor incorrecto -- KeyError: Se produce cuando se intenta acceder a una clave que no existe en un diccionario -- IndexError: Se produce cuando se intenta acceder a un índice que no existe en una lista - ---- -##### Excepciones múltiples - -`try` puede detectar un tipo de excepción específico y ejecutar un bloque de código diferente para cada tipo de excepción - -Se debe poner un bloque `except` el tipo de excepción que se desea capturar con jerarquía de arriba hacía abajo - -```python -try: - # Código que puede lanzar una excepción -except ZeroDivisionError as e: - # Código si se produce una excepción de división por cero -except Exception as e: - # Código si se produce una excepción genérica -``` - ---- -Ejemplo 2, División por cero - -```python [1-2|3-5|6-7|10] -print ("Inicio Ejemplo 2") -divisor = 0 -try: - x = 1 / divisor - print (x) -except ZeroDivisionError as e: - print("0️⃣ Error:", e, type(e)) -except Exception as e: - print("💀 Error:", e, type(e)) -print ("Fin Ejemplo 2") -``` - -```text -Inicio Ejemplo 2 -0️⃣ Error: division by zero -Fin Ejemplo 2 -``` - ---- -Ejemplo 2, División por cero - -```python [1-2|3-5|8-9|10] -print ("Inicio Ejemplo 2") -divisor = "0" -try: - x = 1 / divisor - print (x) -except ZeroDivisionError as e: - print("0️⃣ Error:", e, type(e)) -except Exception as e: - print("💀 Error:", e, type(e)) -print ("Fin Ejemplo 2") -``` - -```text -Inicio Ejemplo 2 -💀 Error: unsupported operand type(s) for /: 'int' and 'str' -Fin Ejemplo 2 -``` - ---- -Jerarquía de excepciones - -Ejemplo 2, División por cero - -```python [1-2|3-5|6-7|10] -print ("Inicio Ejemplo 2") -divisor = 0 -try: - x = 1 / divisor - print (x) -except Exception as e: # Captura cualquier excepción - print("💀 Error:", e, type(e)) -except ZeroDivisionError as e: - print("0️⃣ Error:", e, type(e)) -print ("Fin Ejemplo 2") -``` - -```text -Inicio Ejemplo 2 -💀 Error: division by zero -Fin Ejemplo 2 -``` - ---- -Ejemplo 3, De la lista de calificaciones obtener el promedio - -```python -calificaciones = [20,40,80,"A"] -suma = 0 -try: - for i in range(len(calificaciones)+1): - suma += calificaciones[i] - promedio = suma / len(calificaciones) - print("Promedio:", promedio) -except ZeroDivisionError as e: - print("0️⃣ Error:", e, type(e)) -except TypeError as e: - print("🎭 Error:", e, type(e)) -except Exception as e: - print("💀 Error:", e, type(e)) -``` - -```text -🎭 Error: unsupported operand type(s) for +=: 'int' and 'str' -``` - ---- -Ejemplo 3, De la lista de calificaciones obtener el promedio - -```python -calificaciones = [20,40,80] -suma = 0 -try: - for i in range(len(calificaciones)+1): - suma += calificaciones[i] - promedio = suma / len(calificaciones) - print("Promedio:", promedio) -except ZeroDivisionError as e: - print("0️⃣ Error:", e, type(e)) -except TypeError as e: - print("🎭 Error:", e, type(e)) -except Exception as e: # Captura cualquier excepción - print("💀 Error:", e, type(e)) -``` - -```text -💀 Error: list index out of range -``` - ---- -Ejemplo 3, De la lista de calificaciones obtener el promedio - -```python -calificaciones = [20,40,80] -suma = 0 -try: - for i in range(len(calificaciones)): - suma += calificaciones[i] # suma = suma + calificaciones[i] - promedio = suma / len(calificaciones) - print("Promedio:", promedio) -except ZeroDivisionError as e: - print("0️⃣ Error:", e, type(e)) -except TypeError as e: - print("🎭 Error:", e, type(e)) -except Exception as e: - print("💀 Error:", e, type(e)) -``` - -```text -Promedio: 46.666666666666664 -``` - ---- -##### Bloque `else` - -Se puede agregar un bloque `else` que se ejecuta si no se produce ninguna excepción - -Se debe poner después de todos los bloques `except` - -Lo utilizamos validar la entrada de datos o para mostrar un mensaje de éxito - ---- -Estructura de un bloque `else` - -```python [5-6] -try: - # Código que puede lanzar una excepción -except Exception as e: - # Código si se produce una excepción -else: - # Código si no se produce ninguna excepción -``` - ---- -Ejemplo 4, De la lista de calificaciones obtener el promedio - -```python [1-3|4-8|11-12|13] -print ("Inicio Ejemplo 4") -calificaciones = [20,40,80] -suma = 0 -try: - for i in range(len(calificaciones)): - suma += calificaciones[i] - promedio = suma / len(calificaciones) - print("Promedio:", promedio) -except Exception as e: - print("💀 Error:", e, type(e)) -else: - print ("🎉 Sin errores") -print ("Fin Ejemplo 4") -``` - -```text -Inicio Ejemplo 4 -Promedio: 46.666666666666664 -🎉 Sin errores -Fin Ejemplo 4 -``` - ---- -- Ejercicio 2, Crear un programa que solicite dos números y mediante una función devuelva la división de ambos -- Si hay un error mostrar un mensaje de error. El programa se detiene si se ingresa "salir" -- Añadir un bloque `else` que muestre el resultado de la función - -2 minutos - - - ---- -Solución Ejercicio 2 - -```python -def division(num1, num2): - return num1 / num2 - -while True: - try: - num1 = input("Ingrese el primer número: ") - if num1 == "salir": - break - num2 = input("Ingrese el segundo número: ") - if num2 == "salir": - break - num1 = float(num1) - num2 = float(num2) - resultado = division(num1, num2)) - except Exception as e: - print("💀 Error:", e) - else: - print("🎉 Resultado: ",resultado) -``` - -```text -Ingrese el primer número: 1 -Ingrese el segundo número: 1 -🎉 Resultado: 1.0 -``` - ---- -##### Bloque `finally` - -Se puede agregar un bloque `finally` que se ejecuta siempre, independientemente de si se produce una excepción - -Se debe poner después de todos los bloques `except` y `else` - ---- -Se utiliza para liberar recursos o cerrar archivos - -Para garantizar que se ejecute un código importante sin importar si se produce una excepción o no - ---- -Estructura de un bloque `finally` - -```python [7-8] -try: - # Código que puede lanzar una excepción -except Exception as e: - # Código si se produce una excepción -else: - # Código si no se produce ninguna excepción -finally: - # Código que se ejecuta siempre -``` - ---- -Ejemplo 5, Simula una conexión a internet que haga ping y cerrar la conexión - -```python [1|2-3|6-7|8-9] -print ("Inicio Ejemplo 5") -try: - print("🔗 Ping...") -except Exception as e: - print("💀 Error:", e) -else: - print("🎉 Ping Exitoso") -finally: - print("🔌 Cerrando conexión") -``` - -```text -Inicio Ejemplo 5 -🔗 Ping... -🎉 Ping Exitoso -🔌 Cerrando conexión -``` - ---- -¿Cómo generamos una excepción? - -Para probar que finally se ejecuta siempre - ---- -##### Raise - -`raise` se utiliza para generar una excepción - -Se puede generar una excepción específica o una excepción genérica - ---- -Estructura de `raise` - -```python -raise Exception("Mensaje de error") -``` - -- `raise` es una palabra reservada de Python -- `Exception` es el tipo de excepción que se desea generar -- `"Mensaje de error"` es el mensaje que se mostrará - ---- -Ejemplo 6, Simula una conexión a internet que haga ping y cerrar la conexión - -```python [1|2-4|4|5-6|9-10] -print ("Inicio Ejemplo 6") -try: - print("🔗 Ping...") - raise Exception("Error de conexión") #Excepción genérica -except Exception as e: # Captura cualquier excepción - print("💀 Error:", e) -else: - print("🎉 Ping Exitoso") -finally: - print("🔌 Cerrando conexión") -``` - -```text -Inicio Ejemplo 6 -🔗 Ping... -💀 Error: Error de conexión -🔌 Cerrando conexión -``` - ---- -- Ejercicio 3, Escriba un programa que solicite un número por teclado y se almacene en una lista -- Si es 0 se genera una excepción -- Si la ejecución es correcta muestra "🎉Agregado" -- Termina la ejecución sólo con la palabra "salir" utilizar la excepción `KeyboardInterrupt` -- Finalmente imprima siempre la suma de los números y la lista - -4 minutos - - - ---- -Solución Ejercicio 3 - -```python -numeros = [] -while True: - try: - num = input("Ingrese un número: ") - if num == "salir": - break - num = float(num) - if num == 0: - raise Exception("No se puede agregar el número 0") - numeros.append(num) - except KeyboardInterrupt as e: - print('🚫 Para salir escriba "salir"') - except Exception as e: - print("💀 Error:", e) - else: - print("🎉 Número agregado") - finally: - print("Suma:", sum(numeros)) -``` - ---- -```text -Ingrese un número: 1 -🎉 Número agregado -Lista: [1.0] -Suma: 1.0 -Ingrese un número: 2 -🎉 Número agregado -Lista: [1.0, 2.0] -Suma: 3.0 -Ingrese un número: 🚫 Para salir escriba "salir" -Lista: [1.0, 2.0] -Suma: 3.0 -Ingrese un número: salir -Lista: [1.0, 2.0] -Suma: 3.0 -``` - ---- -##### Pass - -`pass` es una palabra reservada de Python que no hace nada - -Se utiliza para evitar errores de sintaxis - -Se puede utilizar para evitar errores de indentación - ---- -Ejemplo 7, Crea una función que no hace nada - -```python -print("Inicio Ejemplo 7") -def funcion(): - pass - -funcion() -print("Fin Ejemplo 7") -``` - -```text -Inicio Ejemplo 7 -Fin Ejemplo 7 -``` - ---- -##### Excepciones personalizadas - -Se pueden crear excepciones personalizadas - -Nos permite crear excepciones específicas para nuestro programa - ---- -Se utiliza para crear excepciones de acuerdo a las necesidades del programa - ---- -Estructura de una excepción personalizada - -```python -class MiError(Exception): - pass - -raise MiError("Mensaje de error") -``` - -- `class`: palabra reservada de Python para crear una clase -- `MiError (Exception)`: nombre de la clase y la excepción de la que hereda -- `pass`: palabra reservada de Python para indicar que no hace nada - ---- -Ejemplo 8, Tienes un frutero, saca las frutas mientras no sea un gusano y genera una excepción - ---- -```python [1-3|5|6|7-10|11-12|15] -print("Inicio Ejemplo 8") -class GusanoError(Exception): - pass - -frutero = ['🍎', '🍌', '🍐', '🐛', '🍇'] -for fruta in frutero: - try: - if fruta == '🐛': - raise GusanoError("😱 Ewww!") - print(fruta) - except GusanoError as e: - print("🐛 Error:", e) - except Exception as e: - print("💀 Error:", e) -print("Fin Ejemplo 8") -``` - -```text -Inicio Ejemplo 8 -🍎 -🍌 -🍐 -🐛 Error: 😱 Ewww! -🍇 -Fin Ejemplo 8 -``` - ---- -- Ejercicio 4, Crear un programa que solicite palabras por teclado y almacene en una lista -- Si se inserta caracteres no alfabéticos se genera una excepción personalizada y no se almacena -- Si se ingresa "salir" se termina la ejecución -- Mostrar el mensaje "🎉 Palabra agregada" si no hay errores -- Finalmente imprimir la lista de palabras - -3 minutos - - - ---- -Solución Ejercicio 4 - -```python -class NoAlfabeticoError(Exception): - pass - -palabras = [] -while True: - try: - palabra = input("Ingrese una palabra: ") - if palabra == "salir": - break - if not palabra.isalpha(): - raise NoAlfabeticoError("Solo se permiten letras") - palabras.append(palabra) - except NoAlfabeticoError as e: - print("🚫 Error:", e) - except Exception as e: - print("💀 Error:", e) - else: - print("🎉 Palabra agregada") - finally: - print("Lista:", palabras) -``` - ---- -##### Resumen - -- `try`: Bloque de código que puede lanzar una excepción -- `except`: Bloque de código que se ejecuta si se produce una excepción -- `else`: Bloque de código que se ejecuta si no se produce ninguna excepción - ---- -- `finally`: Bloque de código que se ejecuta siempre -- `raise`: Genera una excepción -- `pass`: No hace nada -- Podemos crear excepciones personalizadas con `class` - ---- -##### Retos - -Crear una carpeta con el nombre "retos_sesion_15" en la cual por cada ejercicio debe crear un script de python - -```bash -# Ejemplo carpeta -psg-example/ - retos_sesion_15/ - ejercicio_01.py - ejercicio_02.py - ejercicio_03.py - sesion15.ipynb -``` - -Subir la carpeta a su repositorio en GitHub cuando termine los retos - ---- - -1. Crea una calculadora interactiva que solicite dos números por teclado y realice las operaciones de suma, resta, multiplicación y división. El programa debe seguir solicitando dos números hasta que se ingrese "salir". Se debe incluir el manejo de excepciones para evitar errores al ingresar datos no numéricos, al intentar dividir entre cero, o ante cualquier otro error inesperado. - ---- - -2. Crea un programa que permita construir una canasta de frutas solicitando ingresar frutas por teclado, una por una, y almacenándolas en una lista. El programa debe finalizar cuando se ingrese "salir". - -Solo se permiten las siguientes frutas: `🍅, 🍇, 🍈, 🍉, 🍊, 🍌, 🍍, 🍑` - -Si se ingresa una fruta no permitida, el programa debe lanzar una excepción personalizada que indique que la fruta no es válida. - ---- - -3. Crea un programa que simule el funcionamiento de un cajero automático solicitando al usuario un monto a retirar. Si el monto ingresado es mayor al saldo disponible, el programa debe lanzar una excepción personalizada que indique que no hay fondos suficientes. Además, si el monto ingresado es mayor a 1000, debe lanzarse una excepción genérica que advierta que el monto excede el límite permitido por transacción. - ---- - -4. Convertir y ejecutar el archivo de la "sesion15.py" a un Jupyter Notebook - ---- - - -
-
-
-
-
- -[![GitHub](../../content/github_logo.png) ](https://github.com/python-la-paz/python-study-group-fundamentals/tree/main/content/sesion15) - -Repositorio de la Sesión - ---- - -## Bibliografía y Referencias - -- [Python Learn](https://do1.dr-chuck.com/pythonlearn/ES_es/pythonlearn.pdf) -- [Errors](https://docs.python.org/es/3/tutorial/errors.html) -- [Exceptions](https://docs.python.org/es/3/library/exceptions.html) -- [Bltin-exceptions](https://docs.python.org/es/3/library/exceptions.html#bltin-exceptions) -- [Handling-exceptions](https://docs.python.org/es/3/tutorial/errors.html#handling-exceptions) -- [Raising-exceptions](https://docs.python.org/es/3/tutorial/errors.html#raising-exceptions) -- [The-try-statement](https://docs.python.org/es/3/reference/compound_stmts.html#the-try-statement) -- [Except-star](https://docs.python.org/es/3/reference/compound_stmts.html#except-star) -- [Else-clause](https://docs.python.org/es/3/reference/compound_stmts.html#else-clause) -- [Finally-clause](https://docs.python.org/es/3/reference/compound_stmts.html#finally-clause) -- [The-pass-statement](https://docs.python.org/3/reference/simple_stmts.html#the-pass-statement) -- [Tut-userexceptions](https://docs.python.org/3/tutorial/errors.html#tut-userexceptions) -- [KeyboardInterrupt](https://docs.python.org/es/3/library/exceptions.html#KeyboardInterrupt) -- [Exception-hierarchy](https://docs.python.org/es/3/library/exceptions.html#exception-hierarchy) diff --git a/content/sesion15/img/EXCEPCION-W.gif b/content/sesion15/img/EXCEPCION-W.gif deleted file mode 100644 index 8035768..0000000 Binary files a/content/sesion15/img/EXCEPCION-W.gif and /dev/null differ diff --git a/content/sesion15/index.html b/content/sesion15/index.html deleted file mode 100644 index 5f1a9e1..0000000 --- a/content/sesion15/index.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - Sesión 15 | Python Study Group | Fundamentals - - - - - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/content/sesionBonus/Readme.md b/content/sesionBonus/Readme.md deleted file mode 100644 index cb2ee39..0000000 --- a/content/sesionBonus/Readme.md +++ /dev/null @@ -1,592 +0,0 @@ - -![Python La paz](../Logo.png) - -
-
-
- -### Sesión Bonus -### Depuración -### Debug en Visual Studio Code - ---- -Vamos a aprender a debuggear o depurar nuestro código en Python - ---- -##### ¿Qué es Debug? - ---- -Depurar o debuggear es el proceso de encontrar y corregir errores en el código fuente de un programa - ---- -##### Importancia de Debug - -El proceso de depuración es una parte esencial del desarrollo de software - -A través de la depuración, podemos identificar errores y problemas en nuestro código. - -Nos permite corregirlos y mejorar la calidad de nuestro software - ---- -##### Conceptos básicos de Debug - -1. **Punto de interrupción (Breakpoint)**: Es un punto en el código fuente donde la ejecución del programa se detiene temporalmente. Nos permite inspeccionar el estado del programa en ese punto - ---- -2. **Comandos de Debug**: Son comandos que nos permiten controlar la ejecución del programa durante la depuración - ---- -3. **Inspección de variables**: Nos permite ver el valor de las variables en un punto específico del programa - ---- -4. **Evaluación de expresiones en tiempo de ejecución**: Nos permite evaluar expresiones en tiempo de ejecución - ---- -5. **Consola de Debug**: Es una consola que nos permite interactuar con el programa durante la depuración - ---- -6. **Depuración de un script**: Es el proceso de depurar un archivo de código fuente en un programa - ---- -##### Debug en Visual Studio Code - -Una de las características más útiles de Visual Studio Code es su capacidad para depurar código - -Posee un depurador integrado que nos permite depurar código en varios lenguajes de programación - -incluido Python - ---- - -![Visual Studio Code](./img/01.png) - ---- - -Visual Studio Code no es un IDE de Python especializado en solo Python - -Visual Studio Code es un editor de código que soporta varios lenguajes de programación - -Para depurar código en Python en Visual Studio Code, necesitamos instalar la extensión de Python - ---- -##### Configuración de Debug en Visual Studio Code - -Primero, necesitamos instalar la extensión de Python en Visual Studio Code - -Para instalar la extensión de Python, abrimos Visual Studio Code y hacemos clic en la pestaña de Extensiones - -![Extensiones](./img/02.png) - ---- -En la barra de búsqueda, escribimos Python vemos que el Publicador es Microsoft - -Es la extensión oficial de Python para Visual Studio Code - -Hacemos clic en la extensión de Python - -![Extensión Python](./img/03.png) - ---- -Si vamos a la pestaña Extension Pack observamos que posee varias extensiones útiles cómo: - -- Pylance: Mejora la experiencia de desarrollo añadiendo soporte IntelliSense para el autocompletado -- Python Debugger: Proporciona soporte para depurar código en Python utilizando debugpy - ---- -![Extension Pack](./img/04.png) - ---- - -Presionamos el botón de instalar para instalar la extensión de Python en Visual Studio Code - -![Instalar](./img/05.png) - ---- -Una vez que la extensión de Python está instalada, podemos comenzar a depurar código en Python en Visual Studio Code - ---- -Crearemos el archivo `sesion_bonus.py` donde vamos a empezar a depurar código en Python - ---- -```python -# sesion_bonus.py -def suma(a, b): - c = a + b - return c - -def resta(a, b): - return a - b - -def multiplicacion(x, y): - z = x * y - return z - -def division(x, y): - return x / y - -def division_controlada(x,y): - try: - return x / y - except ZeroDivisionError as e: - return "Division entre cero" - -a = 11 -b = 0 -print (suma(a, b)) -print (resta(a, b)) -print (multiplicacion(a, b)) -print (division_controlada(a, b)) -print (division(a, b)) -``` - - ---- -##### Puntos de interrupción (Breakpoints) - -Un punto de interrupción es un punto en el código fuente donde la ejecución del programa se detiene temporalmente - -Para agregar un punto de interrupción en Visual Studio Code, hacemos clic en el margen izquierdo del editor de código - -![Breakpoint](./img/06.png) - ---- -Después de agregar un punto de interrupción, veremos un círculo rojo en el margen izquierdo del editor de código - -![Breakpoint Agregado](./img/07.png) - ---- -Después de agregar un punto de interrupción, tenemos que iniciar la depuración del programa - -No es lo mismo que ejecutar el programa normalmente - -La depuración nos permite inspeccionar el estado del programa en un punto específico mientras se ejecuta - ---- -Para iniciar la depuración del programa, hacemos clic en el botón de Depurar en la barra de herramientas - -![Depurar](./img/08.png) - -Cuando hacemos clic en el botón de Depurar, Visual Studio Code inicia la depuración del programa y detiene la ejecución siempre que se encuentre un punto de interrupción - ---- -![Depuración](./img/09.png) - ---- -Observamos - -1. En la parte superior, vemos la barra de herramientas de depuración -2. En la izquierda vemos la barra de navegación de depuración -3. Vemos en el script que la ejecución se detiene en el punto de interrupción -4. En la parte inferior vemos en la terminal la salida del programa en Python Debug Console - ---- -##### Navegación de depuración - -La barra de herramientas de depuración nos permite controlar la ejecución del programa durante la depuración - ---- -![Continuar](./img/10.png) - -1. **Continuar (Continue)**: Continúa la ejecución del programa hasta el siguiente punto de interrupción - ---- -![Paso siguiente](./img/11.png) - -2. **Paso siguiente (Step Over)**: Ejecuta la siguiente línea de código - ---- -![Paso en](./img/12.png) - -3. **Paso en (Step Into)**: Entra en la función actual - ---- -![Paso fuera](./img/13.png) - -4. **Paso fuera (Step Out)**: Sale de la función actual - ---- -![Reiniciar](./img/14.png) - -5. **Reiniciar (Restart)**: Reinicia la depuración del programa - ---- -![Detener](./img/15.png) - -6. **Detener (Stop)**: Detiene la depuración del programa - ---- -##### Inspección de variables - -La inspección de variables nos permite ver el valor de las variables en un punto específico del programa - -Para inspeccionar una variable en Visual Studio Code, colocamos el cursor sobre la variable y vemos el valor de la variable - -![Inspección de variables](./img/16.png) - ---- -También podemos inspeccionar variables en el panel de Variables en la barra de navegación de depuración - -![Variables](./img/17.png) - ---- -##### Evaluación de expresiones en tiempo de ejecución - -La evaluación de expresiones nos permite evaluar durante la ejecución del programa - -Para evaluar una expresión en Visual Studio Code, utilizaremos el panel Watch para agregar una expresión y ver su valor en tiempo de ejecución con las variables del programa - ---- -![Evaluación de expresiones](./img/18.png) - - ---- -##### Call Stack (Pila de llamadas) - -Almacena información sobre las llamadas a funciones en el programa - -Nos permite ver la secuencia de llamadas hasta el punto actual del programa - -![Call Stack](./img/19.png) - - ---- -##### Breakpoints condicionales - -Los breakpoints condicionales nos permiten detener la ejecución del programa solo si se cumple una condición - -Para agregar un breakpoint condicional, hacemos clic con el botón derecho en el breakpoint y seleccionamos Edit Breakpoint - ---- -Por ejemplo, si z es igual a 50, el programa se detendrá en el breakpoint - -``` -z == 50 -``` - -![Breakpoint Condicional](./img/20.png) - ---- -##### Breakpoints Panel - -El panel de Breakpoints nos permite ver todos los breakpoints en el programa - -Podemos habilitar o deshabilitar breakpoints, editar breakpoints y eliminar breakpoints - -![Breakpoints Panel](./img/21.png) - ---- -Raised Exceptions - -Habilitar esta opción nos permite detener la ejecución del programa cuando se lanza una excepción - -Sin importar si la excepción es manejada o no mediante un bloque try-except - -![Raised Exceptions](./img/22.png) - ---- -Uncaught Exceptions - -Habilitar esta opción nos permite detener la ejecución del programa cuando se lanza una excepción no manejada - -![Uncaught Exceptions](./img/23.png) - ---- -Add Function Breakpoint - -Nos permite agregar un breakpoint en una función específica en el programa mediante el nombre de la función - -![Add Function Breakpoint](./img/24.png) - ---- -##### Consola de Debug - -La consola de Debug es una consola que nos permite interactuar con el programa durante la depuración - -Podemos ejecutar comandos en la consola de Debug para inspeccionar variables, evaluar expresiones y controlar la ejecución del programa - ---- -Para abrir la consola de Debug, hacemos clic en la pestaña de Debug Console cerca de la terminal en la parte inferior de Visual Studio Code - -![Debug Console](./img/25.png) - ---- -Podemos ejecutar comandos en la consola de Debug para inspeccionar variables, evaluar expresiones y controlar la ejecución del programa - -Ejecutando - -```python -print (a, b) -``` -```python -print (suma(10, 5)) -``` - ---- -Podemos cambiar el valor de las variables en la consola de Debug - -```python -a = 20 -b = 10 -``` - -![Debug Console](./img/26.png) - ---- -##### Depuración de un script - -La depuración de un script es el proceso de identificar y corregir errores en un archivo de código fuente en un programa - -Tenemos este script `calculadora.py` que contiene errores - ---- -```python -def add(a, b): - return a + b - -def subtract(a, b): - return a - b - -def multiply(a, b): - return str(a) * b - -def divide(a, b): - return a / b - -def pow(a): - b = 0b100 - return a ** b - -def calculator(): - while True: - print("\nSimple Calculator") - print("Options:") - print("1. Add") - print("2. Subtract") - print("3. Multiply") - print("4. Divide") - print("5. Pow") - print("6. Exit") - choice = input("Select an operation (1/2/3/4/5): ") - if choice == 'Exit': - print("Exiting calculator.") - break - if choice in ('1', '2', '3', '4', '5'): - num1 = float(input("Enter first number: ")) - num2 = float(input("Enter second number: ")) - if choice == '1': - print(f"Result: {num1} + {num2} = {add(num1, num2)}") - elif choice == '2': - print(f"Result: {num1} - {num2} = {subtract(num1, num2)}") - elif choice == '3': - print(f"Result: {num1} * {num2} = {multiply(num1, num2)}") - elif choice == '4 ': - print(f"Result: {num1} / {num2} = {divide(num1, num2)}") - else: - print("Invalid choice. Please select a valid option.") -calculator() -``` - ---- -Vamos a depurar el script `calculadora.py` en Visual Studio Code - - ---- -##### launch.json - -El archivo `launch.json` es un archivo de configuración que nos permite configurar varios aspectos de la depuración en Visual Studio Code - -Podemos configurar el tipo de depurador, el programa que queremos depurar, los argumentos del programa, el entorno de depuración y más - ---- -Para crear un archivo `launch.json`, hacemos clic en el botón de configuración en la barra de herramientas de depuración - -![Configuración](./img/27.png) - ---- - -Después de hacer clic en el botón de configuración, seleccionamos la opción de Python en la lista de entornos de depuración - -![Python](./img/28.png) - ---- -Seleccionamos la opción de Python File en la lista de entornos de depuración porque queremos depurar un archivo de Python - -Existen configuraciones predefinidas para depurar diferentes tipos de programas en Python - -![Python File](./img/29.png) - ---- -Después de seleccionar la opción de Python File, Visual Studio Code crea un archivo `launch.json` en la carpeta `.vscode` del proyecto - ---- -El archivo `launch.json` contiene la configuración de depuración para el archivo de Python - -![launch.json](./img/30.png) - ---- -Una vez que hemos creado el archivo `launch.json`, veremos que en el panel de depuración aparece la configuración de depuración para el archivo de Python - -![Configuración](./img/31.png) - ---- -Desde el panel de depuración, podemos iniciar la depuración del programa haciendo clic en el botón de Iniciar Depuración - ---- -Es útil tener un archivo `launch.json` para tener una configuración de depuración predefinida para un programa - ---- -##### Resumen - -1. Depurar es el proceso de encontrar y corregir errores en el código fuente de un programa -2. Visual Studio Code es un editor de código que soporta varios lenguajes de programación -3. Visual Studio Code NO es un IDE de Python especializado en solo Python - ---- -4. Para depurar código en Python en Visual Studio Code, necesitamos instalar la extensión de Python -5. Los puntos de interrupción son puntos en el código fuente donde la ejecución del programa se detiene temporalmente -6. La barra de herramientas de depuración nos permite controlar la ejecución del programa durante la depuración - ---- -7. La inspección de variables nos permite ver el valor de las variables en un punto específico del programa -8. La evaluación de expresiones en tiempo de ejecución nos permite evaluar expresiones en tiempo de ejecución -9. La consola de Debug es una consola que nos permite interactuar con el programa durante la depuración - ---- -10. La depuración es el proceso de localizar y corregir errores en un programa -11. El archivo `launch.json` es un archivo de configuración que nos permite configurar varios aspectos de la depuración en Visual Studio Code -12. Es útil tener un archivo `launch.json` para tener una configuración de depuración predefinida para un programa - ---- -##### Retos -Crear una carpeta con el nombre "retos_sesion_bonus" en la cual por cada ejercicio debe crear un script de python - -```bash -# Ejemplo carpeta -psg-example/ - retos_sesion_bonus/ - ejercicio_01.py - ejercicio_02.py -``` - -Subir la carpeta a su repositorio en GitHub cuando termine los retos - - ---- -1. Tienes un programa que cuenta la cantidad de frutas que aparecen en una lista y las guarda en un diccionario. El programa no muestra correctamente la información. Corrigelo! - -```python -frutas = ['🍅','🍇','🍈','🍉','🍊','🍌','🍍','🍌','🍊','🍉','🍈','🍇','🍅','🍅','🍇'] - -# Función para contar las frutas -def contar_frutas(lista_frutas): - contador = {} - for fruta in lista_frutas: - if fruta in contador: - contador[fruta] += 1 - else: - contador[fruta] = 0 - return contador - -# Función para imprimir el conteo de frutas -def imprimir_conteo(conteo): - for fruta, cantidad in conteo: - print(f"Hay {cantidad} {fruta}(s).") - -# Llamando a las funciones -conteo_frutas = contar_frutas(frutas) -imprimir_conteo(conteo_frutas) -``` - ---- -Resultado esperado - -```bash -python ejercicio_01.py -``` - -```bash -Hay 3 🍅s. -Hay 3 🍇s. -Hay 2 🍈s. -Hay 2 🍉s. -Hay 2 🍊s. -Hay 2 🍌s. -Hay 1 🍍. -``` - ---- -2. Tienes un juego de adivinanzas en el que el jugador tiene que adivinar un número entre 1 y 100. El juego tiene bugs, arréglalos! - -```python -def obtener_aleatorio(): - numeros = list(range(1, 101)) - secreto = numeros.pop() - return secreto - -def adivina(secreto): - intentos = 0 - print ("Que número estoy pensando? (1-100)") - while True: - try: - intento = int(input(f"Intento N°: {intentos+1}: ")) - if intento == secreto: - print ("Felicidades! Has adivinado el número!") - break - elif intento < secreto: - print ("El número es mayor.") - else: - print ("El número es menor.") - except ValueError: - print ("Por favor, ingresa un número válido.") - finally: - intentos += 1 - print (f"Has adivinado el número en {intentos*10} intentos.\n") - -nombre_jugador = "Guest" - -def jugar(): - while True: - print ("Bienvenido al juego de adivinanzas! del Python Study Group 2025") - print ("="*63) - nombre_jugador = input("¿Cuál es tu nombre?: ") - print (f"Bienvenido, {nombre_jugador}!") - print ("="*63) - print () - opcion = input("Quieres jugar? (s/n): ") - if opcion.lower() != 'S': - break - secreto = obtener_aleatorio() - adivina(secreto) - print ("Gracias por participar!") - print (f"🐍 Gracias {nombre_jugador.upper()} por ser parte del Python Study Group 2025! 🐍") - -jugar() -``` - ---- -Gracias por Participar del Python Study Group 2025🐍 - -> Cada línea de código es el reflejo de un pensamiento -> -> Domina tu código, domina tu futuro - ---- - - -
-
-
-
-
- -[![GitHub](../../content/github_logo.png) ](https://github.com/python-la-paz/python-study-group-fundamentals/tree/main/content/sesionBonus) - -Repositorio de la Sesión - ---- - -## Bibliografía y Referencias -- [Debugging in Visual Studio Code](https://code.visualstudio.com/docs/editor/debugging) -- [Python Extension for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-python.python) -- [Python Debugging in Visual Studio Code](https://code.visualstudio.com/docs/python/debugging) -- [Debugpy](https://github.com/microsoft/debugpy/) \ No newline at end of file diff --git a/content/sesionBonus/img/01.png b/content/sesionBonus/img/01.png deleted file mode 100644 index a688ea2..0000000 Binary files a/content/sesionBonus/img/01.png and /dev/null differ diff --git a/content/sesionBonus/img/02.png b/content/sesionBonus/img/02.png deleted file mode 100644 index 13d9e4c..0000000 Binary files a/content/sesionBonus/img/02.png and /dev/null differ diff --git a/content/sesionBonus/img/03.png b/content/sesionBonus/img/03.png deleted file mode 100644 index 76c3740..0000000 Binary files a/content/sesionBonus/img/03.png and /dev/null differ diff --git a/content/sesionBonus/img/04.png b/content/sesionBonus/img/04.png deleted file mode 100644 index 7a5847c..0000000 Binary files a/content/sesionBonus/img/04.png and /dev/null differ diff --git a/content/sesionBonus/img/05.png b/content/sesionBonus/img/05.png deleted file mode 100644 index a3207f5..0000000 Binary files a/content/sesionBonus/img/05.png and /dev/null differ diff --git a/content/sesionBonus/img/06.png b/content/sesionBonus/img/06.png deleted file mode 100644 index f1d44a5..0000000 Binary files a/content/sesionBonus/img/06.png and /dev/null differ diff --git a/content/sesionBonus/img/07.png b/content/sesionBonus/img/07.png deleted file mode 100644 index 9196e9c..0000000 Binary files a/content/sesionBonus/img/07.png and /dev/null differ diff --git a/content/sesionBonus/img/08.png b/content/sesionBonus/img/08.png deleted file mode 100644 index 0500f4a..0000000 Binary files a/content/sesionBonus/img/08.png and /dev/null differ diff --git a/content/sesionBonus/img/09.png b/content/sesionBonus/img/09.png deleted file mode 100644 index 6cf79a9..0000000 Binary files a/content/sesionBonus/img/09.png and /dev/null differ diff --git a/content/sesionBonus/img/10.png b/content/sesionBonus/img/10.png deleted file mode 100644 index df96ba5..0000000 Binary files a/content/sesionBonus/img/10.png and /dev/null differ diff --git a/content/sesionBonus/img/11.png b/content/sesionBonus/img/11.png deleted file mode 100644 index 99da91b..0000000 Binary files a/content/sesionBonus/img/11.png and /dev/null differ diff --git a/content/sesionBonus/img/12.png b/content/sesionBonus/img/12.png deleted file mode 100644 index 91b69e2..0000000 Binary files a/content/sesionBonus/img/12.png and /dev/null differ diff --git a/content/sesionBonus/img/13.png b/content/sesionBonus/img/13.png deleted file mode 100644 index ca6b1e3..0000000 Binary files a/content/sesionBonus/img/13.png and /dev/null differ diff --git a/content/sesionBonus/img/14.png b/content/sesionBonus/img/14.png deleted file mode 100644 index c1b75ac..0000000 Binary files a/content/sesionBonus/img/14.png and /dev/null differ diff --git a/content/sesionBonus/img/15.png b/content/sesionBonus/img/15.png deleted file mode 100644 index e50d48d..0000000 Binary files a/content/sesionBonus/img/15.png and /dev/null differ diff --git a/content/sesionBonus/img/16.png b/content/sesionBonus/img/16.png deleted file mode 100644 index 2c3d36e..0000000 Binary files a/content/sesionBonus/img/16.png and /dev/null differ diff --git a/content/sesionBonus/img/17.png b/content/sesionBonus/img/17.png deleted file mode 100644 index 5d3fa21..0000000 Binary files a/content/sesionBonus/img/17.png and /dev/null differ diff --git a/content/sesionBonus/img/18.png b/content/sesionBonus/img/18.png deleted file mode 100644 index 8a4a29e..0000000 Binary files a/content/sesionBonus/img/18.png and /dev/null differ diff --git a/content/sesionBonus/img/19.png b/content/sesionBonus/img/19.png deleted file mode 100644 index e1550b2..0000000 Binary files a/content/sesionBonus/img/19.png and /dev/null differ diff --git a/content/sesionBonus/img/20.png b/content/sesionBonus/img/20.png deleted file mode 100644 index e6469f7..0000000 Binary files a/content/sesionBonus/img/20.png and /dev/null differ diff --git a/content/sesionBonus/img/21.png b/content/sesionBonus/img/21.png deleted file mode 100644 index 8c67f08..0000000 Binary files a/content/sesionBonus/img/21.png and /dev/null differ diff --git a/content/sesionBonus/img/22.png b/content/sesionBonus/img/22.png deleted file mode 100644 index 90c1e7a..0000000 Binary files a/content/sesionBonus/img/22.png and /dev/null differ diff --git a/content/sesionBonus/img/23.png b/content/sesionBonus/img/23.png deleted file mode 100644 index 2affdf1..0000000 Binary files a/content/sesionBonus/img/23.png and /dev/null differ diff --git a/content/sesionBonus/img/24.png b/content/sesionBonus/img/24.png deleted file mode 100644 index 08b5692..0000000 Binary files a/content/sesionBonus/img/24.png and /dev/null differ diff --git a/content/sesionBonus/img/25.png b/content/sesionBonus/img/25.png deleted file mode 100644 index 936182f..0000000 Binary files a/content/sesionBonus/img/25.png and /dev/null differ diff --git a/content/sesionBonus/img/26.png b/content/sesionBonus/img/26.png deleted file mode 100644 index 52f7d8a..0000000 Binary files a/content/sesionBonus/img/26.png and /dev/null differ diff --git a/content/sesionBonus/img/27.png b/content/sesionBonus/img/27.png deleted file mode 100644 index ab7b452..0000000 Binary files a/content/sesionBonus/img/27.png and /dev/null differ diff --git a/content/sesionBonus/img/28.png b/content/sesionBonus/img/28.png deleted file mode 100644 index 8b2df03..0000000 Binary files a/content/sesionBonus/img/28.png and /dev/null differ diff --git a/content/sesionBonus/img/29.png b/content/sesionBonus/img/29.png deleted file mode 100644 index 718c662..0000000 Binary files a/content/sesionBonus/img/29.png and /dev/null differ diff --git a/content/sesionBonus/img/30.png b/content/sesionBonus/img/30.png deleted file mode 100644 index fa9788f..0000000 Binary files a/content/sesionBonus/img/30.png and /dev/null differ diff --git a/content/sesionBonus/img/31.png b/content/sesionBonus/img/31.png deleted file mode 100644 index 12721ff..0000000 Binary files a/content/sesionBonus/img/31.png and /dev/null differ diff --git a/content/sesionBonus/index.html b/content/sesionBonus/index.html deleted file mode 100644 index cc51a0a..0000000 --- a/content/sesionBonus/index.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - Sesión Bonus | Python Study Group | Fundamentals - - - - - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/css/layout.scss b/css/layout.scss deleted file mode 100644 index f499fdd..0000000 --- a/css/layout.scss +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Layout helpers. - */ - -// Stretch an element vertically based on available space -.reveal .stretch, -.reveal .r-stretch { - max-width: none; - max-height: none; -} - -.reveal pre.stretch code, -.reveal pre.r-stretch code { - height: 100%; - max-height: 100%; - box-sizing: border-box; -} - -// Text that auto-fits its container -.reveal .r-fit-text { - display: inline-block; // https://github.com/rikschennink/fitty#performance - white-space: nowrap; -} - -// Stack multiple elements on top of each other -.reveal .r-stack { - display: grid; -} - -.reveal .r-stack > * { - grid-area: 1/1; - margin: auto; -} - -// Horizontal and vertical stacks -.reveal .r-vstack, -.reveal .r-hstack { - display: flex; - - img, video { - min-width: 0; - min-height: 0; - object-fit: contain; - } -} - -.reveal .r-vstack { - flex-direction: column; - align-items: center; - justify-content: center; -} - -.reveal .r-hstack { - flex-direction: row; - align-items: center; - justify-content: center; -} - -// Naming based on tailwindcss -.reveal .items-stretch { align-items: stretch; } -.reveal .items-start { align-items: flex-start; } -.reveal .items-center { align-items: center; } -.reveal .items-end { align-items: flex-end; } - -.reveal .justify-between { justify-content: space-between; } -.reveal .justify-around { justify-content: space-around; } -.reveal .justify-start { justify-content: flex-start; } -.reveal .justify-center { justify-content: center; } -.reveal .justify-end { justify-content: flex-end; } diff --git a/css/print/paper.scss b/css/print/paper.scss deleted file mode 100644 index 32fab8a..0000000 --- a/css/print/paper.scss +++ /dev/null @@ -1,166 +0,0 @@ - -@media print { - html:not(.print-pdf) { - overflow: visible; - width: auto; - height: auto; - - body { - margin: 0; - padding: 0; - overflow: visible; - } - } - - html:not(.print-pdf) .reveal { - background: #fff; - font-size: 20pt; - - .controls, - .state-background, - .progress, - .backgrounds, - .slide-number { - display: none !important; - } - - p, td, li { - font-size: 20pt!important; - color: #000; - } - - h1,h2,h3,h4,h5,h6 { - color: #000!important; - height: auto; - line-height: normal; - text-align: left; - letter-spacing: normal; - } - - h1 { font-size: 28pt !important; } - h2 { font-size: 24pt !important; } - h3 { font-size: 22pt !important; } - h4 { font-size: 22pt !important; font-variant: small-caps; } - h5 { font-size: 21pt !important; } - h6 { font-size: 20pt !important; font-style: italic; } - - a:link, - a:visited { - color: #000 !important; - font-weight: bold; - text-decoration: underline; - } - - ul, ol, div, p { - visibility: visible; - position: static; - width: auto; - height: auto; - display: block; - overflow: visible; - margin: 0; - text-align: left !important; - } - pre, - table { - margin-left: 0; - margin-right: 0; - } - pre code { - padding: 20px; - } - blockquote { - margin: 20px 0; - } - - .slides { - position: static !important; - width: auto !important; - height: auto !important; - - left: 0 !important; - top: 0 !important; - margin-left: 0 !important; - margin-top: 0 !important; - padding: 0 !important; - zoom: 1 !important; - transform: none !important; - - overflow: visible !important; - display: block !important; - - text-align: left !important; - perspective: none; - - perspective-origin: 50% 50%; - } - .slides section { - visibility: visible !important; - position: static !important; - width: auto !important; - height: auto !important; - display: block !important; - overflow: visible !important; - - left: 0 !important; - top: 0 !important; - margin-left: 0 !important; - margin-top: 0 !important; - padding: 60px 20px !important; - z-index: auto !important; - - opacity: 1 !important; - - page-break-after: always !important; - - transform-style: flat !important; - transform: none !important; - transition: none !important; - } - .slides section.stack { - padding: 0 !important; - } - .slides section:last-of-type { - page-break-after: avoid !important; - } - .slides section .fragment { - opacity: 1 !important; - visibility: visible !important; - - transform: none !important; - } - - .r-fit-text { - white-space: normal !important; - } - - section img { - display: block; - margin: 15px 0px; - background: rgba(255,255,255,1); - border: 1px solid #666; - box-shadow: none; - } - - section small { - font-size: 0.8em; - } - - .hljs { - max-height: 100%; - white-space: pre-wrap; - word-wrap: break-word; - word-break: break-word; - font-size: 15pt; - } - - .hljs .hljs-ln-numbers { - white-space: nowrap; - } - - .hljs td { - font-size: inherit !important; - color: inherit !important; - } - } -} diff --git a/css/print/pdf.scss b/css/print/pdf.scss deleted file mode 100644 index 0a1c2bf..0000000 --- a/css/print/pdf.scss +++ /dev/null @@ -1,159 +0,0 @@ -/** - * This stylesheet is used to print reveal.js - * presentations to PDF. - * - * https://revealjs.com/pdf-export/ - */ - -html.reveal-print { - * { - -webkit-print-color-adjust: exact; - } - - & { - width: 100%; - height: 100%; - overflow: visible; - } - - body { - margin: 0 auto !important; - border: 0; - padding: 0; - float: none !important; - overflow: visible; - } - - /* Remove any elements not needed in print. */ - .nestedarrow, - .reveal .controls, - .reveal .progress, - .reveal .playback, - .reveal.overview, - .state-background { - display: none !important; - } - - .reveal pre code { - overflow: hidden !important; - } - - .reveal { - width: auto !important; - height: auto !important; - overflow: hidden !important; - } - .reveal .slides { - position: static; - width: 100% !important; - height: auto !important; - zoom: 1 !important; - pointer-events: initial; - - left: auto; - top: auto; - margin: 0 !important; - padding: 0 !important; - - overflow: visible; - display: block; - - perspective: none; - perspective-origin: 50% 50%; - } - - .reveal .slides .pdf-page { - position: relative; - overflow: hidden; - z-index: 1; - - page-break-after: always; - } - - .reveal .slides .pdf-page:last-of-type { - page-break-after: avoid; - } - - .reveal .slides section { - visibility: visible !important; - display: block !important; - position: absolute !important; - - margin: 0 !important; - padding: 0 !important; - box-sizing: border-box !important; - min-height: 1px; - - opacity: 1 !important; - - transform-style: flat !important; - transform: none !important; - } - - .reveal section.stack { - position: relative !important; - margin: 0 !important; - padding: 0 !important; - page-break-after: avoid !important; - height: auto !important; - min-height: auto !important; - } - - .reveal img { - box-shadow: none; - } - - /* Slide backgrounds are placed inside of their slide when exporting to PDF */ - .reveal .backgrounds { - display: none; - } - .reveal .slide-background { - display: block !important; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: auto !important; - } - - /* Display slide speaker notes when 'showNotes' is enabled */ - .reveal.show-notes { - max-width: none; - max-height: none; - } - .reveal .speaker-notes-pdf { - display: block; - width: 100%; - height: auto; - max-height: none; - top: auto; - right: auto; - bottom: auto; - left: auto; - z-index: 100; - } - - /* Layout option which makes notes appear on a separate page */ - .reveal .speaker-notes-pdf[data-layout="separate-page"] { - position: relative; - color: inherit; - background-color: transparent; - padding: 20px; - page-break-after: always; - border: 0; - } - - /* Display slide numbers when 'slideNumber' is enabled */ - .reveal .slide-number-pdf { - display: block; - position: absolute; - font-size: 14px; - visibility: visible; - } - - /* This accessibility tool is not useful in PDF and breaks it visually */ - .aria-status { - display: none; - } -} diff --git a/css/reveal.scss b/css/reveal.scss deleted file mode 100644 index 0a3ade7..0000000 --- a/css/reveal.scss +++ /dev/null @@ -1,2109 +0,0 @@ -@use "sass:math"; - -/** - * reveal.js - * http://revealjs.com - * MIT licensed - * - * Copyright (C) Hakim El Hattab, https://hakim.se - */ - -@import 'layout'; - -/********************************************* - * GLOBAL STYLES - *********************************************/ - -html.reveal-full-page { - width: 100%; - height: 100%; - height: 100vh; - height: calc( var(--vh, 1vh) * 100 ); - height: 100svh; - overflow: hidden; -} - -.reveal-viewport { - height: 100%; - overflow: hidden; - position: relative; - line-height: 1; - margin: 0; - - background-color: #fff; - color: #000; - - --r-controls-spacing: 12px; -} - -// Force the presentation to cover the full viewport when we -// enter fullscreen mode. Fixes sizing issues in Safari. -.reveal-viewport:fullscreen { - top: 0 !important; - left: 0 !important; - width: 100% !important; - height: 100% !important; - transform: none !important; -} - - -/********************************************* - * VIEW FRAGMENTS - *********************************************/ - -.reveal .fragment { - transition: all .2s ease; - - &:not(.custom) { - opacity: 0; - visibility: hidden; - will-change: opacity; - } - - &.visible { - opacity: 1; - visibility: inherit; - } - - &.disabled { - transition: none; - } -} - -.reveal .fragment.grow { - opacity: 1; - visibility: inherit; - - &.visible { - transform: scale( 1.3 ); - } -} - -.reveal .fragment.shrink { - opacity: 1; - visibility: inherit; - - &.visible { - transform: scale( 0.7 ); - } -} - -.reveal .fragment.zoom-in { - transform: scale( 0.1 ); - - &.visible { - transform: none; - } -} - -.reveal .fragment.fade-out { - opacity: 1; - visibility: inherit; - - &.visible { - opacity: 0; - visibility: hidden; - } -} - -.reveal .fragment.semi-fade-out { - opacity: 1; - visibility: inherit; - - &.visible { - opacity: 0.5; - visibility: inherit; - } -} - -.reveal .fragment.strike { - opacity: 1; - visibility: inherit; - - &.visible { - text-decoration: line-through; - } -} - -.reveal .fragment.fade-up { - transform: translate(0, 40px); - - &.visible { - transform: translate(0, 0); - } -} - -.reveal .fragment.fade-down { - transform: translate(0, -40px); - - &.visible { - transform: translate(0, 0); - } -} - -.reveal .fragment.fade-right { - transform: translate(-40px, 0); - - &.visible { - transform: translate(0, 0); - } -} - -.reveal .fragment.fade-left { - transform: translate(40px, 0); - - &.visible { - transform: translate(0, 0); - } -} - -.reveal .fragment.fade-in-then-out, -.reveal .fragment.current-visible { - opacity: 0; - visibility: hidden; - - &.current-fragment { - opacity: 1; - visibility: inherit; - } -} - -.reveal .fragment.fade-in-then-semi-out { - opacity: 0; - visibility: hidden; - - &.visible { - opacity: 0.5; - visibility: inherit; - } - - &.current-fragment { - opacity: 1; - visibility: inherit; - } -} - -.reveal .fragment.highlight-red, -.reveal .fragment.highlight-current-red, -.reveal .fragment.highlight-green, -.reveal .fragment.highlight-current-green, -.reveal .fragment.highlight-blue, -.reveal .fragment.highlight-current-blue { - opacity: 1; - visibility: inherit; -} - .reveal .fragment.highlight-red.visible { - color: #ff2c2d - } - .reveal .fragment.highlight-green.visible { - color: #17ff2e; - } - .reveal .fragment.highlight-blue.visible { - color: #1b91ff; - } - -.reveal .fragment.highlight-current-red.current-fragment { - color: #ff2c2d -} -.reveal .fragment.highlight-current-green.current-fragment { - color: #17ff2e; -} -.reveal .fragment.highlight-current-blue.current-fragment { - color: #1b91ff; -} - - -/********************************************* - * DEFAULT ELEMENT STYLES - *********************************************/ - -/* Fixes issue in Chrome where italic fonts did not appear when printing to PDF */ -.reveal:after { - content: ''; - font-style: italic; -} - -.reveal iframe { - z-index: 1; -} - -/** Prevents layering issues in certain browser/transition combinations */ -.reveal a { - position: relative; -} - - -/********************************************* - * CONTROLS - *********************************************/ - -@keyframes bounce-right { - 0%, 10%, 25%, 40%, 50% {transform: translateX(0);} - 20% {transform: translateX(10px);} - 30% {transform: translateX(-5px);} -} - -@keyframes bounce-left { - 0%, 10%, 25%, 40%, 50% {transform: translateX(0);} - 20% {transform: translateX(-10px);} - 30% {transform: translateX(5px);} -} - -@keyframes bounce-down { - 0%, 10%, 25%, 40%, 50% {transform: translateY(0);} - 20% {transform: translateY(10px);} - 30% {transform: translateY(-5px);} -} - -$controlArrowSize: 3.6em; -$controlArrowSpacing: 1.4em; -$controlArrowLength: 2.6em; -$controlArrowThickness: 0.5em; -$controlsArrowAngle: 45deg; -$controlsArrowAngleHover: 40deg; -$controlsArrowAngleActive: 36deg; - -@mixin controlsArrowTransform( $angle ) { - &:before { - transform: translateX(($controlArrowSize - $controlArrowLength)*0.5) translateY(($controlArrowSize - $controlArrowThickness)*0.5) rotate( $angle ); - } - - &:after { - transform: translateX(($controlArrowSize - $controlArrowLength)*0.5) translateY(($controlArrowSize - $controlArrowThickness)*0.5) rotate( -$angle ); - } -} - -.reveal .controls { - display: none; - position: absolute; - top: auto; - bottom: var(--r-controls-spacing); - right: var(--r-controls-spacing); - left: auto; - z-index: 11; - color: #000; - pointer-events: none; - font-size: 10px; - - button { - position: absolute; - padding: 0; - background-color: transparent; - border: 0; - outline: 0; - cursor: pointer; - color: currentColor; - transform: scale(.9999); - transition: color 0.2s ease, - opacity 0.2s ease, - transform 0.2s ease; - z-index: 2; // above slides - pointer-events: auto; - font-size: inherit; - - visibility: hidden; - opacity: 0; - - -webkit-appearance: none; - -webkit-tap-highlight-color: rgba( 0, 0, 0, 0 ); - } - - .controls-arrow:before, - .controls-arrow:after { - content: ''; - position: absolute; - top: 0; - left: 0; - width: $controlArrowLength; - height: $controlArrowThickness; - border-radius: $controlArrowThickness*0.5; - background-color: currentColor; - - transition: all 0.15s ease, background-color 0.8s ease; - transform-origin: math.div(floor(($controlArrowThickness*0.5)*10), 10) 50%; - will-change: transform; - } - - .controls-arrow { - position: relative; - width: $controlArrowSize; - height: $controlArrowSize; - - @include controlsArrowTransform( $controlsArrowAngle ); - - &:hover { - @include controlsArrowTransform( $controlsArrowAngleHover ); - } - - &:active { - @include controlsArrowTransform( $controlsArrowAngleActive ); - } - } - - .navigate-left { - right: $controlArrowSize + $controlArrowSpacing*2; - bottom: $controlArrowSpacing + $controlArrowSize*0.5; - transform: translateX( -10px ); - - &.highlight { - animation: bounce-left 2s 50 both ease-out; - } - } - - .navigate-right { - right: 0; - bottom: $controlArrowSpacing + $controlArrowSize*0.5; - transform: translateX( 10px ); - - .controls-arrow { - transform: rotate( 180deg ); - } - - &.highlight { - animation: bounce-right 2s 50 both ease-out; - } - } - - .navigate-up { - right: $controlArrowSpacing + $controlArrowSize*0.5; - bottom: $controlArrowSpacing*2 + $controlArrowSize; - transform: translateY( -10px ); - - .controls-arrow { - transform: rotate( 90deg ); - } - } - - .navigate-down { - right: $controlArrowSpacing + $controlArrowSize*0.5; - bottom: -$controlArrowSpacing; - padding-bottom: $controlArrowSpacing; - transform: translateY( 10px ); - - .controls-arrow { - transform: rotate( -90deg ); - } - - &.highlight { - animation: bounce-down 2s 50 both ease-out; - } - } - - // Back arrow style: "faded": - // Deemphasize backwards navigation arrows in favor of drawing - // attention to forwards navigation - &[data-controls-back-arrows="faded"] .navigate-up.enabled { - opacity: 0.3; - - &:hover { - opacity: 1; - } - } - - // Back arrow style: "hidden": - // Never show arrows for backwards navigation - &[data-controls-back-arrows="hidden"] .navigate-up.enabled { - opacity: 0; - visibility: hidden; - } - - // Any control button that can be clicked is "enabled" - .enabled { - visibility: visible; - opacity: 0.9; - cursor: pointer; - transform: none; - } - - // Any control button that leads to showing or hiding - // a fragment - .enabled.fragmented { - opacity: 0.5; - } - - .enabled:hover, - .enabled.fragmented:hover { - opacity: 1; - } -} - -.reveal:not(.rtl) .controls { - // Back arrow style: "faded": - // Deemphasize left arrow - &[data-controls-back-arrows="faded"] .navigate-left.enabled { - opacity: 0.3; - - &:hover { - opacity: 1; - } - } - - // Back arrow style: "hidden": - // Never show left arrow - &[data-controls-back-arrows="hidden"] .navigate-left.enabled { - opacity: 0; - visibility: hidden; - } -} - -.reveal.rtl .controls { - // Back arrow style: "faded": - // Deemphasize right arrow in RTL mode - &[data-controls-back-arrows="faded"] .navigate-right.enabled { - opacity: 0.3; - - &:hover { - opacity: 1; - } - } - - // Back arrow style: "hidden": - // Never show right arrow in RTL mode - &[data-controls-back-arrows="hidden"] .navigate-right.enabled { - opacity: 0; - visibility: hidden; - } -} - -.reveal[data-navigation-mode="linear"].has-horizontal-slides .navigate-up, -.reveal[data-navigation-mode="linear"].has-horizontal-slides .navigate-down { - display: none; -} - -// Adjust the layout when there are no vertical slides -.reveal[data-navigation-mode="linear"].has-horizontal-slides .navigate-left, -.reveal:not(.has-vertical-slides) .controls .navigate-left { - bottom: $controlArrowSpacing; - right: 0.5em + $controlArrowSpacing + $controlArrowSize; -} - -.reveal[data-navigation-mode="linear"].has-horizontal-slides .navigate-right, -.reveal:not(.has-vertical-slides) .controls .navigate-right { - bottom: $controlArrowSpacing; - right: 0.5em; -} - -// Adjust the layout when there are no horizontal slides -.reveal:not(.has-horizontal-slides) .controls .navigate-up { - right: $controlArrowSpacing; - bottom: $controlArrowSpacing + $controlArrowSize; -} -.reveal:not(.has-horizontal-slides) .controls .navigate-down { - right: $controlArrowSpacing; - bottom: 0.5em; -} - -// Invert arrows based on background color -.reveal.has-dark-background .controls { - color: #fff; -} -.reveal.has-light-background .controls { - color: #000; -} - -// Disable active states on touch devices -.reveal.no-hover .controls .controls-arrow:hover, -.reveal.no-hover .controls .controls-arrow:active { - @include controlsArrowTransform( $controlsArrowAngle ); -} - -// Edge aligned controls layout -@media screen and (min-width: 500px) { - - .reveal-viewport { - --r-controls-spacing: 0.8em; - } - - .reveal .controls[data-controls-layout="edges"] { - & { - top: 0; - right: 0; - bottom: 0; - left: 0; - } - - .navigate-left, - .navigate-right, - .navigate-up, - .navigate-down { - bottom: auto; - right: auto; - } - - .navigate-left { - top: 50%; - left: var(--r-controls-spacing); - margin-top: -$controlArrowSize*0.5; - } - - .navigate-right { - top: 50%; - right: var(--r-controls-spacing); - margin-top: -$controlArrowSize*0.5; - } - - .navigate-up { - top: var(--r-controls-spacing); - left: 50%; - margin-left: -$controlArrowSize*0.5; - } - - .navigate-down { - bottom: calc(var(--r-controls-spacing) - #{$controlArrowSpacing} + 0.3em); - left: 50%; - margin-left: -$controlArrowSize*0.5; - } - } - -} - - -/********************************************* - * PROGRESS BAR - *********************************************/ - -.reveal .progress { - position: absolute; - display: none; - height: 3px; - width: 100%; - bottom: 0; - left: 0; - z-index: 10; - - background-color: rgba( 0, 0, 0, 0.2 ); - color: #fff; -} - .reveal .progress:after { - content: ''; - display: block; - position: absolute; - height: 10px; - width: 100%; - top: -10px; - } - .reveal .progress span { - display: block; - height: 100%; - width: 100%; - - background-color: currentColor; - transition: transform 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - transform-origin: 0 0; - transform: scaleX(0); - } - -/********************************************* - * SLIDE NUMBER - *********************************************/ - -.reveal .slide-number { - position: absolute; - display: block; - right: 8px; - bottom: 8px; - z-index: 31; - font-family: Helvetica, sans-serif; - font-size: 12px; - line-height: 1; - color: #fff; - background-color: rgba( 0, 0, 0, 0.4 ); - padding: 5px; -} - -.reveal .slide-number a { - color: currentColor; -} - -.reveal .slide-number-delimiter { - margin: 0 3px; -} - -/********************************************* - * SLIDES - *********************************************/ - -.reveal { - position: relative; - width: 100%; - height: 100%; - overflow: hidden; - touch-action: pinch-zoom; -} - -// Swiping on an embedded deck should not block page scrolling -.reveal.embedded { - touch-action: pan-y; -} - -.reveal .slides { - position: absolute; - width: 100%; - height: 100%; - top: 0; - right: 0; - bottom: 0; - left: 0; - margin: auto; - pointer-events: none; - - overflow: visible; - z-index: 1; - text-align: center; - perspective: 600px; - perspective-origin: 50% 40%; -} - -.reveal .slides>section { - perspective: 600px; -} - -.reveal .slides>section, -.reveal .slides>section>section { - display: none; - position: absolute; - width: 100%; - pointer-events: auto; - - z-index: 10; - transform-style: flat; - transition: transform-origin 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985), - transform 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985), - visibility 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985), - opacity 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985); -} - -/* Global transition speed settings */ -.reveal[data-transition-speed="fast"] .slides section { - transition-duration: 400ms; -} -.reveal[data-transition-speed="slow"] .slides section { - transition-duration: 1200ms; -} - -/* Slide-specific transition speed overrides */ -.reveal .slides section[data-transition-speed="fast"] { - transition-duration: 400ms; -} -.reveal .slides section[data-transition-speed="slow"] { - transition-duration: 1200ms; -} - -.reveal .slides>section.stack { - padding-top: 0; - padding-bottom: 0; - pointer-events: none; - height: 100%; -} - -.reveal .slides>section.present, -.reveal .slides>section>section.present { - display: block; - z-index: 11; - opacity: 1; -} - -.reveal .slides>section:empty, -.reveal .slides>section>section:empty, -.reveal .slides>section[data-background-interactive], -.reveal .slides>section>section[data-background-interactive] { - pointer-events: none; -} - -.reveal.center, -.reveal.center .slides, -.reveal.center .slides section { - min-height: 0 !important; -} - -/* Don't allow interaction with invisible slides */ -.reveal .slides>section:not(.present), -.reveal .slides>section>section:not(.present) { - pointer-events: none; -} - -.reveal.overview .slides>section, -.reveal.overview .slides>section>section { - pointer-events: auto; -} - -.reveal .slides>section.past, -.reveal .slides>section.future, -.reveal .slides>section.past>section, -.reveal .slides>section.future>section, -.reveal .slides>section>section.past, -.reveal .slides>section>section.future { - opacity: 0; -} - - -/********************************************* - * Mixins for readability of transitions - *********************************************/ - -@mixin transition-global($style) { - .reveal .slides section[data-transition=#{$style}], - .reveal.#{$style} .slides section:not([data-transition]) { - @content; - } -} -@mixin transition-stack($style) { - .reveal .slides section[data-transition=#{$style}].stack, - .reveal.#{$style} .slides section.stack { - @content; - } -} -@mixin transition-horizontal-past($style) { - .reveal .slides>section[data-transition=#{$style}].past, - .reveal .slides>section[data-transition~=#{$style}-out].past, - .reveal.#{$style} .slides>section:not([data-transition]).past { - @content; - } -} -@mixin transition-horizontal-future($style) { - .reveal .slides>section[data-transition=#{$style}].future, - .reveal .slides>section[data-transition~=#{$style}-in].future, - .reveal.#{$style} .slides>section:not([data-transition]).future { - @content; - } -} - -@mixin transition-vertical-past($style) { - .reveal .slides>section>section[data-transition=#{$style}].past, - .reveal .slides>section>section[data-transition~=#{$style}-out].past, - .reveal.#{$style} .slides>section>section:not([data-transition]).past { - @content; - } -} -@mixin transition-vertical-future($style) { - .reveal .slides>section>section[data-transition=#{$style}].future, - .reveal .slides>section>section[data-transition~=#{$style}-in].future, - .reveal.#{$style} .slides>section>section:not([data-transition]).future { - @content; - } -} - -/********************************************* - * SLIDE TRANSITION - * Aliased 'linear' for backwards compatibility - *********************************************/ - -@each $stylename in slide, linear { - @include transition-horizontal-past(#{$stylename}) { - transform: translate(-150%, 0); - } - @include transition-horizontal-future(#{$stylename}) { - transform: translate(150%, 0); - } - @include transition-vertical-past(#{$stylename}) { - transform: translate(0, -150%); - } - @include transition-vertical-future(#{$stylename}) { - transform: translate(0, 150%); - } -} - -/********************************************* - * CONVEX TRANSITION - * Aliased 'default' for backwards compatibility - *********************************************/ - -@each $stylename in default, convex { - @include transition-stack(#{$stylename}) { - transform-style: preserve-3d; - } - - @include transition-horizontal-past(#{$stylename}) { - transform: translate3d(-100%, 0, 0) rotateY(-90deg) translate3d(-100%, 0, 0); - } - @include transition-horizontal-future(#{$stylename}) { - transform: translate3d(100%, 0, 0) rotateY(90deg) translate3d(100%, 0, 0); - } - @include transition-vertical-past(#{$stylename}) { - transform: translate3d(0, -300px, 0) rotateX(70deg) translate3d(0, -300px, 0); - } - @include transition-vertical-future(#{$stylename}) { - transform: translate3d(0, 300px, 0) rotateX(-70deg) translate3d(0, 300px, 0); - } -} - -/********************************************* - * CONCAVE TRANSITION - *********************************************/ - -@include transition-stack(concave) { - transform-style: preserve-3d; -} - -@include transition-horizontal-past(concave) { - transform: translate3d(-100%, 0, 0) rotateY(90deg) translate3d(-100%, 0, 0); -} -@include transition-horizontal-future(concave) { - transform: translate3d(100%, 0, 0) rotateY(-90deg) translate3d(100%, 0, 0); -} -@include transition-vertical-past(concave) { - transform: translate3d(0, -80%, 0) rotateX(-70deg) translate3d(0, -80%, 0); -} -@include transition-vertical-future(concave) { - transform: translate3d(0, 80%, 0) rotateX(70deg) translate3d(0, 80%, 0); -} - - -/********************************************* - * ZOOM TRANSITION - *********************************************/ - -@include transition-global(zoom) { - transition-timing-function: ease; -} -@include transition-horizontal-past(zoom) { - visibility: hidden; - transform: scale(16); -} -@include transition-horizontal-future(zoom) { - visibility: hidden; - transform: scale(0.2); -} -@include transition-vertical-past(zoom) { - transform: scale(16); -} -@include transition-vertical-future(zoom) { - transform: scale(0.2); -} - - -/********************************************* - * CUBE TRANSITION - * - * WARNING: - * this is deprecated and will be removed in a - * future version. - *********************************************/ - -.reveal.cube .slides { - perspective: 1300px; -} - -.reveal.cube .slides section { - padding: 30px; - min-height: 700px; - backface-visibility: hidden; - box-sizing: border-box; - transform-style: preserve-3d; -} - .reveal.center.cube .slides section { - min-height: 0; - } - .reveal.cube .slides section:not(.stack):before { - content: ''; - position: absolute; - display: block; - width: 100%; - height: 100%; - left: 0; - top: 0; - background: rgba(0,0,0,0.1); - border-radius: 4px; - transform: translateZ( -20px ); - } - .reveal.cube .slides section:not(.stack):after { - content: ''; - position: absolute; - display: block; - width: 90%; - height: 30px; - left: 5%; - bottom: 0; - background: none; - z-index: 1; - - border-radius: 4px; - box-shadow: 0px 95px 25px rgba(0,0,0,0.2); - transform: translateZ(-90px) rotateX( 65deg ); - } - -.reveal.cube .slides>section.stack { - padding: 0; - background: none; -} - -.reveal.cube .slides>section.past { - transform-origin: 100% 0%; - transform: translate3d(-100%, 0, 0) rotateY(-90deg); -} - -.reveal.cube .slides>section.future { - transform-origin: 0% 0%; - transform: translate3d(100%, 0, 0) rotateY(90deg); -} - -.reveal.cube .slides>section>section.past { - transform-origin: 0% 100%; - transform: translate3d(0, -100%, 0) rotateX(90deg); -} - -.reveal.cube .slides>section>section.future { - transform-origin: 0% 0%; - transform: translate3d(0, 100%, 0) rotateX(-90deg); -} - - -/********************************************* - * PAGE TRANSITION - * - * WARNING: - * this is deprecated and will be removed in a - * future version. - *********************************************/ - -.reveal.page .slides { - perspective-origin: 0% 50%; - perspective: 3000px; -} - -.reveal.page .slides section { - padding: 30px; - min-height: 700px; - box-sizing: border-box; - transform-style: preserve-3d; -} - .reveal.page .slides section.past { - z-index: 12; - } - .reveal.page .slides section:not(.stack):before { - content: ''; - position: absolute; - display: block; - width: 100%; - height: 100%; - left: 0; - top: 0; - background: rgba(0,0,0,0.1); - transform: translateZ( -20px ); - } - .reveal.page .slides section:not(.stack):after { - content: ''; - position: absolute; - display: block; - width: 90%; - height: 30px; - left: 5%; - bottom: 0; - background: none; - z-index: 1; - - border-radius: 4px; - box-shadow: 0px 95px 25px rgba(0,0,0,0.2); - - -webkit-transform: translateZ(-90px) rotateX( 65deg ); - } - -.reveal.page .slides>section.stack { - padding: 0; - background: none; -} - -.reveal.page .slides>section.past { - transform-origin: 0% 0%; - transform: translate3d(-40%, 0, 0) rotateY(-80deg); -} - -.reveal.page .slides>section.future { - transform-origin: 100% 0%; - transform: translate3d(0, 0, 0); -} - -.reveal.page .slides>section>section.past { - transform-origin: 0% 0%; - transform: translate3d(0, -40%, 0) rotateX(80deg); -} - -.reveal.page .slides>section>section.future { - transform-origin: 0% 100%; - transform: translate3d(0, 0, 0); -} - - -/********************************************* - * FADE TRANSITION - *********************************************/ - -.reveal .slides section[data-transition=fade], -.reveal.fade .slides section:not([data-transition]), -.reveal.fade .slides>section>section:not([data-transition]) { - transform: none; - transition: opacity 0.5s; -} - - -.reveal.fade.overview .slides section, -.reveal.fade.overview .slides>section>section { - transition: none; -} - - -/********************************************* - * NO TRANSITION - *********************************************/ - -@include transition-global(none) { - transform: none; - transition: none; -} - - -/********************************************* - * PAUSED MODE - *********************************************/ - -.reveal .pause-overlay { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: black; - visibility: hidden; - opacity: 0; - z-index: 100; - transition: all 1s ease; -} - -.reveal .pause-overlay .resume-button { - position: absolute; - bottom: 20px; - right: 20px; - color: #ccc; - border-radius: 2px; - padding: 6px 14px; - border: 2px solid #ccc; - font-size: 16px; - background: transparent; - cursor: pointer; - - &:hover { - color: #fff; - border-color: #fff; - } -} - -.reveal.paused .pause-overlay { - visibility: visible; - opacity: 1; -} - - -/********************************************* - * FALLBACK - *********************************************/ - -.reveal .no-transition, -.reveal .no-transition *, -.reveal .slides.disable-slide-transitions section { - transition: none !important; -} - -.reveal .slides.disable-slide-transitions section { - transform: none !important; -} - - -/********************************************* - * PER-SLIDE BACKGROUNDS - *********************************************/ - -.reveal .backgrounds { - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - perspective: 600px; -} - .reveal .slide-background { - display: none; - position: absolute; - width: 100%; - height: 100%; - opacity: 0; - visibility: hidden; - overflow: hidden; - - background-color: rgba( 0, 0, 0, 0 ); - - transition: all 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - } - - .reveal .slide-background-content { - position: absolute; - width: 100%; - height: 100%; - - background-position: 50% 50%; - background-repeat: no-repeat; - background-size: cover; - } - - .reveal .slide-background.stack { - display: block; - } - - .reveal .slide-background.present { - opacity: 1; - visibility: visible; - z-index: 2; - } - - .print-pdf .reveal .slide-background { - opacity: 1 !important; - visibility: visible !important; - } - -/* Video backgrounds */ -.reveal .slide-background video { - position: absolute; - width: 100%; - height: 100%; - max-width: none; - max-height: none; - top: 0; - left: 0; - object-fit: cover; -} - .reveal .slide-background[data-background-size="contain"] video { - object-fit: contain; - } - -/* Immediate transition style */ -.reveal[data-background-transition=none]>.backgrounds .slide-background:not([data-background-transition]), -.reveal>.backgrounds .slide-background[data-background-transition=none] { - transition: none; -} - -/* Slide */ -.reveal[data-background-transition=slide]>.backgrounds .slide-background:not([data-background-transition]), -.reveal>.backgrounds .slide-background[data-background-transition=slide] { - opacity: 1; -} - .reveal[data-background-transition=slide]>.backgrounds .slide-background.past:not([data-background-transition]), - .reveal>.backgrounds .slide-background.past[data-background-transition=slide] { - transform: translate(-100%, 0); - } - .reveal[data-background-transition=slide]>.backgrounds .slide-background.future:not([data-background-transition]), - .reveal>.backgrounds .slide-background.future[data-background-transition=slide] { - transform: translate(100%, 0); - } - - .reveal[data-background-transition=slide]>.backgrounds .slide-background>.slide-background.past:not([data-background-transition]), - .reveal>.backgrounds .slide-background>.slide-background.past[data-background-transition=slide] { - transform: translate(0, -100%); - } - .reveal[data-background-transition=slide]>.backgrounds .slide-background>.slide-background.future:not([data-background-transition]), - .reveal>.backgrounds .slide-background>.slide-background.future[data-background-transition=slide] { - transform: translate(0, 100%); - } - - -/* Convex */ -.reveal[data-background-transition=convex]>.backgrounds .slide-background.past:not([data-background-transition]), -.reveal>.backgrounds .slide-background.past[data-background-transition=convex] { - opacity: 0; - transform: translate3d(-100%, 0, 0) rotateY(-90deg) translate3d(-100%, 0, 0); -} -.reveal[data-background-transition=convex]>.backgrounds .slide-background.future:not([data-background-transition]), -.reveal>.backgrounds .slide-background.future[data-background-transition=convex] { - opacity: 0; - transform: translate3d(100%, 0, 0) rotateY(90deg) translate3d(100%, 0, 0); -} - -.reveal[data-background-transition=convex]>.backgrounds .slide-background>.slide-background.past:not([data-background-transition]), -.reveal>.backgrounds .slide-background>.slide-background.past[data-background-transition=convex] { - opacity: 0; - transform: translate3d(0, -100%, 0) rotateX(90deg) translate3d(0, -100%, 0); -} -.reveal[data-background-transition=convex]>.backgrounds .slide-background>.slide-background.future:not([data-background-transition]), -.reveal>.backgrounds .slide-background>.slide-background.future[data-background-transition=convex] { - opacity: 0; - transform: translate3d(0, 100%, 0) rotateX(-90deg) translate3d(0, 100%, 0); -} - - -/* Concave */ -.reveal[data-background-transition=concave]>.backgrounds .slide-background.past:not([data-background-transition]), -.reveal>.backgrounds .slide-background.past[data-background-transition=concave] { - opacity: 0; - transform: translate3d(-100%, 0, 0) rotateY(90deg) translate3d(-100%, 0, 0); -} -.reveal[data-background-transition=concave]>.backgrounds .slide-background.future:not([data-background-transition]), -.reveal>.backgrounds .slide-background.future[data-background-transition=concave] { - opacity: 0; - transform: translate3d(100%, 0, 0) rotateY(-90deg) translate3d(100%, 0, 0); -} - -.reveal[data-background-transition=concave]>.backgrounds .slide-background>.slide-background.past:not([data-background-transition]), -.reveal>.backgrounds .slide-background>.slide-background.past[data-background-transition=concave] { - opacity: 0; - transform: translate3d(0, -100%, 0) rotateX(-90deg) translate3d(0, -100%, 0); -} -.reveal[data-background-transition=concave]>.backgrounds .slide-background>.slide-background.future:not([data-background-transition]), -.reveal>.backgrounds .slide-background>.slide-background.future[data-background-transition=concave] { - opacity: 0; - transform: translate3d(0, 100%, 0) rotateX(90deg) translate3d(0, 100%, 0); -} - -/* Zoom */ -.reveal[data-background-transition=zoom]>.backgrounds .slide-background:not([data-background-transition]), -.reveal>.backgrounds .slide-background[data-background-transition=zoom] { - transition-timing-function: ease; -} - -.reveal[data-background-transition=zoom]>.backgrounds .slide-background.past:not([data-background-transition]), -.reveal>.backgrounds .slide-background.past[data-background-transition=zoom] { - opacity: 0; - visibility: hidden; - transform: scale(16); -} -.reveal[data-background-transition=zoom]>.backgrounds .slide-background.future:not([data-background-transition]), -.reveal>.backgrounds .slide-background.future[data-background-transition=zoom] { - opacity: 0; - visibility: hidden; - transform: scale(0.2); -} - -.reveal[data-background-transition=zoom]>.backgrounds .slide-background>.slide-background.past:not([data-background-transition]), -.reveal>.backgrounds .slide-background>.slide-background.past[data-background-transition=zoom] { - opacity: 0; - visibility: hidden; - transform: scale(16); -} -.reveal[data-background-transition=zoom]>.backgrounds .slide-background>.slide-background.future:not([data-background-transition]), -.reveal>.backgrounds .slide-background>.slide-background.future[data-background-transition=zoom] { - opacity: 0; - visibility: hidden; - transform: scale(0.2); -} - - -/* Global transition speed settings */ -.reveal[data-transition-speed="fast"]>.backgrounds .slide-background { - transition-duration: 400ms; -} -.reveal[data-transition-speed="slow"]>.backgrounds .slide-background { - transition-duration: 1200ms; -} - - -/********************************************* - * AUTO ANIMATE - *********************************************/ - -.reveal [data-auto-animate-target^="unmatched"] { - will-change: opacity; -} - -.reveal section[data-auto-animate]:not(.stack):not([data-auto-animate="running"]) [data-auto-animate-target^="unmatched"] { - opacity: 0; -} - - -/********************************************* - * OVERVIEW - *********************************************/ - -.reveal.overview { - perspective-origin: 50% 50%; - perspective: 700px; - - .slides { - // Fixes overview rendering errors in FF48+, not applied to - // other browsers since it degrades performance - -moz-transform-style: preserve-3d; - } - - .slides section { - height: 100%; - top: 0 !important; - opacity: 1 !important; - overflow: hidden; - visibility: visible !important; - cursor: pointer; - box-sizing: border-box; - } - .slides section:hover, - .slides section.present { - outline: 10px solid rgba(150,150,150,0.4); - outline-offset: 10px; - } - .slides section .fragment { - opacity: 1; - transition: none; - } - .slides section:after, - .slides section:before { - display: none !important; - } - .slides>section.stack { - padding: 0; - top: 0 !important; - background: none; - outline: none; - overflow: visible; - } - - .backgrounds { - perspective: inherit; - - // Fixes overview rendering errors in FF48+, not applied to - // other browsers since it degrades performance - -moz-transform-style: preserve-3d; - } - - .backgrounds .slide-background { - opacity: 1; - visibility: visible; - - // This can't be applied to the slide itself in Safari - outline: 10px solid rgba(150,150,150,0.1); - outline-offset: 10px; - } - - .backgrounds .slide-background.stack { - overflow: visible; - } -} - -// Disable transitions transitions while we're activating -// or deactivating the overview mode. -.reveal.overview .slides section, -.reveal.overview-deactivating .slides section { - transition: none; -} - -.reveal.overview .backgrounds .slide-background, -.reveal.overview-deactivating .backgrounds .slide-background { - transition: none; -} - - -/********************************************* - * RTL SUPPORT - *********************************************/ - -.reveal.rtl .slides, -.reveal.rtl .slides h1, -.reveal.rtl .slides h2, -.reveal.rtl .slides h3, -.reveal.rtl .slides h4, -.reveal.rtl .slides h5, -.reveal.rtl .slides h6 { - direction: rtl; - font-family: sans-serif; -} - -.reveal.rtl pre, -.reveal.rtl code { - direction: ltr; -} - -.reveal.rtl ol, -.reveal.rtl ul { - text-align: right; -} - -.reveal.rtl .progress span { - transform-origin: 100% 0; -} - -/********************************************* - * PARALLAX BACKGROUND - *********************************************/ - -.reveal.has-parallax-background .backgrounds { - transition: all 0.8s ease; -} - -/* Global transition speed settings */ -.reveal.has-parallax-background[data-transition-speed="fast"] .backgrounds { - transition-duration: 400ms; -} -.reveal.has-parallax-background[data-transition-speed="slow"] .backgrounds { - transition-duration: 1200ms; -} - - -/********************************************* - * OVERLAY FOR LINK PREVIEWS AND HELP - *********************************************/ - -$overlayHeaderHeight: 40px; -$overlayHeaderPadding: 5px; - -.reveal > .overlay { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 1000; - background: rgba( 0, 0, 0, 0.95 ); - backdrop-filter: blur( 6px ); - transition: all 0.3s ease; -} - - .reveal > .overlay .spinner { - position: absolute; - display: block; - top: 50%; - left: 50%; - width: 32px; - height: 32px; - margin: -16px 0 0 -16px; - z-index: 10; - background-image: url(data:image/gif;base64,R0lGODlhIAAgAPMAAJmZmf%2F%2F%2F6%2Bvr8nJybW1tcDAwOjo6Nvb26ioqKOjo7Ozs%2FLy8vz8%2FAAAAAAAAAAAACH%2FC05FVFNDQVBFMi4wAwEAAAAh%2FhpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh%2BQQJCgAAACwAAAAAIAAgAAAE5xDISWlhperN52JLhSSdRgwVo1ICQZRUsiwHpTJT4iowNS8vyW2icCF6k8HMMBkCEDskxTBDAZwuAkkqIfxIQyhBQBFvAQSDITM5VDW6XNE4KagNh6Bgwe60smQUB3d4Rz1ZBApnFASDd0hihh12BkE9kjAJVlycXIg7CQIFA6SlnJ87paqbSKiKoqusnbMdmDC2tXQlkUhziYtyWTxIfy6BE8WJt5YJvpJivxNaGmLHT0VnOgSYf0dZXS7APdpB309RnHOG5gDqXGLDaC457D1zZ%2FV%2FnmOM82XiHRLYKhKP1oZmADdEAAAh%2BQQJCgAAACwAAAAAIAAgAAAE6hDISWlZpOrNp1lGNRSdRpDUolIGw5RUYhhHukqFu8DsrEyqnWThGvAmhVlteBvojpTDDBUEIFwMFBRAmBkSgOrBFZogCASwBDEY%2FCZSg7GSE0gSCjQBMVG023xWBhklAnoEdhQEfyNqMIcKjhRsjEdnezB%2BA4k8gTwJhFuiW4dokXiloUepBAp5qaKpp6%2BHo7aWW54wl7obvEe0kRuoplCGepwSx2jJvqHEmGt6whJpGpfJCHmOoNHKaHx61WiSR92E4lbFoq%2BB6QDtuetcaBPnW6%2BO7wDHpIiK9SaVK5GgV543tzjgGcghAgAh%2BQQJCgAAACwAAAAAIAAgAAAE7hDISSkxpOrN5zFHNWRdhSiVoVLHspRUMoyUakyEe8PTPCATW9A14E0UvuAKMNAZKYUZCiBMuBakSQKG8G2FzUWox2AUtAQFcBKlVQoLgQReZhQlCIJesQXI5B0CBnUMOxMCenoCfTCEWBsJColTMANldx15BGs8B5wlCZ9Po6OJkwmRpnqkqnuSrayqfKmqpLajoiW5HJq7FL1Gr2mMMcKUMIiJgIemy7xZtJsTmsM4xHiKv5KMCXqfyUCJEonXPN2rAOIAmsfB3uPoAK%2B%2BG%2Bw48edZPK%2BM6hLJpQg484enXIdQFSS1u6UhksENEQAAIfkECQoAAAAsAAAAACAAIAAABOcQyEmpGKLqzWcZRVUQnZYg1aBSh2GUVEIQ2aQOE%2BG%2BcD4ntpWkZQj1JIiZIogDFFyHI0UxQwFugMSOFIPJftfVAEoZLBbcLEFhlQiqGp1Vd140AUklUN3eCA51C1EWMzMCezCBBmkxVIVHBWd3HHl9JQOIJSdSnJ0TDKChCwUJjoWMPaGqDKannasMo6WnM562R5YluZRwur0wpgqZE7NKUm%2BFNRPIhjBJxKZteWuIBMN4zRMIVIhffcgojwCF117i4nlLnY5ztRLsnOk%2BaV%2BoJY7V7m76PdkS4trKcdg0Zc0tTcKkRAAAIfkECQoAAAAsAAAAACAAIAAABO4QyEkpKqjqzScpRaVkXZWQEximw1BSCUEIlDohrft6cpKCk5xid5MNJTaAIkekKGQkWyKHkvhKsR7ARmitkAYDYRIbUQRQjWBwJRzChi9CRlBcY1UN4g0%2FVNB0AlcvcAYHRyZPdEQFYV8ccwR5HWxEJ02YmRMLnJ1xCYp0Y5idpQuhopmmC2KgojKasUQDk5BNAwwMOh2RtRq5uQuPZKGIJQIGwAwGf6I0JXMpC8C7kXWDBINFMxS4DKMAWVWAGYsAdNqW5uaRxkSKJOZKaU3tPOBZ4DuK2LATgJhkPJMgTwKCdFjyPHEnKxFCDhEAACH5BAkKAAAALAAAAAAgACAAAATzEMhJaVKp6s2nIkolIJ2WkBShpkVRWqqQrhLSEu9MZJKK9y1ZrqYK9WiClmvoUaF8gIQSNeF1Er4MNFn4SRSDARWroAIETg1iVwuHjYB1kYc1mwruwXKC9gmsJXliGxc%2BXiUCby9ydh1sOSdMkpMTBpaXBzsfhoc5l58Gm5yToAaZhaOUqjkDgCWNHAULCwOLaTmzswadEqggQwgHuQsHIoZCHQMMQgQGubVEcxOPFAcMDAYUA85eWARmfSRQCdcMe0zeP1AAygwLlJtPNAAL19DARdPzBOWSm1brJBi45soRAWQAAkrQIykShQ9wVhHCwCQCACH5BAkKAAAALAAAAAAgACAAAATrEMhJaVKp6s2nIkqFZF2VIBWhUsJaTokqUCoBq%2BE71SRQeyqUToLA7VxF0JDyIQh%2FMVVPMt1ECZlfcjZJ9mIKoaTl1MRIl5o4CUKXOwmyrCInCKqcWtvadL2SYhyASyNDJ0uIiRMDjI0Fd30%2FiI2UA5GSS5UDj2l6NoqgOgN4gksEBgYFf0FDqKgHnyZ9OX8HrgYHdHpcHQULXAS2qKpENRg7eAMLC7kTBaixUYFkKAzWAAnLC7FLVxLWDBLKCwaKTULgEwbLA4hJtOkSBNqITT3xEgfLpBtzE%2FjiuL04RGEBgwWhShRgQExHBAAh%2BQQJCgAAACwAAAAAIAAgAAAE7xDISWlSqerNpyJKhWRdlSAVoVLCWk6JKlAqAavhO9UkUHsqlE6CwO1cRdCQ8iEIfzFVTzLdRAmZX3I2SfZiCqGk5dTESJeaOAlClzsJsqwiJwiqnFrb2nS9kmIcgEsjQydLiIlHehhpejaIjzh9eomSjZR%2BipslWIRLAgMDOR2DOqKogTB9pCUJBagDBXR6XB0EBkIIsaRsGGMMAxoDBgYHTKJiUYEGDAzHC9EACcUGkIgFzgwZ0QsSBcXHiQvOwgDdEwfFs0sDzt4S6BK4xYjkDOzn0unFeBzOBijIm1Dgmg5YFQwsCMjp1oJ8LyIAACH5BAkKAAAALAAAAAAgACAAAATwEMhJaVKp6s2nIkqFZF2VIBWhUsJaTokqUCoBq%2BE71SRQeyqUToLA7VxF0JDyIQh%2FMVVPMt1ECZlfcjZJ9mIKoaTl1MRIl5o4CUKXOwmyrCInCKqcWtvadL2SYhyASyNDJ0uIiUd6GGl6NoiPOH16iZKNlH6KmyWFOggHhEEvAwwMA0N9GBsEC6amhnVcEwavDAazGwIDaH1ipaYLBUTCGgQDA8NdHz0FpqgTBwsLqAbWAAnIA4FWKdMLGdYGEgraigbT0OITBcg5QwPT4xLrROZL6AuQAPUS7bxLpoWidY0JtxLHKhwwMJBTHgPKdEQAACH5BAkKAAAALAAAAAAgACAAAATrEMhJaVKp6s2nIkqFZF2VIBWhUsJaTokqUCoBq%2BE71SRQeyqUToLA7VxF0JDyIQh%2FMVVPMt1ECZlfcjZJ9mIKoaTl1MRIl5o4CUKXOwmyrCInCKqcWtvadL2SYhyASyNDJ0uIiUd6GAULDJCRiXo1CpGXDJOUjY%2BYip9DhToJA4RBLwMLCwVDfRgbBAaqqoZ1XBMHswsHtxtFaH1iqaoGNgAIxRpbFAgfPQSqpbgGBqUD1wBXeCYp1AYZ19JJOYgH1KwA4UBvQwXUBxPqVD9L3sbp2BNk2xvvFPJd%2BMFCN6HAAIKgNggY0KtEBAAh%2BQQJCgAAACwAAAAAIAAgAAAE6BDISWlSqerNpyJKhWRdlSAVoVLCWk6JKlAqAavhO9UkUHsqlE6CwO1cRdCQ8iEIfzFVTzLdRAmZX3I2SfYIDMaAFdTESJeaEDAIMxYFqrOUaNW4E4ObYcCXaiBVEgULe0NJaxxtYksjh2NLkZISgDgJhHthkpU4mW6blRiYmZOlh4JWkDqILwUGBnE6TYEbCgevr0N1gH4At7gHiRpFaLNrrq8HNgAJA70AWxQIH1%2BvsYMDAzZQPC9VCNkDWUhGkuE5PxJNwiUK4UfLzOlD4WvzAHaoG9nxPi5d%2BjYUqfAhhykOFwJWiAAAIfkECQoAAAAsAAAAACAAIAAABPAQyElpUqnqzaciSoVkXVUMFaFSwlpOCcMYlErAavhOMnNLNo8KsZsMZItJEIDIFSkLGQoQTNhIsFehRww2CQLKF0tYGKYSg%2BygsZIuNqJksKgbfgIGepNo2cIUB3V1B3IvNiBYNQaDSTtfhhx0CwVPI0UJe0%2Bbm4g5VgcGoqOcnjmjqDSdnhgEoamcsZuXO1aWQy8KAwOAuTYYGwi7w5h%2BKr0SJ8MFihpNbx%2B4Erq7BYBuzsdiH1jCAzoSfl0rVirNbRXlBBlLX%2BBP0XJLAPGzTkAuAOqb0WT5AH7OcdCm5B8TgRwSRKIHQtaLCwg1RAAAOwAAAAAAAAAAAA%3D%3D); - - visibility: visible; - opacity: 0.6; - transition: all 0.3s ease; - } - - .reveal > .overlay header { - position: absolute; - left: 0; - top: 0; - width: 100%; - padding: $overlayHeaderPadding; - z-index: 2; - box-sizing: border-box; - } - .reveal > .overlay header a { - display: inline-block; - width: $overlayHeaderHeight; - height: $overlayHeaderHeight; - line-height: 36px; - padding: 0 10px; - float: right; - opacity: 0.6; - - box-sizing: border-box; - } - .reveal > .overlay header a:hover { - opacity: 1; - } - .reveal > .overlay header a .icon { - display: inline-block; - width: 20px; - height: 20px; - - background-position: 50% 50%; - background-size: 100%; - background-repeat: no-repeat; - } - .reveal > .overlay header a.close .icon { - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABkklEQVRYR8WX4VHDMAxG6wnoJrABZQPYBCaBTWAD2g1gE5gg6OOsXuxIlr40d81dfrSJ9V4c2VLK7spHuTJ/5wpM07QXuXc5X0opX2tEJcadjHuV80li/FgxTIEK/5QBCICBD6xEhSMGHgQPgBgLiYVAB1dpSqKDawxTohFw4JSEA3clzgIBPCURwE2JucBR7rhPJJv5OpJwDX+SfDjgx1wACQeJG1aChP9K/IMmdZ8DtESV1WyP3Bt4MwM6sj4NMxMYiqUWHQu4KYA/SYkIjOsm3BXYWMKFDwU2khjCQ4ELJUJ4SmClRArOCmSXGuKma0fYD5CbzHxFpCSGAhfAVSSUGDUk2BWZaff2g6GE15BsBQ9nwmpIGDiyHQddwNTMKkbZaf9fajXQca1EX44puJZUsnY0ObGmITE3GVLCbEhQUjGVt146j6oasWN+49Vph2w1pZ5EansNZqKBm1txbU57iRRcZ86RWMDdWtBJUHBHwoQPi1GV+JCbntmvok7iTX4/Up9mgyTc/FJYDTcndgH/AA5A/CHsyEkVAAAAAElFTkSuQmCC); - } - .reveal > .overlay header a.external .icon { - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAcElEQVRYR+2WSQoAIQwEzf8f7XiOMkUQxUPlGkM3hVmiQfQR9GYnH1SsAQlI4DiBqkCMoNb9y2e90IAEJPAcgdznU9+engMaeJ7Azh5Y1U67gAho4DqBqmB1buAf0MB1AlVBek83ZPkmJMGc1wAR+AAqod/B97TRpQAAAABJRU5ErkJggg==); - } - - .reveal > .overlay .viewport { - position: absolute; - display: flex; - top: $overlayHeaderHeight + $overlayHeaderPadding*2; - right: 0; - bottom: 0; - left: 0; - } - - .reveal > .overlay.overlay-preview .viewport iframe { - width: 100%; - height: 100%; - max-width: 100%; - max-height: 100%; - border: 0; - - opacity: 0; - visibility: hidden; - transition: all 0.3s ease; - } - - .reveal > .overlay.overlay-preview.loaded .viewport iframe { - opacity: 1; - visibility: visible; - } - - .reveal > .overlay.overlay-preview.loaded .viewport-inner { - position: absolute; - z-index: -1; - left: 0; - top: 45%; - width: 100%; - text-align: center; - letter-spacing: normal; - } - .reveal > .overlay.overlay-preview .x-frame-error { - opacity: 0; - transition: opacity 0.3s ease 0.3s; - } - .reveal > .overlay.overlay-preview.loaded .x-frame-error { - opacity: 1; - } - - .reveal > .overlay.overlay-preview.loaded .spinner { - opacity: 0; - visibility: hidden; - transform: scale(0.2); - } - - .reveal > .overlay.overlay-help .viewport { - overflow: auto; - color: #fff; - } - - .reveal > .overlay.overlay-help .viewport .viewport-inner { - width: 600px; - margin: auto; - padding: 20px 20px 80px 20px; - text-align: center; - letter-spacing: normal; - } - - .reveal > .overlay.overlay-help .viewport .viewport-inner .title { - font-size: 20px; - } - - .reveal > .overlay.overlay-help .viewport .viewport-inner table { - border: 1px solid #fff; - border-collapse: collapse; - font-size: 16px; - } - - .reveal > .overlay.overlay-help .viewport .viewport-inner table th, - .reveal > .overlay.overlay-help .viewport .viewport-inner table td { - width: 200px; - padding: 14px; - border: 1px solid #fff; - vertical-align: middle; - } - - .reveal > .overlay.overlay-help .viewport .viewport-inner table th { - padding-top: 20px; - padding-bottom: 20px; - } - -/********************************************* - * PLAYBACK COMPONENT - *********************************************/ - -.reveal .playback { - position: absolute; - left: 15px; - bottom: 20px; - z-index: 30; - cursor: pointer; - transition: all 400ms ease; - -webkit-tap-highlight-color: rgba( 0, 0, 0, 0 ); -} - -.reveal.overview .playback { - opacity: 0; - visibility: hidden; -} - - -/********************************************* - * CODE HIGHLGIHTING - *********************************************/ - -.reveal .hljs { - min-height: 100%; -} - -.reveal .hljs table { - margin: initial; -} - -.reveal .hljs-ln-code, -.reveal .hljs-ln-numbers { - padding: 0; - border: 0; -} - -.reveal .hljs-ln-numbers { - opacity: 0.6; - padding-right: 0.75em; - text-align: right; - vertical-align: top; -} - -.reveal .hljs.has-highlights tr:not(.highlight-line) { - opacity: 0.4; -} - -.reveal .hljs.has-highlights.fragment { - transition: all .2s ease; -} - -.reveal .hljs:not(:first-child).fragment { - position: absolute; - top: 0; - left: 0; - width: 100%; - box-sizing: border-box; -} - -.reveal pre[data-auto-animate-target] { - overflow: hidden; -} -.reveal pre[data-auto-animate-target] code { - height: 100%; -} - - -/********************************************* - * ROLLING LINKS - *********************************************/ - -.reveal .roll { - display: inline-block; - line-height: 1.2; - overflow: hidden; - - vertical-align: top; - perspective: 400px; - perspective-origin: 50% 50%; -} - .reveal .roll:hover { - background: none; - text-shadow: none; - } -.reveal .roll span { - display: block; - position: relative; - padding: 0 2px; - - pointer-events: none; - transition: all 400ms ease; - transform-origin: 50% 0%; - transform-style: preserve-3d; - backface-visibility: hidden; -} - .reveal .roll:hover span { - background: rgba(0,0,0,0.5); - transform: translate3d( 0px, 0px, -45px ) rotateX( 90deg ); - } -.reveal .roll span:after { - content: attr(data-title); - - display: block; - position: absolute; - left: 0; - top: 0; - padding: 0 2px; - backface-visibility: hidden; - transform-origin: 50% 0%; - transform: translate3d( 0px, 110%, 0px ) rotateX( -90deg ); -} - - -/********************************************* - * SPEAKER NOTES - *********************************************/ - -$notesWidthPercent: 25%; - -// Hide on-page notes -.reveal aside.notes { - display: none; -} - -// An interface element that can optionally be used to show the -// speaker notes to all viewers, on top of the presentation -.reveal .speaker-notes { - display: none; - position: absolute; - width: math.div($notesWidthPercent, (1 - math.div($notesWidthPercent,100))) * 1%; - height: 100%; - top: 0; - left: 100%; - padding: 14px 18px 14px 18px; - z-index: 1; - font-size: 18px; - line-height: 1.4; - border: 1px solid rgba( 0, 0, 0, 0.05 ); - color: #222; - background-color: #f5f5f5; - overflow: auto; - box-sizing: border-box; - text-align: left; - font-family: Helvetica, sans-serif; - -webkit-overflow-scrolling: touch; - - .notes-placeholder { - color: #ccc; - font-style: italic; - } - - &:focus { - outline: none; - } - - &:before { - content: 'Speaker notes'; - display: block; - margin-bottom: 10px; - opacity: 0.5; - } -} - - -.reveal.show-notes { - max-width: 100% - $notesWidthPercent; - overflow: visible; -} - -.reveal.show-notes .speaker-notes { - display: block; -} - -@media screen and (min-width: 1600px) { - .reveal .speaker-notes { - font-size: 20px; - } -} - -@media screen and (max-width: 1024px) { - .reveal.show-notes { - border-left: 0; - max-width: none; - max-height: 70%; - max-height: 70vh; - overflow: visible; - } - - .reveal.show-notes .speaker-notes { - top: 100%; - left: 0; - width: 100%; - height: 30vh; - border: 0; - } -} - -@media screen and (max-width: 600px) { - .reveal.show-notes { - max-height: 60%; - max-height: 60vh; - } - - .reveal.show-notes .speaker-notes { - top: 100%; - height: 40vh; - } - - .reveal .speaker-notes { - font-size: 14px; - } -} - - -/********************************************* - * JUMP-TO-SLIDE COMPONENT - *********************************************/ - - .reveal .jump-to-slide { - position: absolute; - top: 15px; - left: 15px; - z-index: 30; - font-size: 32px; - -webkit-tap-highlight-color: rgba( 0, 0, 0, 0 ); -} - -.reveal .jump-to-slide-input { - background: transparent; - padding: 8px; - font-size: inherit; - color: currentColor; - border: 0; -} -.reveal .jump-to-slide-input::placeholder { - color: currentColor; - opacity: 0.5; -} - -.reveal.has-dark-background .jump-to-slide-input { - color: #fff; -} -.reveal.has-light-background .jump-to-slide-input { - color: #222; -} - -.reveal .jump-to-slide-input:focus { - outline: none; -} - - -/********************************************* - * ZOOM PLUGIN - *********************************************/ - -.zoomed .reveal *, -.zoomed .reveal *:before, -.zoomed .reveal *:after { - backface-visibility: visible !important; -} - -.zoomed .reveal .progress, -.zoomed .reveal .controls { - opacity: 0; -} - -.zoomed .reveal .roll span { - background: none; -} - -.zoomed .reveal .roll span:after { - visibility: hidden; -} - - -/********************************************* - * SCROLL VIEW - *********************************************/ -.reveal-viewport.loading-scroll-mode { - visibility: hidden; -} - -.reveal-viewport.reveal-scroll { - & { - margin: 0 auto; - overflow: auto; - overflow-x: hidden; - overflow-y: auto; - z-index: 1; - - --r-scrollbar-width: 7px; - --r-scrollbar-trigger-size: 5px; - --r-controls-spacing: 8px; - } - - @media screen and (max-width: 500px) { - --r-scrollbar-width: 3px; - --r-scrollbar-trigger-size: 3px; - } - - .controls, - .progress, - .playback, - .backgrounds, - .slide-number, - .speaker-notes { - display: none !important; - } - - .overlay, - .pause-overlay { - position: fixed; - } - - .reveal { - overflow: visible; - touch-action: manipulation; - } - - .slides { - position: static; - pointer-events: initial; - - left: auto; - top: auto; - width: 100% !important; - margin: 0; - padding: 0; - - overflow: visible; - display: block; - - perspective: none; - perspective-origin: 50% 50%; - } - - .scroll-page { - position: relative; - width: 100%; - height: calc(var(--page-height) + var(--page-scroll-padding)); - z-index: 1; - overflow: visible; - } - - .scroll-page-sticky { - position: sticky; - height: var(--page-height); - top: 0px; - } - - .scroll-page-content { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - overflow: hidden; - } - - .scroll-page section { - visibility: visible !important; - display: block !important; - position: absolute !important; - width: var(--slide-width) !important; - height: var(--slide-height) !important; - top: 50% !important; - left: 50% !important; - opacity: 1 !important; - transform: scale(var(--slide-scale)) translate(-50%, -50%) !important; - transform-style: flat !important; - transform-origin: 0 0 !important; - } - - .slide-background { - display: block !important; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: auto !important; - visibility: visible; - opacity: 1; - touch-action: manipulation; - } -} - -// Chromium -.reveal-viewport.reveal-scroll[data-scrollbar="true"]::-webkit-scrollbar, -.reveal-viewport.reveal-scroll[data-scrollbar="auto"]::-webkit-scrollbar { - display: none; -} - -// Firefox -.reveal-viewport.reveal-scroll[data-scrollbar="true"], -.reveal-viewport.reveal-scroll[data-scrollbar="auto"] { - scrollbar-width: none; -} - -.reveal.has-dark-background, -.reveal-viewport.has-dark-background { - --r-overlay-element-bg-color: 240, 240, 240; - --r-overlay-element-fg-color: 0, 0, 0; -} -.reveal.has-light-background, -.reveal-viewport.has-light-background { - --r-overlay-element-bg-color: 0, 0, 0; - --r-overlay-element-fg-color: 240, 240, 240; -} - -.reveal-viewport.reveal-scroll .scrollbar { - position: sticky; - top: 50%; - z-index: 20; - opacity: 0; - transition: all 0.3s ease; - - &.visible, - &:hover { - opacity: 1; - } - - .scrollbar-inner { - position: absolute; - width: var(--r-scrollbar-width); - height: calc(var(--viewport-height) - var(--r-controls-spacing) * 2); - right: var(--r-controls-spacing); - top: 0; - transform: translateY(-50%); - border-radius: var(--r-scrollbar-width); - z-index: 10; - } - - .scrollbar-playhead { - position: absolute; - width: var(--r-scrollbar-width); - height: var(--r-scrollbar-width); - top: 0; - left: 0; - border-radius: var(--r-scrollbar-width); - background-color: rgba(var(--r-overlay-element-bg-color), 1); - z-index: 11; - transition: background-color 0.2s ease; - } - - .scrollbar-slide { - position: absolute; - width: 100%; - background-color: rgba(var(--r-overlay-element-bg-color), 0.2); - box-shadow: 0 0 0px 1px rgba(var(--r-overlay-element-fg-color), 0.1); - border-radius: var(--r-scrollbar-width); - transition: background-color 0.2s ease; - } - - // Hit area - .scrollbar-slide:after { - content: ''; - position: absolute; - width: 200%; - height: 100%; - top: 0; - left: -50%; - background: rgba( 0, 0, 0, 0 ); - z-index: -1; - } - - .scrollbar-slide:hover, - .scrollbar-slide.active { - background-color: rgba(var(--r-overlay-element-bg-color), 0.4); - } - - .scrollbar-trigger { - position: absolute; - width: 100%; - transition: background-color 0.2s ease; - } - - .scrollbar-slide.active.has-triggers { - background-color: rgba(var(--r-overlay-element-bg-color), 0.4); - z-index: 10; - } - - .scrollbar-slide.active .scrollbar-trigger:after { - content: ''; - position: absolute; - width: var(--r-scrollbar-trigger-size); - height: var(--r-scrollbar-trigger-size); - border-radius: 20px; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - background-color: rgba(var(--r-overlay-element-bg-color), 1); - transition: transform 0.2s ease, opacity 0.2s ease; - opacity: 0.4; - } - - .scrollbar-slide.active .scrollbar-trigger.active:after, - .scrollbar-slide.active .scrollbar-trigger.active ~ .scrollbar-trigger:after { - opacity: 1; - } - - .scrollbar-slide.active .scrollbar-trigger ~ .scrollbar-trigger.active:after { - transform: translate(calc( var(--r-scrollbar-width) * -2), 0); - background-color: rgba(var(--r-overlay-element-bg-color), 1); - } -} - - -/********************************************* - * PRINT STYLES - *********************************************/ - -@import 'print/pdf.scss'; -@import 'print/paper.scss'; - diff --git a/css/theme/README.md b/css/theme/README.md deleted file mode 100644 index 30916c4..0000000 --- a/css/theme/README.md +++ /dev/null @@ -1,21 +0,0 @@ -## Dependencies - -Themes are written using Sass to keep things modular and reduce the need for repeated selectors across files. Make sure that you have the reveal.js development environment installed before proceeding: https://revealjs.com/installation/#full-setup - -## Creating a Theme - -To create your own theme, start by duplicating a ```.scss``` file in [/css/theme/source](https://github.com/hakimel/reveal.js/blob/master/css/theme/source). It will be automatically compiled from Sass to CSS (see the [gulpfile](https://github.com/hakimel/reveal.js/blob/master/gulpfile.js)) when you run `npm run build -- css-themes`. - -Each theme file does four things in the following order: - -1. **Include [/css/theme/template/mixins.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/mixins.scss)** -Shared utility functions. - -2. **Include [/css/theme/template/settings.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/settings.scss)** -Declares a set of custom variables that the template file (step 4) expects. Can be overridden in step 3. - -3. **Override** -This is where you override the default theme. Either by specifying variables (see [settings.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/settings.scss) for reference) or by adding any selectors and styles you please. - -4. **Include [/css/theme/template/theme.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/theme.scss)** -The template theme file which will generate final CSS output based on the currently defined variables. diff --git a/css/theme/source/beige.scss b/css/theme/source/beige.scss deleted file mode 100644 index 7598b94..0000000 --- a/css/theme/source/beige.scss +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Beige theme for reveal.js. - * - * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - - -// Include theme-specific fonts -@import url(./fonts/league-gothic/league-gothic.css); -@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); - - -// Override theme settings (see ../template/settings.scss) -$mainColor: #333; -$headingColor: #333; -$headingTextShadow: none; -$backgroundColor: #f7f3de; -$linkColor: #8b743d; -$linkColorHover: lighten( $linkColor, 20% ); -$selectionBackgroundColor: rgba(79, 64, 28, 0.99); -$heading1TextShadow: 0 1px 0 #ccc, 0 2px 0 #c9c9c9, 0 3px 0 #bbb, 0 4px 0 #b9b9b9, 0 5px 0 #aaa, 0 6px 1px rgba(0,0,0,.1), 0 0 5px rgba(0,0,0,.1), 0 1px 3px rgba(0,0,0,.3), 0 3px 5px rgba(0,0,0,.2), 0 5px 10px rgba(0,0,0,.25), 0 20px 20px rgba(0,0,0,.15); - -$overlayElementBgColor: 0, 0, 0; -$overlayElementFgColor: 240, 240, 240; - -// Background generator -@mixin bodyBackground() { - @include radial-gradient( rgba(247,242,211,1), rgba(255,255,255,1) ); -} - -// Change text colors against dark slide backgrounds -@include dark-bg-text-color(#fff); - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- diff --git a/css/theme/source/black-contrast.scss b/css/theme/source/black-contrast.scss deleted file mode 100644 index 9e1a2ca..0000000 --- a/css/theme/source/black-contrast.scss +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Black compact & high contrast reveal.js theme, with headers not in capitals. - * - * By Peter Kehl. Based on black.(s)css by Hakim El Hattab, http://hakim.se - * - * - Keep the source similar to black.css - for easy comparison. - * - $mainFontSize controls code blocks, too (although under some ratio). - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - -// Include theme-specific fonts -@import url(./fonts/source-sans-pro/source-sans-pro.css); - - -// Override theme settings (see ../template/settings.scss) -$backgroundColor: #000000; - -$mainColor: #fff; -$headingColor: #fff; - -$mainFontSize: 42px; -$mainFont: 'Source Sans Pro', Helvetica, sans-serif; -$headingFont: 'Source Sans Pro', Helvetica, sans-serif; -$headingTextShadow: none; -$headingLetterSpacing: normal; -$headingTextTransform: uppercase; -$headingFontWeight: 600; -$linkColor: #42affa; -$linkColorHover: lighten( $linkColor, 15% ); -$selectionBackgroundColor: lighten( $linkColor, 25% ); - -$heading1Size: 2.5em; -$heading2Size: 1.6em; -$heading3Size: 1.3em; -$heading4Size: 1.0em; - -// Change text colors against light slide backgrounds -@include light-bg-text-color(#000); - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- diff --git a/css/theme/source/black.scss b/css/theme/source/black.scss deleted file mode 100644 index 7c655c4..0000000 --- a/css/theme/source/black.scss +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Black theme for reveal.js. This is the opposite of the 'white' theme. - * - * By Hakim El Hattab, http://hakim.se - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - -// Include theme-specific fonts -@import url(./fonts/source-sans-pro/source-sans-pro.css); - - -// Override theme settings (see ../template/settings.scss) -$backgroundColor: #191919; - -$mainColor: #fff; -$headingColor: #fff; - -$mainFontSize: 42px; -$mainFont: 'Source Sans Pro', Helvetica, sans-serif; -$headingFont: 'Source Sans Pro', Helvetica, sans-serif; -$headingTextShadow: none; -$headingLetterSpacing: normal; -$headingTextTransform: uppercase; -$headingFontWeight: 600; -$linkColor: #42affa; -$linkColorHover: lighten( $linkColor, 15% ); -$selectionBackgroundColor: rgba( $linkColor, 0.75 ); - -$heading1Size: 2.5em; -$heading2Size: 1.6em; -$heading3Size: 1.3em; -$heading4Size: 1.0em; - -// Change text colors against light slide backgrounds -@include light-bg-text-color(#222); - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- diff --git a/css/theme/source/blood.scss b/css/theme/source/blood.scss deleted file mode 100644 index b5a8679..0000000 --- a/css/theme/source/blood.scss +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Blood theme for reveal.js - * Author: Walther http://github.com/Walther - * - * Designed to be used with highlight.js theme - * "monokai_sublime.css" available from - * https://github.com/isagalaev/highlight.js/ - * - * For other themes, change $codeBackground accordingly. - * - */ - - // Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - -// Include theme-specific fonts - -@import url(https://fonts.googleapis.com/css?family=Ubuntu:300,700,300italic,700italic); - -// Colors used in the theme -$blood: #a23; -$coal: #222; -$codeBackground: #23241f; - -$backgroundColor: $coal; - -// Main text -$mainFont: Ubuntu, 'sans-serif'; -$mainColor: #eee; - -// Headings -$headingFont: Ubuntu, 'sans-serif'; -$headingTextShadow: 2px 2px 2px $coal; - -// h1 shadow, borrowed humbly from -// (c) Default theme by Hakim El Hattab -$heading1TextShadow: 0 1px 0 #ccc, 0 2px 0 #c9c9c9, 0 3px 0 #bbb, 0 4px 0 #b9b9b9, 0 5px 0 #aaa, 0 6px 1px rgba(0,0,0,.1), 0 0 5px rgba(0,0,0,.1), 0 1px 3px rgba(0,0,0,.3), 0 3px 5px rgba(0,0,0,.2), 0 5px 10px rgba(0,0,0,.25), 0 20px 20px rgba(0,0,0,.15); - -// Links -$linkColor: $blood; -$linkColorHover: lighten( $linkColor, 20% ); - -// Text selection -$selectionBackgroundColor: $blood; -$selectionColor: #fff; - -// Change text colors against dark slide backgrounds -@include light-bg-text-color(#222); - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- - -// some overrides after theme template import - -.reveal p { - font-weight: 300; - text-shadow: 1px 1px $coal; -} - -section.has-light-background { - p, h1, h2, h3, h4 { - text-shadow: none; - } -} - -.reveal h1, -.reveal h2, -.reveal h3, -.reveal h4, -.reveal h5, -.reveal h6 { - font-weight: 700; -} - -.reveal p code { - background-color: $codeBackground; - display: inline-block; - border-radius: 7px; -} - -.reveal small code { - vertical-align: baseline; -} \ No newline at end of file diff --git a/css/theme/source/dracula.scss b/css/theme/source/dracula.scss deleted file mode 100644 index ae968b8..0000000 --- a/css/theme/source/dracula.scss +++ /dev/null @@ -1,106 +0,0 @@ -/** - * Dracula Dark theme for reveal.js. - * Based on https://draculatheme.com - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - - -// Include theme-specific fonts -$systemFontsSansSerif: -apple-system, - BlinkMacSystemFont, - avenir next, - avenir, - segoe ui, - helvetica neue, - helvetica, - Cantarell, - Ubuntu, - roboto, - noto, - arial, - sans-serif; -$systemFontsMono: Menlo, - Consolas, - Monaco, - Liberation Mono, - Lucida Console, - monospace; - -/** - * Dracula colors by Zeno Rocha - * https://draculatheme.com/contribute - */ -html * { - color-profile: sRGB; - rendering-intent: auto; -} - -$background: #282A36; -$foreground: #F8F8F2; -$selection: #44475A; -$comment: #6272A4; -$red: #FF5555; -$orange: #FFB86C; -$yellow: #F1FA8C; -$green: #50FA7B; -$purple: #BD93F9; -$cyan: #8BE9FD; -$pink: #FF79C6; - - - -// Override theme settings (see ../template/settings.scss) -$mainColor: $foreground; -$headingColor: $purple; -$headingTextShadow: none; -$headingTextTransform: none; -$backgroundColor: $background; -$linkColor: $pink; -$linkColorHover: $cyan; -$selectionBackgroundColor: $selection; -$inlineCodeColor: $green; -$listBulletColor: $cyan; - -$mainFont: $systemFontsSansSerif; -$codeFont: "Fira Code", $systemFontsMono; - -// Change text colors against light slide backgrounds -@include light-bg-text-color($background); - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- - -// Define additional color effects based on Dracula spec -// https://spec.draculatheme.com/ -:root { - --r-bold-color: #{$orange}; - --r-italic-color: #{$yellow}; - --r-inline-code-color: #{$inlineCodeColor}; - --r-list-bullet-color: #{$listBulletColor}; -} - -.reveal { - strong, b { - color: var(--r-bold-color); - } - em, i, blockquote { - color: var(--r-italic-color); - } - code { - color: var(--r-inline-code-color); - } - // Dracula colored list bullets and numbers - ul, ol { - li::marker { - color: var(--r-list-bullet-color); - } - } -} - diff --git a/css/theme/source/league.scss b/css/theme/source/league.scss deleted file mode 100644 index ee01258..0000000 --- a/css/theme/source/league.scss +++ /dev/null @@ -1,36 +0,0 @@ -/** - * League theme for reveal.js. - * - * This was the default theme pre-3.0.0. - * - * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - - -// Include theme-specific fonts -@import url(./fonts/league-gothic/league-gothic.css); -@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); - -// Override theme settings (see ../template/settings.scss) -$headingTextShadow: 0px 0px 6px rgba(0,0,0,0.2); -$heading1TextShadow: 0 1px 0 #ccc, 0 2px 0 #c9c9c9, 0 3px 0 #bbb, 0 4px 0 #b9b9b9, 0 5px 0 #aaa, 0 6px 1px rgba(0,0,0,.1), 0 0 5px rgba(0,0,0,.1), 0 1px 3px rgba(0,0,0,.3), 0 3px 5px rgba(0,0,0,.2), 0 5px 10px rgba(0,0,0,.25), 0 20px 20px rgba(0,0,0,.15); - -// Background generator -@mixin bodyBackground() { - @include radial-gradient( rgba(28,30,32,1), rgba(85,90,95,1) ); -} - -// Change text colors against light slide backgrounds -@include light-bg-text-color(#222); - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- diff --git a/css/theme/source/moon.scss b/css/theme/source/moon.scss deleted file mode 100644 index 59ef0a9..0000000 --- a/css/theme/source/moon.scss +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Solarized Dark theme for reveal.js. - * Author: Achim Staebler - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - - -// Include theme-specific fonts -@import url(./fonts/league-gothic/league-gothic.css); -@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); - -/** - * Solarized colors by Ethan Schoonover - */ - -// Solarized colors -$base03: #002b36; -$base02: #073642; -$base01: #586e75; -$base00: #657b83; -$base0: #839496; -$base1: #93a1a1; -$base2: #eee8d5; -$base3: #fdf6e3; -$yellow: #b58900; -$orange: #cb4b16; -$red: #dc322f; -$magenta: #d33682; -$violet: #6c71c4; -$blue: #268bd2; -$cyan: #2aa198; -$green: #859900; - -// Override theme settings (see ../template/settings.scss) -$mainColor: $base1; -$headingColor: $base2; -$headingTextShadow: none; -$backgroundColor: $base03; -$linkColor: $blue; -$linkColorHover: lighten( $linkColor, 20% ); -$selectionBackgroundColor: $magenta; - -// Change text colors against light slide backgrounds -@include light-bg-text-color(#222); - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- diff --git a/css/theme/source/night.scss b/css/theme/source/night.scss deleted file mode 100644 index 98a2062..0000000 --- a/css/theme/source/night.scss +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Black theme for reveal.js. - * - * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - -// Include theme-specific fonts -@import url(https://fonts.googleapis.com/css?family=Montserrat:700); -@import url(https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic,700italic); - - -// Override theme settings (see ../template/settings.scss) -$backgroundColor: #111; - -$mainFont: 'Open Sans', sans-serif; -$linkColor: #e7ad52; -$linkColorHover: lighten( $linkColor, 20% ); -$headingFont: 'Montserrat', Impact, sans-serif; -$headingTextShadow: none; -$headingLetterSpacing: -0.03em; -$headingTextTransform: none; -$selectionBackgroundColor: #e7ad52; - -// Change text colors against light slide backgrounds -@include light-bg-text-color(#222); - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- \ No newline at end of file diff --git a/css/theme/source/serif.scss b/css/theme/source/serif.scss deleted file mode 100644 index babec4d..0000000 --- a/css/theme/source/serif.scss +++ /dev/null @@ -1,41 +0,0 @@ -/** - * A simple theme for reveal.js presentations, similar - * to the default theme. The accent color is brown. - * - * This theme is Copyright (C) 2012-2013 Owen Versteeg, http://owenversteeg.com - it is MIT licensed. - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - - -// Override theme settings (see ../template/settings.scss) -$mainFont: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; -$mainColor: #000; -$headingFont: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; -$headingColor: #383D3D; -$headingTextShadow: none; -$headingTextTransform: none; -$backgroundColor: #F0F1EB; -$linkColor: #51483D; -$linkColorHover: lighten( $linkColor, 20% ); -$selectionBackgroundColor: #26351C; - -$overlayElementBgColor: 0, 0, 0; -$overlayElementFgColor: 240, 240, 240; - -.reveal a { - line-height: 1.3em; -} - -// Change text colors against dark slide backgrounds -@include dark-bg-text-color(#fff); - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- diff --git a/css/theme/source/simple.scss b/css/theme/source/simple.scss deleted file mode 100644 index 51a21af..0000000 --- a/css/theme/source/simple.scss +++ /dev/null @@ -1,43 +0,0 @@ -/** - * A simple theme for reveal.js presentations, similar - * to the default theme. The accent color is darkblue. - * - * This theme is Copyright (C) 2012 Owen Versteeg, https://github.com/StereotypicalApps. It is MIT licensed. - * reveal.js is Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - - -// Include theme-specific fonts -@import url(https://fonts.googleapis.com/css?family=News+Cycle:400,700); -@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); - - -// Override theme settings (see ../template/settings.scss) -$mainFont: 'Lato', sans-serif; -$mainColor: #000; -$headingFont: 'News Cycle', Impact, sans-serif; -$headingColor: #000; -$headingTextShadow: none; -$headingTextTransform: none; -$backgroundColor: #fff; -$linkColor: #00008B; -$linkColorHover: lighten( $linkColor, 20% ); -$selectionBackgroundColor: rgba(0, 0, 0, 0.99); - -$overlayElementBgColor: 0, 0, 0; -$overlayElementFgColor: 240, 240, 240; - -// Change text colors against dark slide backgrounds -@include dark-bg-text-color(#fff); - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- \ No newline at end of file diff --git a/css/theme/source/sky.scss b/css/theme/source/sky.scss deleted file mode 100644 index 457e9e5..0000000 --- a/css/theme/source/sky.scss +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Sky theme for reveal.js. - * - * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - - -// Include theme-specific fonts -@import url(https://fonts.googleapis.com/css?family=Quicksand:400,700,400italic,700italic); -@import url(https://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700); - - -// Override theme settings (see ../template/settings.scss) -$mainFont: 'Open Sans', sans-serif; -$mainColor: #333; -$headingFont: 'Quicksand', sans-serif; -$headingColor: #333; -$headingLetterSpacing: -0.08em; -$headingTextShadow: none; -$backgroundColor: #f7fbfc; -$linkColor: #3b759e; -$linkColorHover: lighten( $linkColor, 20% ); -$selectionBackgroundColor: #134674; - -$overlayElementBgColor: 0, 0, 0; -$overlayElementFgColor: 240, 240, 240; - -// Fix links so they are not cut off -.reveal a { - line-height: 1.3em; -} - -// Background generator -@mixin bodyBackground() { - @include radial-gradient( #add9e4, #f7fbfc ); -} - -// Change text colors against dark slide backgrounds -@include dark-bg-text-color(#fff); - - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- diff --git a/css/theme/source/solarized.scss b/css/theme/source/solarized.scss deleted file mode 100644 index f325345..0000000 --- a/css/theme/source/solarized.scss +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Solarized Light theme for reveal.js. - * Author: Achim Staebler - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - - -// Include theme-specific fonts -@import url(./fonts/league-gothic/league-gothic.css); -@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); - - -/** - * Solarized colors by Ethan Schoonover - */ -html * { - color-profile: sRGB; - rendering-intent: auto; -} - -// Solarized colors -$base03: #002b36; -$base02: #073642; -$base01: #586e75; -$base00: #657b83; -$base0: #839496; -$base1: #93a1a1; -$base2: #eee8d5; -$base3: #fdf6e3; -$yellow: #b58900; -$orange: #cb4b16; -$red: #dc322f; -$magenta: #d33682; -$violet: #6c71c4; -$blue: #268bd2; -$cyan: #2aa198; -$green: #859900; - -// Override theme settings (see ../template/settings.scss) -$mainColor: $base00; -$headingColor: $base01; -$headingTextShadow: none; -$backgroundColor: $base3; -$linkColor: $blue; -$linkColorHover: lighten( $linkColor, 20% ); -$selectionBackgroundColor: $magenta; - -$overlayElementBgColor: 0, 0, 0; -$overlayElementFgColor: 240, 240, 240; - -// Background generator -// @mixin bodyBackground() { -// @include radial-gradient( rgba($base3,1), rgba(lighten($base3, 20%),1) ); -// } - - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- diff --git a/css/theme/source/white-contrast.scss b/css/theme/source/white-contrast.scss deleted file mode 100644 index e22007e..0000000 --- a/css/theme/source/white-contrast.scss +++ /dev/null @@ -1,52 +0,0 @@ -/** - * White compact & high contrast reveal.js theme, with headers not in capitals. - * - * By Peter Kehl. Based on white.(s)css by Hakim El Hattab, http://hakim.se - * - * - Keep the source similar to black.css - for easy comparison. - * - $mainFontSize controls code blocks, too (although under some ratio). - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - -// Include theme-specific fonts -@import url(./fonts/source-sans-pro/source-sans-pro.css); - - -// Override theme settings (see ../template/settings.scss) -$backgroundColor: #fff; - -$mainColor: #000; -$headingColor: #000; - -$mainFontSize: 42px; -$mainFont: 'Source Sans Pro', Helvetica, sans-serif; -$headingFont: 'Source Sans Pro', Helvetica, sans-serif; -$headingTextShadow: none; -$headingLetterSpacing: normal; -$headingTextTransform: uppercase; -$headingFontWeight: 600; -$linkColor: #2a76dd; -$linkColorHover: lighten( $linkColor, 15% ); -$selectionBackgroundColor: lighten( $linkColor, 25% ); - -$heading1Size: 2.5em; -$heading2Size: 1.6em; -$heading3Size: 1.3em; -$heading4Size: 1.0em; - -$overlayElementBgColor: 0, 0, 0; -$overlayElementFgColor: 240, 240, 240; - -// Change text colors against dark slide backgrounds -@include dark-bg-text-color(#fff); - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- diff --git a/css/theme/source/white.scss b/css/theme/source/white.scss deleted file mode 100644 index a2b1292..0000000 --- a/css/theme/source/white.scss +++ /dev/null @@ -1,49 +0,0 @@ -/** - * White theme for reveal.js. This is the opposite of the 'black' theme. - * - * By Hakim El Hattab, http://hakim.se - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - -// Include theme-specific fonts -@import url(./fonts/source-sans-pro/source-sans-pro.css); - - -// Override theme settings (see ../template/settings.scss) -$backgroundColor: #fff; - -$mainColor: #222; -$headingColor: #222; - -$mainFontSize: 42px; -$mainFont: 'Source Sans Pro', Helvetica, sans-serif; -$headingFont: 'Source Sans Pro', Helvetica, sans-serif; -$headingTextShadow: none; -$headingLetterSpacing: normal; -$headingTextTransform: uppercase; -$headingFontWeight: 600; -$linkColor: #2a76dd; -$linkColorHover: lighten( $linkColor, 15% ); -$selectionBackgroundColor: lighten( $linkColor, 25% ); - -$heading1Size: 2.5em; -$heading2Size: 1.6em; -$heading3Size: 1.3em; -$heading4Size: 1.0em; - -$overlayElementBgColor: 0, 0, 0; -$overlayElementFgColor: 240, 240, 240; - -// Change text colors against dark slide backgrounds -@include dark-bg-text-color(#fff); - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- diff --git a/css/theme/template/exposer.scss b/css/theme/template/exposer.scss deleted file mode 100644 index 2e9288d..0000000 --- a/css/theme/template/exposer.scss +++ /dev/null @@ -1,30 +0,0 @@ -// Exposes theme's variables for easy re-use in CSS for plugin authors - -:root { - --r-background-color: #{$backgroundColor}; - --r-main-font: #{$mainFont}; - --r-main-font-size: #{$mainFontSize}; - --r-main-color: #{$mainColor}; - --r-block-margin: #{$blockMargin}; - --r-heading-margin: #{$headingMargin}; - --r-heading-font: #{$headingFont}; - --r-heading-color: #{$headingColor}; - --r-heading-line-height: #{$headingLineHeight}; - --r-heading-letter-spacing: #{$headingLetterSpacing}; - --r-heading-text-transform: #{$headingTextTransform}; - --r-heading-text-shadow: #{$headingTextShadow}; - --r-heading-font-weight: #{$headingFontWeight}; - --r-heading1-text-shadow: #{$heading1TextShadow}; - --r-heading1-size: #{$heading1Size}; - --r-heading2-size: #{$heading2Size}; - --r-heading3-size: #{$heading3Size}; - --r-heading4-size: #{$heading4Size}; - --r-code-font: #{$codeFont}; - --r-link-color: #{$linkColor}; - --r-link-color-dark: #{darken($linkColor , 15% )}; - --r-link-color-hover: #{$linkColorHover}; - --r-selection-background-color: #{$selectionBackgroundColor}; - --r-selection-color: #{$selectionColor}; - --r-overlay-element-bg-color: #{$overlayElementBgColor}; - --r-overlay-element-fg-color: #{$overlayElementFgColor}; -} diff --git a/css/theme/template/mixins.scss b/css/theme/template/mixins.scss deleted file mode 100644 index 17a3db5..0000000 --- a/css/theme/template/mixins.scss +++ /dev/null @@ -1,45 +0,0 @@ -@mixin vertical-gradient( $top, $bottom ) { - background: $top; - background: -moz-linear-gradient( top, $top 0%, $bottom 100% ); - background: -webkit-gradient( linear, left top, left bottom, color-stop(0%,$top), color-stop(100%,$bottom) ); - background: -webkit-linear-gradient( top, $top 0%, $bottom 100% ); - background: -o-linear-gradient( top, $top 0%, $bottom 100% ); - background: -ms-linear-gradient( top, $top 0%, $bottom 100% ); - background: linear-gradient( top, $top 0%, $bottom 100% ); -} - -@mixin horizontal-gradient( $top, $bottom ) { - background: $top; - background: -moz-linear-gradient( left, $top 0%, $bottom 100% ); - background: -webkit-gradient( linear, left top, right top, color-stop(0%,$top), color-stop(100%,$bottom) ); - background: -webkit-linear-gradient( left, $top 0%, $bottom 100% ); - background: -o-linear-gradient( left, $top 0%, $bottom 100% ); - background: -ms-linear-gradient( left, $top 0%, $bottom 100% ); - background: linear-gradient( left, $top 0%, $bottom 100% ); -} - -@mixin radial-gradient( $outer, $inner, $type: circle ) { - background: $outer; - background: -moz-radial-gradient( center, $type cover, $inner 0%, $outer 100% ); - background: -webkit-gradient( radial, center center, 0px, center center, 100%, color-stop(0%,$inner), color-stop(100%,$outer) ); - background: -webkit-radial-gradient( center, $type cover, $inner 0%, $outer 100% ); - background: -o-radial-gradient( center, $type cover, $inner 0%, $outer 100% ); - background: -ms-radial-gradient( center, $type cover, $inner 0%, $outer 100% ); - background: radial-gradient( center, $type cover, $inner 0%, $outer 100% ); -} - -@mixin light-bg-text-color( $color ) { - section.has-light-background { - &, h1, h2, h3, h4, h5, h6 { - color: $color; - } - } -} - -@mixin dark-bg-text-color( $color ) { - section.has-dark-background { - &, h1, h2, h3, h4, h5, h6 { - color: $color; - } - } -} \ No newline at end of file diff --git a/css/theme/template/settings.scss b/css/theme/template/settings.scss deleted file mode 100644 index 3d54ac8..0000000 --- a/css/theme/template/settings.scss +++ /dev/null @@ -1,50 +0,0 @@ -// Base settings for all themes that can optionally be -// overridden by the super-theme - -// Background of the presentation -$backgroundColor: #2b2b2b; - -// Primary/body text -$mainFont: 'Lato', sans-serif; -$mainFontSize: 40px; -$mainColor: #eee; - -// Vertical spacing between blocks of text -$blockMargin: 20px; - -// Headings -$headingMargin: 0 0 $blockMargin 0; -$headingFont: 'League Gothic', Impact, sans-serif; -$headingColor: #eee; -$headingLineHeight: 1.2; -$headingLetterSpacing: normal; -$headingTextTransform: uppercase; -$headingTextShadow: none; -$headingFontWeight: normal; -$heading1TextShadow: $headingTextShadow; - -$heading1Size: 3.77em; -$heading2Size: 2.11em; -$heading3Size: 1.55em; -$heading4Size: 1.00em; - -$codeFont: monospace; - -// Links and actions -$linkColor: #13DAEC; -$linkColorHover: lighten( $linkColor, 20% ); - -// Text selection -$selectionBackgroundColor: #FF5E99; -$selectionColor: #fff; - -// Colors used for UI elements that are overlaid on top of -// the presentation -$overlayElementBgColor: 240, 240, 240; -$overlayElementFgColor: 0, 0, 0; - -// Generates the presentation background, can be overridden -// to return a background image or gradient -@mixin bodyBackground() { - background: $backgroundColor; -} diff --git a/css/theme/template/theme.scss b/css/theme/template/theme.scss deleted file mode 100644 index bc377d3..0000000 --- a/css/theme/template/theme.scss +++ /dev/null @@ -1,331 +0,0 @@ -// Base theme template for reveal.js - -/********************************************* - * GLOBAL STYLES - *********************************************/ - -@import "./exposer"; - -.reveal-viewport { - @include bodyBackground(); - background-color: var(--r-background-color); -} - -.reveal { - font-family: var(--r-main-font); - font-size: var(--r-main-font-size); - font-weight: normal; - color: var(--r-main-color); -} - -.reveal ::selection { - color: var(--r-selection-color); - background: var(--r-selection-background-color); - text-shadow: none; -} - -.reveal ::-moz-selection { - color: var(--r-selection-color); - background: var(--r-selection-background-color); - text-shadow: none; -} - -.reveal .slides section, -.reveal .slides section>section { - line-height: 1.3; - font-weight: inherit; -} - -/********************************************* - * HEADERS - *********************************************/ - -.reveal h1, -.reveal h2, -.reveal h3, -.reveal h4, -.reveal h5, -.reveal h6 { - margin: var(--r-heading-margin); - color: var(--r-heading-color); - - font-family: var(--r-heading-font); - font-weight: var(--r-heading-font-weight); - line-height: var(--r-heading-line-height); - letter-spacing: var(--r-heading-letter-spacing); - - text-transform: var(--r-heading-text-transform); - text-shadow: var(--r-heading-text-shadow); - - word-wrap: break-word; -} - -.reveal h1 {font-size: var(--r-heading1-size); } -.reveal h2 {font-size: var(--r-heading2-size); } -.reveal h3 {font-size: var(--r-heading3-size); } -.reveal h4 {font-size: var(--r-heading4-size); } - -.reveal h1 { - text-shadow: var(--r-heading1-text-shadow); -} - - -/********************************************* - * OTHER - *********************************************/ - -.reveal p { - margin: var(--r-block-margin) 0; - line-height: 1.3; -} - -/* Remove trailing margins after titles */ -.reveal h1:last-child, -.reveal h2:last-child, -.reveal h3:last-child, -.reveal h4:last-child, -.reveal h5:last-child, -.reveal h6:last-child { - margin-bottom: 0; -} - -/* Ensure certain elements are never larger than the slide itself */ -.reveal img, -.reveal video, -.reveal iframe { - max-width: 95%; - max-height: 95%; -} -.reveal strong, -.reveal b { - font-weight: bold; -} - -.reveal em { - font-style: italic; -} - -.reveal ol, -.reveal dl, -.reveal ul { - display: inline-block; - - text-align: left; - margin: 0 0 0 1em; -} - -.reveal ol { - list-style-type: decimal; -} - -.reveal ul { - list-style-type: disc; -} - -.reveal ul ul { - list-style-type: square; -} - -.reveal ul ul ul { - list-style-type: circle; -} - -.reveal ul ul, -.reveal ul ol, -.reveal ol ol, -.reveal ol ul { - display: block; - margin-left: 40px; -} - -.reveal dt { - font-weight: bold; -} - -.reveal dd { - margin-left: 40px; -} - -.reveal blockquote { - display: block; - position: relative; - width: 70%; - margin: var(--r-block-margin) auto; - padding: 5px; - - font-style: italic; - background: rgba(255, 255, 255, 0.05); - box-shadow: 0px 0px 2px rgba(0,0,0,0.2); -} - .reveal blockquote p:first-child, - .reveal blockquote p:last-child { - display: inline-block; - } - -.reveal q { - font-style: italic; -} - -.reveal pre { - display: block; - position: relative; - width: 90%; - margin: var(--r-block-margin) auto; - - text-align: left; - font-size: 0.55em; - font-family: var(--r-code-font); - line-height: 1.2em; - - word-wrap: break-word; - - box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.15); -} - -.reveal code { - font-family: var(--r-code-font); - text-transform: none; - tab-size: 2; -} - -.reveal pre code { - display: block; - padding: 5px; - overflow: auto; - max-height: 400px; - word-wrap: normal; -} - -.reveal .code-wrapper { - white-space: normal; -} - -.reveal .code-wrapper code { - white-space: pre; -} - -.reveal table { - margin: auto; - border-collapse: collapse; - border-spacing: 0; -} - -.reveal table th { - font-weight: bold; -} - -.reveal table th, -.reveal table td { - text-align: left; - padding: 0.2em 0.5em 0.2em 0.5em; - border-bottom: 1px solid; -} - -.reveal table th[align="center"], -.reveal table td[align="center"] { - text-align: center; -} - -.reveal table th[align="right"], -.reveal table td[align="right"] { - text-align: right; -} - -.reveal table tbody tr:last-child th, -.reveal table tbody tr:last-child td { - border-bottom: none; -} - -.reveal sup { - vertical-align: super; - font-size: smaller; -} -.reveal sub { - vertical-align: sub; - font-size: smaller; -} - -.reveal small { - display: inline-block; - font-size: 0.6em; - line-height: 1.2em; - vertical-align: top; -} - -.reveal small * { - vertical-align: top; -} - -.reveal img { - margin: var(--r-block-margin) 0; -} - - -/********************************************* - * LINKS - *********************************************/ - -.reveal a { - color: var(--r-link-color); - text-decoration: none; - transition: color .15s ease; -} - .reveal a:hover { - color: var(--r-link-color-hover); - text-shadow: none; - border: none; - } - -.reveal .roll span:after { - color: #fff; - // background: darken( var(--r-link-color), 15% ); - background: var(--r-link-color-dark); - -} - - -/********************************************* - * Frame helper - *********************************************/ - -.reveal .r-frame { - border: 4px solid var(--r-main-color); - box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); -} - -.reveal a .r-frame { - transition: all .15s linear; -} - -.reveal a:hover .r-frame { - border-color: var(--r-link-color); - box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); -} - - -/********************************************* - * NAVIGATION CONTROLS - *********************************************/ - -.reveal .controls { - color: var(--r-link-color); -} - - -/********************************************* - * PROGRESS BAR - *********************************************/ - -.reveal .progress { - background: rgba(0,0,0,0.2); - color: var(--r-link-color); -} - -/********************************************* - * PRINT BACKGROUND - *********************************************/ - @media print { - .backgrounds { - background-color: var(--r-background-color); - } -} diff --git a/dist/reveal.esm.js.map b/dist/reveal.esm.js.map deleted file mode 100644 index e3a20ea..0000000 --- a/dist/reveal.esm.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"reveal.esm.js","sources":["../js/utils/util.js","../js/utils/device.js","../node_modules/fitty/dist/fitty.module.js","../js/controllers/slidecontent.js","../js/utils/constants.js","../js/controllers/slidenumber.js","../js/controllers/jumptoslide.js","../js/utils/color.js","../js/controllers/backgrounds.js","../js/controllers/autoanimate.js","../js/controllers/scrollview.js","../js/controllers/printview.js","../js/controllers/fragments.js","../js/controllers/overview.js","../js/controllers/keyboard.js","../js/controllers/location.js","../js/controllers/controls.js","../js/controllers/progress.js","../js/controllers/pointer.js","../js/utils/loader.js","../js/controllers/plugins.js","../js/controllers/touch.js","../js/controllers/focus.js","../js/controllers/notes.js","../js/components/playback.js","../js/config.js","../js/reveal.js","../js/index.js"],"sourcesContent":["/**\r\n * Extend object a with the properties of object b.\r\n * If there's a conflict, object b takes precedence.\r\n *\r\n * @param {object} a\r\n * @param {object} b\r\n */\r\nexport const extend = ( a, b ) => {\r\n\r\n\tfor( let i in b ) {\r\n\t\ta[ i ] = b[ i ];\r\n\t}\r\n\r\n\treturn a;\r\n\r\n}\r\n\r\n/**\r\n * querySelectorAll but returns an Array.\r\n */\r\nexport const queryAll = ( el, selector ) => {\r\n\r\n\treturn Array.from( el.querySelectorAll( selector ) );\r\n\r\n}\r\n\r\n/**\r\n * classList.toggle() with cross browser support\r\n */\r\nexport const toggleClass = ( el, className, value ) => {\r\n\tif( value ) {\r\n\t\tel.classList.add( className );\r\n\t}\r\n\telse {\r\n\t\tel.classList.remove( className );\r\n\t}\r\n}\r\n\r\n/**\r\n * Utility for deserializing a value.\r\n *\r\n * @param {*} value\r\n * @return {*}\r\n */\r\nexport const deserialize = ( value ) => {\r\n\r\n\tif( typeof value === 'string' ) {\r\n\t\tif( value === 'null' ) return null;\r\n\t\telse if( value === 'true' ) return true;\r\n\t\telse if( value === 'false' ) return false;\r\n\t\telse if( value.match( /^-?[\\d\\.]+$/ ) ) return parseFloat( value );\r\n\t}\r\n\r\n\treturn value;\r\n\r\n}\r\n\r\n/**\r\n * Measures the distance in pixels between point a\r\n * and point b.\r\n *\r\n * @param {object} a point with x/y properties\r\n * @param {object} b point with x/y properties\r\n *\r\n * @return {number}\r\n */\r\nexport const distanceBetween = ( a, b ) => {\r\n\r\n\tlet dx = a.x - b.x,\r\n\t\tdy = a.y - b.y;\r\n\r\n\treturn Math.sqrt( dx*dx + dy*dy );\r\n\r\n}\r\n\r\n/**\r\n * Applies a CSS transform to the target element.\r\n *\r\n * @param {HTMLElement} element\r\n * @param {string} transform\r\n */\r\nexport const transformElement = ( element, transform ) => {\r\n\r\n\telement.style.transform = transform;\r\n\r\n}\r\n\r\n/**\r\n * Element.matches with IE support.\r\n *\r\n * @param {HTMLElement} target The element to match\r\n * @param {String} selector The CSS selector to match\r\n * the element against\r\n *\r\n * @return {Boolean}\r\n */\r\nexport const matches = ( target, selector ) => {\r\n\r\n\tlet matchesMethod = target.matches || target.matchesSelector || target.msMatchesSelector;\r\n\r\n\treturn !!( matchesMethod && matchesMethod.call( target, selector ) );\r\n\r\n}\r\n\r\n/**\r\n * Find the closest parent that matches the given\r\n * selector.\r\n *\r\n * @param {HTMLElement} target The child element\r\n * @param {String} selector The CSS selector to match\r\n * the parents against\r\n *\r\n * @return {HTMLElement} The matched parent or null\r\n * if no matching parent was found\r\n */\r\nexport const closest = ( target, selector ) => {\r\n\r\n\t// Native Element.closest\r\n\tif( typeof target.closest === 'function' ) {\r\n\t\treturn target.closest( selector );\r\n\t}\r\n\r\n\t// Polyfill\r\n\twhile( target ) {\r\n\t\tif( matches( target, selector ) ) {\r\n\t\t\treturn target;\r\n\t\t}\r\n\r\n\t\t// Keep searching\r\n\t\ttarget = target.parentNode;\r\n\t}\r\n\r\n\treturn null;\r\n\r\n}\r\n\r\n/**\r\n * Handling the fullscreen functionality via the fullscreen API\r\n *\r\n * @see http://fullscreen.spec.whatwg.org/\r\n * @see https://developer.mozilla.org/en-US/docs/DOM/Using_fullscreen_mode\r\n */\r\nexport const enterFullscreen = element => {\r\n\r\n\telement = element || document.documentElement;\r\n\r\n\t// Check which implementation is available\r\n\tlet requestMethod = element.requestFullscreen ||\r\n\t\t\t\t\t\telement.webkitRequestFullscreen ||\r\n\t\t\t\t\t\telement.webkitRequestFullScreen ||\r\n\t\t\t\t\t\telement.mozRequestFullScreen ||\r\n\t\t\t\t\t\telement.msRequestFullscreen;\r\n\r\n\tif( requestMethod ) {\r\n\t\trequestMethod.apply( element );\r\n\t}\r\n\r\n}\r\n\r\n/**\r\n * Creates an HTML element and returns a reference to it.\r\n * If the element already exists the existing instance will\r\n * be returned.\r\n *\r\n * @param {HTMLElement} container\r\n * @param {string} tagname\r\n * @param {string} classname\r\n * @param {string} innerHTML\r\n *\r\n * @return {HTMLElement}\r\n */\r\nexport const createSingletonNode = ( container, tagname, classname, innerHTML='' ) => {\r\n\r\n\t// Find all nodes matching the description\r\n\tlet nodes = container.querySelectorAll( '.' + classname );\r\n\r\n\t// Check all matches to find one which is a direct child of\r\n\t// the specified container\r\n\tfor( let i = 0; i < nodes.length; i++ ) {\r\n\t\tlet testNode = nodes[i];\r\n\t\tif( testNode.parentNode === container ) {\r\n\t\t\treturn testNode;\r\n\t\t}\r\n\t}\r\n\r\n\t// If no node was found, create it now\r\n\tlet node = document.createElement( tagname );\r\n\tnode.className = classname;\r\n\tnode.innerHTML = innerHTML;\r\n\tcontainer.appendChild( node );\r\n\r\n\treturn node;\r\n\r\n}\r\n\r\n/**\r\n * Injects the given CSS styles into the DOM.\r\n *\r\n * @param {string} value\r\n */\r\nexport const createStyleSheet = ( value ) => {\r\n\r\n\tlet tag = document.createElement( 'style' );\r\n\ttag.type = 'text/css';\r\n\r\n\tif( value && value.length > 0 ) {\r\n\t\tif( tag.styleSheet ) {\r\n\t\t\ttag.styleSheet.cssText = value;\r\n\t\t}\r\n\t\telse {\r\n\t\t\ttag.appendChild( document.createTextNode( value ) );\r\n\t\t}\r\n\t}\r\n\r\n\tdocument.head.appendChild( tag );\r\n\r\n\treturn tag;\r\n\r\n}\r\n\r\n/**\r\n * Returns a key:value hash of all query params.\r\n */\r\nexport const getQueryHash = () => {\r\n\r\n\tlet query = {};\r\n\r\n\tlocation.search.replace( /[A-Z0-9]+?=([\\w\\.%-]*)/gi, a => {\r\n\t\tquery[ a.split( '=' ).shift() ] = a.split( '=' ).pop();\r\n\t} );\r\n\r\n\t// Basic deserialization\r\n\tfor( let i in query ) {\r\n\t\tlet value = query[ i ];\r\n\r\n\t\tquery[ i ] = deserialize( unescape( value ) );\r\n\t}\r\n\r\n\t// Do not accept new dependencies via query config to avoid\r\n\t// the potential of malicious script injection\r\n\tif( typeof query['dependencies'] !== 'undefined' ) delete query['dependencies'];\r\n\r\n\treturn query;\r\n\r\n}\r\n\r\n/**\r\n * Returns the remaining height within the parent of the\r\n * target element.\r\n *\r\n * remaining height = [ configured parent height ] - [ current parent height ]\r\n *\r\n * @param {HTMLElement} element\r\n * @param {number} [height]\r\n */\r\nexport const getRemainingHeight = ( element, height = 0 ) => {\r\n\r\n\tif( element ) {\r\n\t\tlet newHeight, oldHeight = element.style.height;\r\n\r\n\t\t// Change the .stretch element height to 0 in order find the height of all\r\n\t\t// the other elements\r\n\t\telement.style.height = '0px';\r\n\r\n\t\t// In Overview mode, the parent (.slide) height is set of 700px.\r\n\t\t// Restore it temporarily to its natural height.\r\n\t\telement.parentNode.style.height = 'auto';\r\n\r\n\t\tnewHeight = height - element.parentNode.offsetHeight;\r\n\r\n\t\t// Restore the old height, just in case\r\n\t\telement.style.height = oldHeight + 'px';\r\n\r\n\t\t// Clear the parent (.slide) height. .removeProperty works in IE9+\r\n\t\telement.parentNode.style.removeProperty('height');\r\n\r\n\t\treturn newHeight;\r\n\t}\r\n\r\n\treturn height;\r\n\r\n}\r\n\r\nconst fileExtensionToMimeMap = {\r\n\t'mp4': 'video/mp4',\r\n\t'm4a': 'video/mp4',\r\n\t'ogv': 'video/ogg',\r\n\t'mpeg': 'video/mpeg',\r\n\t'webm': 'video/webm'\r\n}\r\n\r\n/**\r\n * Guess the MIME type for common file formats.\r\n */\r\nexport const getMimeTypeFromFile = ( filename='' ) => {\r\n\treturn fileExtensionToMimeMap[filename.split('.').pop()]\r\n}\r\n\r\n/**\r\n * Encodes a string for RFC3986-compliant URL format.\r\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI#encoding_for_rfc3986\r\n *\r\n * @param {string} url\r\n */\r\nexport const encodeRFC3986URI = ( url='' ) => {\r\n\treturn encodeURI(url)\r\n\t .replace(/%5B/g, \"[\")\r\n\t .replace(/%5D/g, \"]\")\r\n\t .replace(\r\n\t\t/[!'()*]/g,\r\n\t\t(c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`\r\n\t );\r\n}","const UA = navigator.userAgent;\r\n\r\nexport const isMobile = /(iphone|ipod|ipad|android)/gi.test( UA ) ||\r\n\t\t\t\t\t\t( navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1 ); // iPadOS\r\n\r\nexport const isChrome = /chrome/i.test( UA ) && !/edge/i.test( UA );\r\n\r\nexport const isAndroid = /android/gi.test( UA );","/**\n * fitty v2.3.7 - Snugly resizes text to fit its parent container\n * Copyright (c) 2023 Rik Schennink (https://pqina.nl/)\n */\n\nvar e=function(e){if(e){var t=function(e){return[].slice.call(e)},n=0,i=1,r=2,o=3,a=[],l=null,u=\"requestAnimationFrame\"in e?function(){e.cancelAnimationFrame(l),l=e.requestAnimationFrame((function(){return s(a.filter((function(e){return e.dirty&&e.active})))}))}:function(){},c=function(e){return function(){a.forEach((function(t){return t.dirty=e})),u()}},s=function(e){e.filter((function(e){return!e.styleComputed})).forEach((function(e){e.styleComputed=m(e)})),e.filter(y).forEach(v);var t=e.filter(p);t.forEach(d),t.forEach((function(e){v(e),f(e)})),t.forEach(S)},f=function(e){return e.dirty=n},d=function(e){e.availableWidth=e.element.parentNode.clientWidth,e.currentWidth=e.element.scrollWidth,e.previousFontSize=e.currentFontSize,e.currentFontSize=Math.min(Math.max(e.minSize,e.availableWidth/e.currentWidth*e.previousFontSize),e.maxSize),e.whiteSpace=e.multiLine&&e.currentFontSize===e.minSize?\"normal\":\"nowrap\"},p=function(e){return e.dirty!==r||e.dirty===r&&e.element.parentNode.clientWidth!==e.availableWidth},m=function(t){var n=e.getComputedStyle(t.element,null);return t.currentFontSize=parseFloat(n.getPropertyValue(\"font-size\")),t.display=n.getPropertyValue(\"display\"),t.whiteSpace=n.getPropertyValue(\"white-space\"),!0},y=function(e){var t=!1;return!e.preStyleTestCompleted&&(/inline-/.test(e.display)||(t=!0,e.display=\"inline-block\"),\"nowrap\"!==e.whiteSpace&&(t=!0,e.whiteSpace=\"nowrap\"),e.preStyleTestCompleted=!0,t)},v=function(e){e.element.style.whiteSpace=e.whiteSpace,e.element.style.display=e.display,e.element.style.fontSize=e.currentFontSize+\"px\"},S=function(e){e.element.dispatchEvent(new CustomEvent(\"fit\",{detail:{oldValue:e.previousFontSize,newValue:e.currentFontSize,scaleFactor:e.currentFontSize/e.previousFontSize}}))},h=function(e,t){return function(){e.dirty=t,e.active&&u()}},w=function(e){return function(){a=a.filter((function(t){return t.element!==e.element})),e.observeMutations&&e.observer.disconnect(),e.element.style.whiteSpace=e.originalStyle.whiteSpace,e.element.style.display=e.originalStyle.display,e.element.style.fontSize=e.originalStyle.fontSize}},b=function(e){return function(){e.active||(e.active=!0,u())}},z=function(e){return function(){return e.active=!1}},F=function(e){e.observeMutations&&(e.observer=new MutationObserver(h(e,i)),e.observer.observe(e.element,e.observeMutations))},g={minSize:16,maxSize:512,multiLine:!0,observeMutations:\"MutationObserver\"in e&&{subtree:!0,childList:!0,characterData:!0}},W=null,E=function(){e.clearTimeout(W),W=e.setTimeout(c(r),x.observeWindowDelay)},M=[\"resize\",\"orientationchange\"];return Object.defineProperty(x,\"observeWindow\",{set:function(t){var n=\"\".concat(t?\"add\":\"remove\",\"EventListener\");M.forEach((function(t){e[n](t,E)}))}}),x.observeWindow=!0,x.observeWindowDelay=100,x.fitAll=c(o),x}function C(e,t){var n=Object.assign({},g,t),i=e.map((function(e){var t=Object.assign({},n,{element:e,active:!0});return function(e){e.originalStyle={whiteSpace:e.element.style.whiteSpace,display:e.element.style.display,fontSize:e.element.style.fontSize},F(e),e.newbie=!0,e.dirty=!0,a.push(e)}(t),{element:e,fit:h(t,o),unfreeze:b(t),freeze:z(t),unsubscribe:w(t)}}));return u(),i}function x(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return\"string\"==typeof e?C(t(document.querySelectorAll(e)),n):C([e],n)[0]}}(\"undefined\"==typeof window?null:window);export default e;\n","import { extend, queryAll, closest, getMimeTypeFromFile, encodeRFC3986URI } from '../utils/util.js'\r\nimport { isMobile } from '../utils/device.js'\r\n\r\nimport fitty from 'fitty';\r\n\r\n/**\r\n * Handles loading, unloading and playback of slide\r\n * content such as images, videos and iframes.\r\n */\r\nexport default class SlideContent {\r\n\r\n\tconstructor( Reveal ) {\r\n\r\n\t\tthis.Reveal = Reveal;\r\n\r\n\t\tthis.startEmbeddedIframe = this.startEmbeddedIframe.bind( this );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Should the given element be preloaded?\r\n\t * Decides based on local element attributes and global config.\r\n\t *\r\n\t * @param {HTMLElement} element\r\n\t */\r\n\tshouldPreload( element ) {\r\n\r\n\t\tif( this.Reveal.isScrollView() ) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\t// Prefer an explicit global preload setting\r\n\t\tlet preload = this.Reveal.getConfig().preloadIframes;\r\n\r\n\t\t// If no global setting is available, fall back on the element's\r\n\t\t// own preload setting\r\n\t\tif( typeof preload !== 'boolean' ) {\r\n\t\t\tpreload = element.hasAttribute( 'data-preload' );\r\n\t\t}\r\n\r\n\t\treturn preload;\r\n\t}\r\n\r\n\t/**\r\n\t * Called when the given slide is within the configured view\r\n\t * distance. Shows the slide element and loads any content\r\n\t * that is set to load lazily (data-src).\r\n\t *\r\n\t * @param {HTMLElement} slide Slide to show\r\n\t */\r\n\tload( slide, options = {} ) {\r\n\r\n\t\t// Show the slide element\r\n\t\tslide.style.display = this.Reveal.getConfig().display;\r\n\r\n\t\t// Media elements with data-src attributes\r\n\t\tqueryAll( slide, 'img[data-src], video[data-src], audio[data-src], iframe[data-src]' ).forEach( element => {\r\n\t\t\tif( element.tagName !== 'IFRAME' || this.shouldPreload( element ) ) {\r\n\t\t\t\telement.setAttribute( 'src', element.getAttribute( 'data-src' ) );\r\n\t\t\t\telement.setAttribute( 'data-lazy-loaded', '' );\r\n\t\t\t\telement.removeAttribute( 'data-src' );\r\n\t\t\t}\r\n\t\t} );\r\n\r\n\t\t// Media elements with children\r\n\t\tqueryAll( slide, 'video, audio' ).forEach( media => {\r\n\t\t\tlet sources = 0;\r\n\r\n\t\t\tqueryAll( media, 'source[data-src]' ).forEach( source => {\r\n\t\t\t\tsource.setAttribute( 'src', source.getAttribute( 'data-src' ) );\r\n\t\t\t\tsource.removeAttribute( 'data-src' );\r\n\t\t\t\tsource.setAttribute( 'data-lazy-loaded', '' );\r\n\t\t\t\tsources += 1;\r\n\t\t\t} );\r\n\r\n\t\t\t// Enable inline video playback in mobile Safari\r\n\t\t\tif( isMobile && media.tagName === 'VIDEO' ) {\r\n\t\t\t\tmedia.setAttribute( 'playsinline', '' );\r\n\t\t\t}\r\n\r\n\t\t\t// If we rewrote sources for this video/audio element, we need\r\n\t\t\t// to manually tell it to load from its new origin\r\n\t\t\tif( sources > 0 ) {\r\n\t\t\t\tmedia.load();\r\n\t\t\t}\r\n\t\t} );\r\n\r\n\r\n\t\t// Show the corresponding background element\r\n\t\tlet background = slide.slideBackgroundElement;\r\n\t\tif( background ) {\r\n\t\t\tbackground.style.display = 'block';\r\n\r\n\t\t\tlet backgroundContent = slide.slideBackgroundContentElement;\r\n\t\t\tlet backgroundIframe = slide.getAttribute( 'data-background-iframe' );\r\n\r\n\t\t\t// If the background contains media, load it\r\n\t\t\tif( background.hasAttribute( 'data-loaded' ) === false ) {\r\n\t\t\t\tbackground.setAttribute( 'data-loaded', 'true' );\r\n\r\n\t\t\t\tlet backgroundImage = slide.getAttribute( 'data-background-image' ),\r\n\t\t\t\t\tbackgroundVideo = slide.getAttribute( 'data-background-video' ),\r\n\t\t\t\t\tbackgroundVideoLoop = slide.hasAttribute( 'data-background-video-loop' ),\r\n\t\t\t\t\tbackgroundVideoMuted = slide.hasAttribute( 'data-background-video-muted' );\r\n\r\n\t\t\t\t// Images\r\n\t\t\t\tif( backgroundImage ) {\r\n\t\t\t\t\t// base64\r\n\t\t\t\t\tif( /^data:/.test( backgroundImage.trim() ) ) {\r\n\t\t\t\t\t\tbackgroundContent.style.backgroundImage = `url(${backgroundImage.trim()})`;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t// URL(s)\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tbackgroundContent.style.backgroundImage = backgroundImage.split( ',' ).map( background => {\r\n\t\t\t\t\t\t\t// Decode URL(s) that are already encoded first\r\n\t\t\t\t\t\t\tlet decoded = decodeURI(background.trim());\r\n\t\t\t\t\t\t\treturn `url(${encodeRFC3986URI(decoded)})`;\r\n\t\t\t\t\t\t}).join( ',' );\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\t// Videos\r\n\t\t\t\telse if ( backgroundVideo && !this.Reveal.isSpeakerNotes() ) {\r\n\t\t\t\t\tlet video = document.createElement( 'video' );\r\n\r\n\t\t\t\t\tif( backgroundVideoLoop ) {\r\n\t\t\t\t\t\tvideo.setAttribute( 'loop', '' );\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif( backgroundVideoMuted ) {\r\n\t\t\t\t\t\tvideo.muted = true;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t// Enable inline playback in mobile Safari\r\n\t\t\t\t\t//\r\n\t\t\t\t\t// Mute is required for video to play when using\r\n\t\t\t\t\t// swipe gestures to navigate since they don't\r\n\t\t\t\t\t// count as direct user actions :'(\r\n\t\t\t\t\tif( isMobile ) {\r\n\t\t\t\t\t\tvideo.muted = true;\r\n\t\t\t\t\t\tvideo.setAttribute( 'playsinline', '' );\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t// Support comma separated lists of video sources\r\n\t\t\t\t\tbackgroundVideo.split( ',' ).forEach( source => {\r\n\t\t\t\t\t\tconst sourceElement = document.createElement( 'source' );\r\n\t\t\t\t\t\tsourceElement.setAttribute( 'src', source );\r\n\r\n\t\t\t\t\t\tlet type = getMimeTypeFromFile( source );\r\n\t\t\t\t\t\tif( type ) {\r\n\t\t\t\t\t\t\tsourceElement.setAttribute( 'type', type );\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tvideo.appendChild( sourceElement );\r\n\t\t\t\t\t} );\r\n\r\n\t\t\t\t\tbackgroundContent.appendChild( video );\r\n\t\t\t\t}\r\n\t\t\t\t// Iframes\r\n\t\t\t\telse if( backgroundIframe && options.excludeIframes !== true ) {\r\n\t\t\t\t\tlet iframe = document.createElement( 'iframe' );\r\n\t\t\t\t\tiframe.setAttribute( 'allowfullscreen', '' );\r\n\t\t\t\t\tiframe.setAttribute( 'mozallowfullscreen', '' );\r\n\t\t\t\t\tiframe.setAttribute( 'webkitallowfullscreen', '' );\r\n\t\t\t\t\tiframe.setAttribute( 'allow', 'autoplay' );\r\n\r\n\t\t\t\t\tiframe.setAttribute( 'data-src', backgroundIframe );\r\n\r\n\t\t\t\t\tiframe.style.width = '100%';\r\n\t\t\t\t\tiframe.style.height = '100%';\r\n\t\t\t\t\tiframe.style.maxHeight = '100%';\r\n\t\t\t\t\tiframe.style.maxWidth = '100%';\r\n\r\n\t\t\t\t\tbackgroundContent.appendChild( iframe );\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// Start loading preloadable iframes\r\n\t\t\tlet backgroundIframeElement = backgroundContent.querySelector( 'iframe[data-src]' );\r\n\t\t\tif( backgroundIframeElement ) {\r\n\r\n\t\t\t\t// Check if this iframe is eligible to be preloaded\r\n\t\t\t\tif( this.shouldPreload( background ) && !/autoplay=(1|true|yes)/gi.test( backgroundIframe ) ) {\r\n\t\t\t\t\tif( backgroundIframeElement.getAttribute( 'src' ) !== backgroundIframe ) {\r\n\t\t\t\t\t\tbackgroundIframeElement.setAttribute( 'src', backgroundIframe );\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tthis.layout( slide );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Applies JS-dependent layout helpers for the scope.\r\n\t */\r\n\tlayout( scopeElement ) {\r\n\r\n\t\t// Autosize text with the r-fit-text class based on the\r\n\t\t// size of its container. This needs to happen after the\r\n\t\t// slide is visible in order to measure the text.\r\n\t\tArray.from( scopeElement.querySelectorAll( '.r-fit-text' ) ).forEach( element => {\r\n\t\t\tfitty( element, {\r\n\t\t\t\tminSize: 24,\r\n\t\t\t\tmaxSize: this.Reveal.getConfig().height * 0.8,\r\n\t\t\t\tobserveMutations: false,\r\n\t\t\t\tobserveWindow: false\r\n\t\t\t} );\r\n\t\t} );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Unloads and hides the given slide. This is called when the\r\n\t * slide is moved outside of the configured view distance.\r\n\t *\r\n\t * @param {HTMLElement} slide\r\n\t */\r\n\tunload( slide ) {\r\n\r\n\t\t// Hide the slide element\r\n\t\tslide.style.display = 'none';\r\n\r\n\t\t// Hide the corresponding background element\r\n\t\tlet background = this.Reveal.getSlideBackground( slide );\r\n\t\tif( background ) {\r\n\t\t\tbackground.style.display = 'none';\r\n\r\n\t\t\t// Unload any background iframes\r\n\t\t\tqueryAll( background, 'iframe[src]' ).forEach( element => {\r\n\t\t\t\telement.removeAttribute( 'src' );\r\n\t\t\t} );\r\n\t\t}\r\n\r\n\t\t// Reset lazy-loaded media elements with src attributes\r\n\t\tqueryAll( slide, 'video[data-lazy-loaded][src], audio[data-lazy-loaded][src], iframe[data-lazy-loaded][src]' ).forEach( element => {\r\n\t\t\telement.setAttribute( 'data-src', element.getAttribute( 'src' ) );\r\n\t\t\telement.removeAttribute( 'src' );\r\n\t\t} );\r\n\r\n\t\t// Reset lazy-loaded media elements with children\r\n\t\tqueryAll( slide, 'video[data-lazy-loaded] source[src], audio source[src]' ).forEach( source => {\r\n\t\t\tsource.setAttribute( 'data-src', source.getAttribute( 'src' ) );\r\n\t\t\tsource.removeAttribute( 'src' );\r\n\t\t} );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Enforces origin-specific format rules for embedded media.\r\n\t */\r\n\tformatEmbeddedContent() {\r\n\r\n\t\tlet _appendParamToIframeSource = ( sourceAttribute, sourceURL, param ) => {\r\n\t\t\tqueryAll( this.Reveal.getSlidesElement(), 'iframe['+ sourceAttribute +'*=\"'+ sourceURL +'\"]' ).forEach( el => {\r\n\t\t\t\tlet src = el.getAttribute( sourceAttribute );\r\n\t\t\t\tif( src && src.indexOf( param ) === -1 ) {\r\n\t\t\t\t\tel.setAttribute( sourceAttribute, src + ( !/\\?/.test( src ) ? '?' : '&' ) + param );\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t};\r\n\r\n\t\t// YouTube frames must include \"?enablejsapi=1\"\r\n\t\t_appendParamToIframeSource( 'src', 'youtube.com/embed/', 'enablejsapi=1' );\r\n\t\t_appendParamToIframeSource( 'data-src', 'youtube.com/embed/', 'enablejsapi=1' );\r\n\r\n\t\t// Vimeo frames must include \"?api=1\"\r\n\t\t_appendParamToIframeSource( 'src', 'player.vimeo.com/', 'api=1' );\r\n\t\t_appendParamToIframeSource( 'data-src', 'player.vimeo.com/', 'api=1' );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Start playback of any embedded content inside of\r\n\t * the given element.\r\n\t *\r\n\t * @param {HTMLElement} element\r\n\t */\r\n\tstartEmbeddedContent( element ) {\r\n\r\n\t\tif( element && !this.Reveal.isSpeakerNotes() ) {\r\n\r\n\t\t\t// Restart GIFs\r\n\t\t\tqueryAll( element, 'img[src$=\".gif\"]' ).forEach( el => {\r\n\t\t\t\t// Setting the same unchanged source like this was confirmed\r\n\t\t\t\t// to work in Chrome, FF & Safari\r\n\t\t\t\tel.setAttribute( 'src', el.getAttribute( 'src' ) );\r\n\t\t\t} );\r\n\r\n\t\t\t// HTML5 media elements\r\n\t\t\tqueryAll( element, 'video, audio' ).forEach( el => {\r\n\t\t\t\tif( closest( el, '.fragment' ) && !closest( el, '.fragment.visible' ) ) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Prefer an explicit global autoplay setting\r\n\t\t\t\tlet autoplay = this.Reveal.getConfig().autoPlayMedia;\r\n\r\n\t\t\t\t// If no global setting is available, fall back on the element's\r\n\t\t\t\t// own autoplay setting\r\n\t\t\t\tif( typeof autoplay !== 'boolean' ) {\r\n\t\t\t\t\tautoplay = el.hasAttribute( 'data-autoplay' ) || !!closest( el, '.slide-background' );\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif( autoplay && typeof el.play === 'function' ) {\r\n\r\n\t\t\t\t\t// If the media is ready, start playback\r\n\t\t\t\t\tif( el.readyState > 1 ) {\r\n\t\t\t\t\t\tthis.startEmbeddedMedia( { target: el } );\r\n\t\t\t\t\t}\r\n\t\t\t\t\t// Mobile devices never fire a loaded event so instead\r\n\t\t\t\t\t// of waiting, we initiate playback\r\n\t\t\t\t\telse if( isMobile ) {\r\n\t\t\t\t\t\tlet promise = el.play();\r\n\r\n\t\t\t\t\t\t// If autoplay does not work, ensure that the controls are visible so\r\n\t\t\t\t\t\t// that the viewer can start the media on their own\r\n\t\t\t\t\t\tif( promise && typeof promise.catch === 'function' && el.controls === false ) {\r\n\t\t\t\t\t\t\tpromise.catch( () => {\r\n\t\t\t\t\t\t\t\tel.controls = true;\r\n\r\n\t\t\t\t\t\t\t\t// Once the video does start playing, hide the controls again\r\n\t\t\t\t\t\t\t\tel.addEventListener( 'play', () => {\r\n\t\t\t\t\t\t\t\t\tel.controls = false;\r\n\t\t\t\t\t\t\t\t} );\r\n\t\t\t\t\t\t\t} );\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\t// If the media isn't loaded, wait before playing\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tel.removeEventListener( 'loadeddata', this.startEmbeddedMedia ); // remove first to avoid dupes\r\n\t\t\t\t\t\tel.addEventListener( 'loadeddata', this.startEmbeddedMedia );\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\t\t\t} );\r\n\r\n\t\t\t// Normal iframes\r\n\t\t\tqueryAll( element, 'iframe[src]' ).forEach( el => {\r\n\t\t\t\tif( closest( el, '.fragment' ) && !closest( el, '.fragment.visible' ) ) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis.startEmbeddedIframe( { target: el } );\r\n\t\t\t} );\r\n\r\n\t\t\t// Lazy loading iframes\r\n\t\t\tqueryAll( element, 'iframe[data-src]' ).forEach( el => {\r\n\t\t\t\tif( closest( el, '.fragment' ) && !closest( el, '.fragment.visible' ) ) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif( el.getAttribute( 'src' ) !== el.getAttribute( 'data-src' ) ) {\r\n\t\t\t\t\tel.removeEventListener( 'load', this.startEmbeddedIframe ); // remove first to avoid dupes\r\n\t\t\t\t\tel.addEventListener( 'load', this.startEmbeddedIframe );\r\n\t\t\t\t\tel.setAttribute( 'src', el.getAttribute( 'data-src' ) );\r\n\t\t\t\t}\r\n\t\t\t} );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Starts playing an embedded video/audio element after\r\n\t * it has finished loading.\r\n\t *\r\n\t * @param {object} event\r\n\t */\r\n\tstartEmbeddedMedia( event ) {\r\n\r\n\t\tlet isAttachedToDOM = !!closest( event.target, 'html' ),\r\n\t\t\tisVisible \t\t= !!closest( event.target, '.present' );\r\n\r\n\t\tif( isAttachedToDOM && isVisible ) {\r\n\t\t\tevent.target.currentTime = 0;\r\n\t\t\tevent.target.play();\r\n\t\t}\r\n\r\n\t\tevent.target.removeEventListener( 'loadeddata', this.startEmbeddedMedia );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * \"Starts\" the content of an embedded iframe using the\r\n\t * postMessage API.\r\n\t *\r\n\t * @param {object} event\r\n\t */\r\n\tstartEmbeddedIframe( event ) {\r\n\r\n\t\tlet iframe = event.target;\r\n\r\n\t\tif( iframe && iframe.contentWindow ) {\r\n\r\n\t\t\tlet isAttachedToDOM = !!closest( event.target, 'html' ),\r\n\t\t\t\tisVisible \t\t= !!closest( event.target, '.present' );\r\n\r\n\t\t\tif( isAttachedToDOM && isVisible ) {\r\n\r\n\t\t\t\t// Prefer an explicit global autoplay setting\r\n\t\t\t\tlet autoplay = this.Reveal.getConfig().autoPlayMedia;\r\n\r\n\t\t\t\t// If no global setting is available, fall back on the element's\r\n\t\t\t\t// own autoplay setting\r\n\t\t\t\tif( typeof autoplay !== 'boolean' ) {\r\n\t\t\t\t\tautoplay = iframe.hasAttribute( 'data-autoplay' ) || !!closest( iframe, '.slide-background' );\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// YouTube postMessage API\r\n\t\t\t\tif( /youtube\\.com\\/embed\\//.test( iframe.getAttribute( 'src' ) ) && autoplay ) {\r\n\t\t\t\t\tiframe.contentWindow.postMessage( '{\"event\":\"command\",\"func\":\"playVideo\",\"args\":\"\"}', '*' );\r\n\t\t\t\t}\r\n\t\t\t\t// Vimeo postMessage API\r\n\t\t\t\telse if( /player\\.vimeo\\.com\\//.test( iframe.getAttribute( 'src' ) ) && autoplay ) {\r\n\t\t\t\t\tiframe.contentWindow.postMessage( '{\"method\":\"play\"}', '*' );\r\n\t\t\t\t}\r\n\t\t\t\t// Generic postMessage API\r\n\t\t\t\telse {\r\n\t\t\t\t\tiframe.contentWindow.postMessage( 'slide:start', '*' );\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Stop playback of any embedded content inside of\r\n\t * the targeted slide.\r\n\t *\r\n\t * @param {HTMLElement} element\r\n\t */\r\n\tstopEmbeddedContent( element, options = {} ) {\r\n\r\n\t\toptions = extend( {\r\n\t\t\t// Defaults\r\n\t\t\tunloadIframes: true\r\n\t\t}, options );\r\n\r\n\t\tif( element && element.parentNode ) {\r\n\t\t\t// HTML5 media elements\r\n\t\t\tqueryAll( element, 'video, audio' ).forEach( el => {\r\n\t\t\t\tif( !el.hasAttribute( 'data-ignore' ) && typeof el.pause === 'function' ) {\r\n\t\t\t\t\tel.setAttribute('data-paused-by-reveal', '');\r\n\t\t\t\t\tel.pause();\r\n\t\t\t\t}\r\n\t\t\t} );\r\n\r\n\t\t\t// Generic postMessage API for non-lazy loaded iframes\r\n\t\t\tqueryAll( element, 'iframe' ).forEach( el => {\r\n\t\t\t\tif( el.contentWindow ) el.contentWindow.postMessage( 'slide:stop', '*' );\r\n\t\t\t\tel.removeEventListener( 'load', this.startEmbeddedIframe );\r\n\t\t\t});\r\n\r\n\t\t\t// YouTube postMessage API\r\n\t\t\tqueryAll( element, 'iframe[src*=\"youtube.com/embed/\"]' ).forEach( el => {\r\n\t\t\t\tif( !el.hasAttribute( 'data-ignore' ) && el.contentWindow && typeof el.contentWindow.postMessage === 'function' ) {\r\n\t\t\t\t\tel.contentWindow.postMessage( '{\"event\":\"command\",\"func\":\"pauseVideo\",\"args\":\"\"}', '*' );\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\t\t// Vimeo postMessage API\r\n\t\t\tqueryAll( element, 'iframe[src*=\"player.vimeo.com/\"]' ).forEach( el => {\r\n\t\t\t\tif( !el.hasAttribute( 'data-ignore' ) && el.contentWindow && typeof el.contentWindow.postMessage === 'function' ) {\r\n\t\t\t\t\tel.contentWindow.postMessage( '{\"method\":\"pause\"}', '*' );\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\t\tif( options.unloadIframes === true ) {\r\n\t\t\t\t// Unload lazy-loaded iframes\r\n\t\t\t\tqueryAll( element, 'iframe[data-src]' ).forEach( el => {\r\n\t\t\t\t\t// Only removing the src doesn't actually unload the frame\r\n\t\t\t\t\t// in all browsers (Firefox) so we set it to blank first\r\n\t\t\t\t\tel.setAttribute( 'src', 'about:blank' );\r\n\t\t\t\t\tel.removeAttribute( 'src' );\r\n\t\t\t\t} );\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t}\r\n\r\n}\r\n","\r\nexport const SLIDES_SELECTOR = '.slides section';\r\nexport const HORIZONTAL_SLIDES_SELECTOR = '.slides>section';\r\nexport const VERTICAL_SLIDES_SELECTOR = '.slides>section.present>section';\r\n\r\n// Methods that may not be invoked via the postMessage API\r\nexport const POST_MESSAGE_METHOD_BLACKLIST = /registerPlugin|registerKeyboardShortcut|addKeyBinding|addEventListener|showPreview/;\r\n\r\n// Regex for retrieving the fragment style from a class attribute\r\nexport const FRAGMENT_STYLE_REGEX = /fade-(down|up|right|left|out|in-then-out|in-then-semi-out)|semi-fade-out|current-visible|shrink|grow/;\r\n\r\n// Slide number formats\r\nexport const SLIDE_NUMBER_FORMAT_HORIZONTAL_DOT_VERTICAL = 'h.v';\r\nexport const SLIDE_NUMBER_FORMAT_HORIZONTAL_SLASH_VERTICAL = 'h/v';\r\nexport const SLIDE_NUMBER_FORMAT_CURRENT = 'c';\r\nexport const SLIDE_NUMBER_FORMAT_CURRENT_SLASH_TOTAL = 'c/t';","import {\r\n\tSLIDE_NUMBER_FORMAT_CURRENT,\r\n\tSLIDE_NUMBER_FORMAT_CURRENT_SLASH_TOTAL,\r\n\tSLIDE_NUMBER_FORMAT_HORIZONTAL_DOT_VERTICAL,\r\n\tSLIDE_NUMBER_FORMAT_HORIZONTAL_SLASH_VERTICAL\r\n} from \"../utils/constants\";\r\n\r\n/**\r\n * Handles the display of reveal.js' optional slide number.\r\n */\r\nexport default class SlideNumber {\r\n\r\n\tconstructor( Reveal ) {\r\n\r\n\t\tthis.Reveal = Reveal;\r\n\r\n\t}\r\n\r\n\trender() {\r\n\r\n\t\tthis.element = document.createElement( 'div' );\r\n\t\tthis.element.className = 'slide-number';\r\n\t\tthis.Reveal.getRevealElement().appendChild( this.element );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Called when the reveal.js config is updated.\r\n\t */\r\n\tconfigure( config, oldConfig ) {\r\n\r\n\t\tlet slideNumberDisplay = 'none';\r\n\t\tif( config.slideNumber && !this.Reveal.isPrintView() ) {\r\n\t\t\tif( config.showSlideNumber === 'all' ) {\r\n\t\t\t\tslideNumberDisplay = 'block';\r\n\t\t\t}\r\n\t\t\telse if( config.showSlideNumber === 'speaker' && this.Reveal.isSpeakerNotes() ) {\r\n\t\t\t\tslideNumberDisplay = 'block';\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis.element.style.display = slideNumberDisplay;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Updates the slide number to match the current slide.\r\n\t */\r\n\tupdate() {\r\n\r\n\t\t// Update slide number if enabled\r\n\t\tif( this.Reveal.getConfig().slideNumber && this.element ) {\r\n\t\t\tthis.element.innerHTML = this.getSlideNumber();\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the HTML string corresponding to the current slide\r\n\t * number, including formatting.\r\n\t */\r\n\tgetSlideNumber( slide = this.Reveal.getCurrentSlide() ) {\r\n\r\n\t\tlet config = this.Reveal.getConfig();\r\n\t\tlet value;\r\n\t\tlet format = SLIDE_NUMBER_FORMAT_HORIZONTAL_DOT_VERTICAL;\r\n\r\n\t\tif ( typeof config.slideNumber === 'function' ) {\r\n\t\t\tvalue = config.slideNumber( slide );\r\n\t\t} else {\r\n\t\t\t// Check if a custom number format is available\r\n\t\t\tif( typeof config.slideNumber === 'string' ) {\r\n\t\t\t\tformat = config.slideNumber;\r\n\t\t\t}\r\n\r\n\t\t\t// If there are ONLY vertical slides in this deck, always use\r\n\t\t\t// a flattened slide number\r\n\t\t\tif( !/c/.test( format ) && this.Reveal.getHorizontalSlides().length === 1 ) {\r\n\t\t\t\tformat = SLIDE_NUMBER_FORMAT_CURRENT;\r\n\t\t\t}\r\n\r\n\t\t\t// Offset the current slide number by 1 to make it 1-indexed\r\n\t\t\tlet horizontalOffset = slide && slide.dataset.visibility === 'uncounted' ? 0 : 1;\r\n\r\n\t\t\tvalue = [];\r\n\t\t\tswitch( format ) {\r\n\t\t\t\tcase SLIDE_NUMBER_FORMAT_CURRENT:\r\n\t\t\t\t\tvalue.push( this.Reveal.getSlidePastCount( slide ) + horizontalOffset );\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase SLIDE_NUMBER_FORMAT_CURRENT_SLASH_TOTAL:\r\n\t\t\t\t\tvalue.push( this.Reveal.getSlidePastCount( slide ) + horizontalOffset, '/', this.Reveal.getTotalSlides() );\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tdefault:\r\n\t\t\t\t\tlet indices = this.Reveal.getIndices( slide );\r\n\t\t\t\t\tvalue.push( indices.h + horizontalOffset );\r\n\t\t\t\t\tlet sep = format === SLIDE_NUMBER_FORMAT_HORIZONTAL_SLASH_VERTICAL ? '/' : '.';\r\n\t\t\t\t\tif( this.Reveal.isVerticalSlide( slide ) ) value.push( sep, indices.v + 1 );\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet url = '#' + this.Reveal.location.getHash( slide );\r\n\t\treturn this.formatNumber( value[0], value[1], value[2], url );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Applies HTML formatting to a slide number before it's\r\n\t * written to the DOM.\r\n\t *\r\n\t * @param {number} a Current slide\r\n\t * @param {string} delimiter Character to separate slide numbers\r\n\t * @param {(number|*)} b Total slides\r\n\t * @param {HTMLElement} [url='#'+locationHash()] The url to link to\r\n\t * @return {string} HTML string fragment\r\n\t */\r\n\tformatNumber( a, delimiter, b, url = '#' + this.Reveal.location.getHash() ) {\r\n\r\n\t\tif( typeof b === 'number' && !isNaN( b ) ) {\r\n\t\t\treturn `\r\n\t\t\t\t\t${a}\r\n\t\t\t\t\t${delimiter}\r\n\t\t\t\t\t${b}\r\n\t\t\t\t\t`;\r\n\t\t}\r\n\t\telse {\r\n\t\t\treturn `\r\n\t\t\t\t\t${a}\r\n\t\t\t\t\t`;\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tdestroy() {\r\n\r\n\t\tthis.element.remove();\r\n\r\n\t}\r\n\r\n}","import {\r\n\tSLIDE_NUMBER_FORMAT_CURRENT,\r\n\tSLIDE_NUMBER_FORMAT_CURRENT_SLASH_TOTAL\r\n} from \"../utils/constants\";\r\n\r\n/**\r\n * Makes it possible to jump to a slide by entering its\r\n * slide number or id.\r\n */\r\nexport default class JumpToSlide {\r\n\r\n\tconstructor( Reveal ) {\r\n\r\n\t\tthis.Reveal = Reveal;\r\n\r\n\t\tthis.onInput = this.onInput.bind( this );\r\n\t\tthis.onBlur = this.onBlur.bind( this );\r\n\t\tthis.onKeyDown = this.onKeyDown.bind( this );\r\n\r\n\t}\r\n\r\n\trender() {\r\n\r\n\t\tthis.element = document.createElement( 'div' );\r\n\t\tthis.element.className = 'jump-to-slide';\r\n\r\n this.jumpInput = document.createElement( 'input' );\r\n this.jumpInput.type = 'text';\r\n this.jumpInput.className = 'jump-to-slide-input';\r\n this.jumpInput.placeholder = 'Jump to slide';\r\n\t\tthis.jumpInput.addEventListener( 'input', this.onInput );\r\n\t\tthis.jumpInput.addEventListener( 'keydown', this.onKeyDown );\r\n\t\tthis.jumpInput.addEventListener( 'blur', this.onBlur );\r\n\r\n this.element.appendChild( this.jumpInput );\r\n\r\n\t}\r\n\r\n\tshow() {\r\n\r\n\t\tthis.indicesOnShow = this.Reveal.getIndices();\r\n\r\n\t\tthis.Reveal.getRevealElement().appendChild( this.element );\r\n\t\tthis.jumpInput.focus();\r\n\r\n\t}\r\n\r\n\thide() {\r\n\r\n\t\tif( this.isVisible() ) {\r\n\t\t\tthis.element.remove();\r\n\t\t\tthis.jumpInput.value = '';\r\n\r\n\t\t\tclearTimeout( this.jumpTimeout );\r\n\t\t\tdelete this.jumpTimeout;\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tisVisible() {\r\n\r\n\t\treturn !!this.element.parentNode;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Parses the current input and jumps to the given slide.\r\n\t */\r\n\tjump() {\r\n\r\n\t\tclearTimeout( this.jumpTimeout );\r\n\t\tdelete this.jumpTimeout;\r\n\r\n\t\tlet query = this.jumpInput.value.trim( '' );\r\n\t\tlet indices;\r\n\r\n\t\t// When slide numbers are formatted to be a single linear mumber\r\n\t\t// (instead of showing a separate horizontal/vertical index) we\r\n\t\t// use the same format for slide jumps\r\n\t\tif( /^\\d+$/.test( query ) ) {\r\n\t\t\tconst slideNumberFormat = this.Reveal.getConfig().slideNumber;\r\n\t\t\tif( slideNumberFormat === SLIDE_NUMBER_FORMAT_CURRENT || slideNumberFormat === SLIDE_NUMBER_FORMAT_CURRENT_SLASH_TOTAL ) {\r\n\t\t\t\tconst slide = this.Reveal.getSlides()[ parseInt( query, 10 ) - 1 ];\r\n\t\t\t\tif( slide ) {\r\n\t\t\t\t\tindices = this.Reveal.getIndices( slide );\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif( !indices ) {\r\n\t\t\t// If the query uses \"horizontal.vertical\" format, convert to\r\n\t\t\t// \"horizontal/vertical\" so that our URL parser can understand\r\n\t\t\tif( /^\\d+\\.\\d+$/.test( query ) ) {\r\n\t\t\t\tquery = query.replace( '.', '/' );\r\n\t\t\t}\r\n\r\n\t\t\tindices = this.Reveal.location.getIndicesFromHash( query, { oneBasedIndex: true } );\r\n\t\t}\r\n\r\n\t\t// Still no valid index? Fall back on a text search\r\n\t\tif( !indices && /\\S+/i.test( query ) && query.length > 1 ) {\r\n\t\t\tindices = this.search( query );\r\n\t\t}\r\n\r\n\t\tif( indices && query !== '' ) {\r\n\t\t\tthis.Reveal.slide( indices.h, indices.v, indices.f );\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\telse {\r\n\t\t\tthis.Reveal.slide( this.indicesOnShow.h, this.indicesOnShow.v, this.indicesOnShow.f );\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tjumpAfter( delay ) {\r\n\r\n\t\tclearTimeout( this.jumpTimeout );\r\n\t\tthis.jumpTimeout = setTimeout( () => this.jump(), delay );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * A lofi search that looks for the given query in all\r\n\t * of our slides and returns the first match.\r\n\t */\r\n\tsearch( query ) {\r\n\r\n\t\tconst regex = new RegExp( '\\\\b' + query.trim() + '\\\\b', 'i' );\r\n\r\n\t\tconst slide = this.Reveal.getSlides().find( ( slide ) => {\r\n\t\t\treturn regex.test( slide.innerText );\r\n\t\t} );\r\n\r\n\t\tif( slide ) {\r\n\t\t\treturn this.Reveal.getIndices( slide );\r\n\t\t}\r\n\t\telse {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Reverts back to the slide we were on when jump to slide was\r\n\t * invoked.\r\n\t */\r\n\tcancel() {\r\n\r\n\t\tthis.Reveal.slide( this.indicesOnShow.h, this.indicesOnShow.v, this.indicesOnShow.f );\r\n\t\tthis.hide();\r\n\r\n\t}\r\n\r\n\tconfirm() {\r\n\r\n\t\tthis.jump();\r\n\t\tthis.hide();\r\n\r\n\t}\r\n\r\n\tdestroy() {\r\n\r\n\t\tthis.jumpInput.removeEventListener( 'input', this.onInput );\r\n\t\tthis.jumpInput.removeEventListener( 'keydown', this.onKeyDown );\r\n\t\tthis.jumpInput.removeEventListener( 'blur', this.onBlur );\r\n\r\n\t\tthis.element.remove();\r\n\r\n\t}\r\n\r\n\tonKeyDown( event ) {\r\n\r\n\t\tif( event.keyCode === 13 ) {\r\n\t\t\tthis.confirm();\r\n\t\t}\r\n\t\telse if( event.keyCode === 27 ) {\r\n\t\t\tthis.cancel();\r\n\r\n\t\t\tevent.stopImmediatePropagation();\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tonInput( event ) {\r\n\r\n\t\tthis.jumpAfter( 200 );\r\n\r\n\t}\r\n\r\n\tonBlur() {\r\n\r\n\t\tsetTimeout( () => this.hide(), 1 );\r\n\r\n\t}\r\n\r\n}","/**\r\n * Converts various color input formats to an {r:0,g:0,b:0} object.\r\n *\r\n * @param {string} color The string representation of a color\r\n * @example\r\n * colorToRgb('#000');\r\n * @example\r\n * colorToRgb('#000000');\r\n * @example\r\n * colorToRgb('rgb(0,0,0)');\r\n * @example\r\n * colorToRgb('rgba(0,0,0)');\r\n *\r\n * @return {{r: number, g: number, b: number, [a]: number}|null}\r\n */\r\nexport const colorToRgb = ( color ) => {\r\n\r\n\tlet hex3 = color.match( /^#([0-9a-f]{3})$/i );\r\n\tif( hex3 && hex3[1] ) {\r\n\t\thex3 = hex3[1];\r\n\t\treturn {\r\n\t\t\tr: parseInt( hex3.charAt( 0 ), 16 ) * 0x11,\r\n\t\t\tg: parseInt( hex3.charAt( 1 ), 16 ) * 0x11,\r\n\t\t\tb: parseInt( hex3.charAt( 2 ), 16 ) * 0x11\r\n\t\t};\r\n\t}\r\n\r\n\tlet hex6 = color.match( /^#([0-9a-f]{6})$/i );\r\n\tif( hex6 && hex6[1] ) {\r\n\t\thex6 = hex6[1];\r\n\t\treturn {\r\n\t\t\tr: parseInt( hex6.slice( 0, 2 ), 16 ),\r\n\t\t\tg: parseInt( hex6.slice( 2, 4 ), 16 ),\r\n\t\t\tb: parseInt( hex6.slice( 4, 6 ), 16 )\r\n\t\t};\r\n\t}\r\n\r\n\tlet rgb = color.match( /^rgb\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)$/i );\r\n\tif( rgb ) {\r\n\t\treturn {\r\n\t\t\tr: parseInt( rgb[1], 10 ),\r\n\t\t\tg: parseInt( rgb[2], 10 ),\r\n\t\t\tb: parseInt( rgb[3], 10 )\r\n\t\t};\r\n\t}\r\n\r\n\tlet rgba = color.match( /^rgba\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\,\\s*([\\d]+|[\\d]*.[\\d]+)\\s*\\)$/i );\r\n\tif( rgba ) {\r\n\t\treturn {\r\n\t\t\tr: parseInt( rgba[1], 10 ),\r\n\t\t\tg: parseInt( rgba[2], 10 ),\r\n\t\t\tb: parseInt( rgba[3], 10 ),\r\n\t\t\ta: parseFloat( rgba[4] )\r\n\t\t};\r\n\t}\r\n\r\n\treturn null;\r\n\r\n}\r\n\r\n/**\r\n * Calculates brightness on a scale of 0-255.\r\n *\r\n * @param {string} color See colorToRgb for supported formats.\r\n * @see {@link colorToRgb}\r\n */\r\nexport const colorBrightness = ( color ) => {\r\n\r\n\tif( typeof color === 'string' ) color = colorToRgb( color );\r\n\r\n\tif( color ) {\r\n\t\treturn ( color.r * 299 + color.g * 587 + color.b * 114 ) / 1000;\r\n\t}\r\n\r\n\treturn null;\r\n\r\n}","import { queryAll } from '../utils/util.js'\r\nimport { colorToRgb, colorBrightness } from '../utils/color.js'\r\n\r\n/**\r\n * Creates and updates slide backgrounds.\r\n */\r\nexport default class Backgrounds {\r\n\r\n\tconstructor( Reveal ) {\r\n\r\n\t\tthis.Reveal = Reveal;\r\n\r\n\t}\r\n\r\n\trender() {\r\n\r\n\t\tthis.element = document.createElement( 'div' );\r\n\t\tthis.element.className = 'backgrounds';\r\n\t\tthis.Reveal.getRevealElement().appendChild( this.element );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Creates the slide background elements and appends them\r\n\t * to the background container. One element is created per\r\n\t * slide no matter if the given slide has visible background.\r\n\t */\r\n\tcreate() {\r\n\r\n\t\t// Clear prior backgrounds\r\n\t\tthis.element.innerHTML = '';\r\n\t\tthis.element.classList.add( 'no-transition' );\r\n\r\n\t\t// Iterate over all horizontal slides\r\n\t\tthis.Reveal.getHorizontalSlides().forEach( slideh => {\r\n\r\n\t\t\tlet backgroundStack = this.createBackground( slideh, this.element );\r\n\r\n\t\t\t// Iterate over all vertical slides\r\n\t\t\tqueryAll( slideh, 'section' ).forEach( slidev => {\r\n\r\n\t\t\t\tthis.createBackground( slidev, backgroundStack );\r\n\r\n\t\t\t\tbackgroundStack.classList.add( 'stack' );\r\n\r\n\t\t\t} );\r\n\r\n\t\t} );\r\n\r\n\t\t// Add parallax background if specified\r\n\t\tif( this.Reveal.getConfig().parallaxBackgroundImage ) {\r\n\r\n\t\t\tthis.element.style.backgroundImage = 'url(\"' + this.Reveal.getConfig().parallaxBackgroundImage + '\")';\r\n\t\t\tthis.element.style.backgroundSize = this.Reveal.getConfig().parallaxBackgroundSize;\r\n\t\t\tthis.element.style.backgroundRepeat = this.Reveal.getConfig().parallaxBackgroundRepeat;\r\n\t\t\tthis.element.style.backgroundPosition = this.Reveal.getConfig().parallaxBackgroundPosition;\r\n\r\n\t\t\t// Make sure the below properties are set on the element - these properties are\r\n\t\t\t// needed for proper transitions to be set on the element via CSS. To remove\r\n\t\t\t// annoying background slide-in effect when the presentation starts, apply\r\n\t\t\t// these properties after short time delay\r\n\t\t\tsetTimeout( () => {\r\n\t\t\t\tthis.Reveal.getRevealElement().classList.add( 'has-parallax-background' );\r\n\t\t\t}, 1 );\r\n\r\n\t\t}\r\n\t\telse {\r\n\r\n\t\t\tthis.element.style.backgroundImage = '';\r\n\t\t\tthis.Reveal.getRevealElement().classList.remove( 'has-parallax-background' );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Creates a background for the given slide.\r\n\t *\r\n\t * @param {HTMLElement} slide\r\n\t * @param {HTMLElement} container The element that the background\r\n\t * should be appended to\r\n\t * @return {HTMLElement} New background div\r\n\t */\r\n\tcreateBackground( slide, container ) {\r\n\r\n\t\t// Main slide background element\r\n\t\tlet element = document.createElement( 'div' );\r\n\t\telement.className = 'slide-background ' + slide.className.replace( /present|past|future/, '' );\r\n\r\n\t\t// Inner background element that wraps images/videos/iframes\r\n\t\tlet contentElement = document.createElement( 'div' );\r\n\t\tcontentElement.className = 'slide-background-content';\r\n\r\n\t\telement.appendChild( contentElement );\r\n\t\tcontainer.appendChild( element );\r\n\r\n\t\tslide.slideBackgroundElement = element;\r\n\t\tslide.slideBackgroundContentElement = contentElement;\r\n\r\n\t\t// Syncs the background to reflect all current background settings\r\n\t\tthis.sync( slide );\r\n\r\n\t\treturn element;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Renders all of the visual properties of a slide background\r\n\t * based on the various background attributes.\r\n\t *\r\n\t * @param {HTMLElement} slide\r\n\t */\r\n\tsync( slide ) {\r\n\r\n\t\tconst element = slide.slideBackgroundElement,\r\n\t\t\tcontentElement = slide.slideBackgroundContentElement;\r\n\r\n\t\tconst data = {\r\n\t\t\tbackground: slide.getAttribute( 'data-background' ),\r\n\t\t\tbackgroundSize: slide.getAttribute( 'data-background-size' ),\r\n\t\t\tbackgroundImage: slide.getAttribute( 'data-background-image' ),\r\n\t\t\tbackgroundVideo: slide.getAttribute( 'data-background-video' ),\r\n\t\t\tbackgroundIframe: slide.getAttribute( 'data-background-iframe' ),\r\n\t\t\tbackgroundColor: slide.getAttribute( 'data-background-color' ),\r\n\t\t\tbackgroundGradient: slide.getAttribute( 'data-background-gradient' ),\r\n\t\t\tbackgroundRepeat: slide.getAttribute( 'data-background-repeat' ),\r\n\t\t\tbackgroundPosition: slide.getAttribute( 'data-background-position' ),\r\n\t\t\tbackgroundTransition: slide.getAttribute( 'data-background-transition' ),\r\n\t\t\tbackgroundOpacity: slide.getAttribute( 'data-background-opacity' ),\r\n\t\t};\r\n\r\n\t\tconst dataPreload = slide.hasAttribute( 'data-preload' );\r\n\r\n\t\t// Reset the prior background state in case this is not the\r\n\t\t// initial sync\r\n\t\tslide.classList.remove( 'has-dark-background' );\r\n\t\tslide.classList.remove( 'has-light-background' );\r\n\r\n\t\telement.removeAttribute( 'data-loaded' );\r\n\t\telement.removeAttribute( 'data-background-hash' );\r\n\t\telement.removeAttribute( 'data-background-size' );\r\n\t\telement.removeAttribute( 'data-background-transition' );\r\n\t\telement.style.backgroundColor = '';\r\n\r\n\t\tcontentElement.style.backgroundSize = '';\r\n\t\tcontentElement.style.backgroundRepeat = '';\r\n\t\tcontentElement.style.backgroundPosition = '';\r\n\t\tcontentElement.style.backgroundImage = '';\r\n\t\tcontentElement.style.opacity = '';\r\n\t\tcontentElement.innerHTML = '';\r\n\r\n\t\tif( data.background ) {\r\n\t\t\t// Auto-wrap image urls in url(...)\r\n\t\t\tif( /^(http|file|\\/\\/)/gi.test( data.background ) || /\\.(svg|png|jpg|jpeg|gif|bmp|webp)([?#\\s]|$)/gi.test( data.background ) ) {\r\n\t\t\t\tslide.setAttribute( 'data-background-image', data.background );\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\telement.style.background = data.background;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Create a hash for this combination of background settings.\r\n\t\t// This is used to determine when two slide backgrounds are\r\n\t\t// the same.\r\n\t\tif( data.background || data.backgroundColor || data.backgroundGradient || data.backgroundImage || data.backgroundVideo || data.backgroundIframe ) {\r\n\t\t\telement.setAttribute( 'data-background-hash', data.background +\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.backgroundSize +\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.backgroundImage +\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.backgroundVideo +\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.backgroundIframe +\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.backgroundColor +\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.backgroundGradient +\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.backgroundRepeat +\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.backgroundPosition +\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.backgroundTransition +\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.backgroundOpacity );\r\n\t\t}\r\n\r\n\t\t// Additional and optional background properties\r\n\t\tif( data.backgroundSize ) element.setAttribute( 'data-background-size', data.backgroundSize );\r\n\t\tif( data.backgroundColor ) element.style.backgroundColor = data.backgroundColor;\r\n\t\tif( data.backgroundGradient ) element.style.backgroundImage = data.backgroundGradient;\r\n\t\tif( data.backgroundTransition ) element.setAttribute( 'data-background-transition', data.backgroundTransition );\r\n\r\n\t\tif( dataPreload ) element.setAttribute( 'data-preload', '' );\r\n\r\n\t\t// Background image options are set on the content wrapper\r\n\t\tif( data.backgroundSize ) contentElement.style.backgroundSize = data.backgroundSize;\r\n\t\tif( data.backgroundRepeat ) contentElement.style.backgroundRepeat = data.backgroundRepeat;\r\n\t\tif( data.backgroundPosition ) contentElement.style.backgroundPosition = data.backgroundPosition;\r\n\t\tif( data.backgroundOpacity ) contentElement.style.opacity = data.backgroundOpacity;\r\n\r\n\t\tconst contrastClass = this.getContrastClass( slide );\r\n\r\n\t\tif( typeof contrastClass === 'string' ) {\r\n\t\t\tslide.classList.add( contrastClass );\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Returns a class name that can be applied to a slide to indicate\r\n\t * if it has a light or dark background.\r\n\t *\r\n\t * @param {*} slide\r\n\t *\r\n\t * @returns {string|null}\r\n\t */\r\n\tgetContrastClass( slide ) {\r\n\r\n\t\tconst element = slide.slideBackgroundElement;\r\n\r\n\t\t// If this slide has a background color, we add a class that\r\n\t\t// signals if it is light or dark. If the slide has no background\r\n\t\t// color, no class will be added\r\n\t\tlet contrastColor = slide.getAttribute( 'data-background-color' );\r\n\r\n\t\t// If no bg color was found, or it cannot be converted by colorToRgb, check the computed background\r\n\t\tif( !contrastColor || !colorToRgb( contrastColor ) ) {\r\n\t\t\tlet computedBackgroundStyle = window.getComputedStyle( element );\r\n\t\t\tif( computedBackgroundStyle && computedBackgroundStyle.backgroundColor ) {\r\n\t\t\t\tcontrastColor = computedBackgroundStyle.backgroundColor;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif( contrastColor ) {\r\n\t\t\tconst rgb = colorToRgb( contrastColor );\r\n\r\n\t\t\t// Ignore fully transparent backgrounds. Some browsers return\r\n\t\t\t// rgba(0,0,0,0) when reading the computed background color of\r\n\t\t\t// an element with no background\r\n\t\t\tif( rgb && rgb.a !== 0 ) {\r\n\t\t\t\tif( colorBrightness( contrastColor ) < 128 ) {\r\n\t\t\t\t\treturn 'has-dark-background';\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\treturn 'has-light-background';\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Bubble the 'has-light-background'/'has-dark-background' classes.\r\n\t */\r\n\tbubbleSlideContrastClassToElement( slide, target ) {\r\n\r\n\t\t[ 'has-light-background', 'has-dark-background' ].forEach( classToBubble => {\r\n\t\t\tif( slide.classList.contains( classToBubble ) ) {\r\n\t\t\t\ttarget.classList.add( classToBubble );\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\ttarget.classList.remove( classToBubble );\r\n\t\t\t}\r\n\t\t}, this );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Updates the background elements to reflect the current\r\n\t * slide.\r\n\t *\r\n\t * @param {boolean} includeAll If true, the backgrounds of\r\n\t * all vertical slides (not just the present) will be updated.\r\n\t */\r\n\tupdate( includeAll = false ) {\r\n\r\n\t\tlet currentSlide = this.Reveal.getCurrentSlide();\r\n\t\tlet indices = this.Reveal.getIndices();\r\n\r\n\t\tlet currentBackground = null;\r\n\r\n\t\t// Reverse past/future classes when in RTL mode\r\n\t\tlet horizontalPast = this.Reveal.getConfig().rtl ? 'future' : 'past',\r\n\t\t\thorizontalFuture = this.Reveal.getConfig().rtl ? 'past' : 'future';\r\n\r\n\t\t// Update the classes of all backgrounds to match the\r\n\t\t// states of their slides (past/present/future)\r\n\t\tArray.from( this.element.childNodes ).forEach( ( backgroundh, h ) => {\r\n\r\n\t\t\tbackgroundh.classList.remove( 'past', 'present', 'future' );\r\n\r\n\t\t\tif( h < indices.h ) {\r\n\t\t\t\tbackgroundh.classList.add( horizontalPast );\r\n\t\t\t}\r\n\t\t\telse if ( h > indices.h ) {\r\n\t\t\t\tbackgroundh.classList.add( horizontalFuture );\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tbackgroundh.classList.add( 'present' );\r\n\r\n\t\t\t\t// Store a reference to the current background element\r\n\t\t\t\tcurrentBackground = backgroundh;\r\n\t\t\t}\r\n\r\n\t\t\tif( includeAll || h === indices.h ) {\r\n\t\t\t\tqueryAll( backgroundh, '.slide-background' ).forEach( ( backgroundv, v ) => {\r\n\r\n\t\t\t\t\tbackgroundv.classList.remove( 'past', 'present', 'future' );\r\n\r\n\t\t\t\t\tconst indexv = typeof indices.v === 'number' ? indices.v : 0;\r\n\r\n\t\t\t\t\tif( v < indexv ) {\r\n\t\t\t\t\t\tbackgroundv.classList.add( 'past' );\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if ( v > indexv ) {\r\n\t\t\t\t\t\tbackgroundv.classList.add( 'future' );\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tbackgroundv.classList.add( 'present' );\r\n\r\n\t\t\t\t\t\t// Only if this is the present horizontal and vertical slide\r\n\t\t\t\t\t\tif( h === indices.h ) currentBackground = backgroundv;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t} );\r\n\t\t\t}\r\n\r\n\t\t} );\r\n\r\n\t\t// Stop content inside of previous backgrounds\r\n\t\tif( this.previousBackground ) {\r\n\r\n\t\t\tthis.Reveal.slideContent.stopEmbeddedContent( this.previousBackground, { unloadIframes: !this.Reveal.slideContent.shouldPreload( this.previousBackground ) } );\r\n\r\n\t\t}\r\n\r\n\t\t// Start content in the current background\r\n\t\tif( currentBackground ) {\r\n\r\n\t\t\tthis.Reveal.slideContent.startEmbeddedContent( currentBackground );\r\n\r\n\t\t\tlet currentBackgroundContent = currentBackground.querySelector( '.slide-background-content' );\r\n\t\t\tif( currentBackgroundContent ) {\r\n\r\n\t\t\t\tlet backgroundImageURL = currentBackgroundContent.style.backgroundImage || '';\r\n\r\n\t\t\t\t// Restart GIFs (doesn't work in Firefox)\r\n\t\t\t\tif( /\\.gif/i.test( backgroundImageURL ) ) {\r\n\t\t\t\t\tcurrentBackgroundContent.style.backgroundImage = '';\r\n\t\t\t\t\twindow.getComputedStyle( currentBackgroundContent ).opacity;\r\n\t\t\t\t\tcurrentBackgroundContent.style.backgroundImage = backgroundImageURL;\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\t// Don't transition between identical backgrounds. This\r\n\t\t\t// prevents unwanted flicker.\r\n\t\t\tlet previousBackgroundHash = this.previousBackground ? this.previousBackground.getAttribute( 'data-background-hash' ) : null;\r\n\t\t\tlet currentBackgroundHash = currentBackground.getAttribute( 'data-background-hash' );\r\n\t\t\tif( currentBackgroundHash && currentBackgroundHash === previousBackgroundHash && currentBackground !== this.previousBackground ) {\r\n\t\t\t\tthis.element.classList.add( 'no-transition' );\r\n\t\t\t}\r\n\r\n\t\t\tthis.previousBackground = currentBackground;\r\n\r\n\t\t}\r\n\r\n\t\t// If there's a background brightness flag for this slide,\r\n\t\t// bubble it to the .reveal container\r\n\t\tif( currentSlide ) {\r\n\t\t\tthis.bubbleSlideContrastClassToElement( currentSlide, this.Reveal.getRevealElement() );\r\n\t\t}\r\n\r\n\t\t// Allow the first background to apply without transition\r\n\t\tsetTimeout( () => {\r\n\t\t\tthis.element.classList.remove( 'no-transition' );\r\n\t\t}, 1 );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Updates the position of the parallax background based\r\n\t * on the current slide index.\r\n\t */\r\n\tupdateParallax() {\r\n\r\n\t\tlet indices = this.Reveal.getIndices();\r\n\r\n\t\tif( this.Reveal.getConfig().parallaxBackgroundImage ) {\r\n\r\n\t\t\tlet horizontalSlides = this.Reveal.getHorizontalSlides(),\r\n\t\t\t\tverticalSlides = this.Reveal.getVerticalSlides();\r\n\r\n\t\t\tlet backgroundSize = this.element.style.backgroundSize.split( ' ' ),\r\n\t\t\t\tbackgroundWidth, backgroundHeight;\r\n\r\n\t\t\tif( backgroundSize.length === 1 ) {\r\n\t\t\t\tbackgroundWidth = backgroundHeight = parseInt( backgroundSize[0], 10 );\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tbackgroundWidth = parseInt( backgroundSize[0], 10 );\r\n\t\t\t\tbackgroundHeight = parseInt( backgroundSize[1], 10 );\r\n\t\t\t}\r\n\r\n\t\t\tlet slideWidth = this.element.offsetWidth,\r\n\t\t\t\thorizontalSlideCount = horizontalSlides.length,\r\n\t\t\t\thorizontalOffsetMultiplier,\r\n\t\t\t\thorizontalOffset;\r\n\r\n\t\t\tif( typeof this.Reveal.getConfig().parallaxBackgroundHorizontal === 'number' ) {\r\n\t\t\t\thorizontalOffsetMultiplier = this.Reveal.getConfig().parallaxBackgroundHorizontal;\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\thorizontalOffsetMultiplier = horizontalSlideCount > 1 ? ( backgroundWidth - slideWidth ) / ( horizontalSlideCount-1 ) : 0;\r\n\t\t\t}\r\n\r\n\t\t\thorizontalOffset = horizontalOffsetMultiplier * indices.h * -1;\r\n\r\n\t\t\tlet slideHeight = this.element.offsetHeight,\r\n\t\t\t\tverticalSlideCount = verticalSlides.length,\r\n\t\t\t\tverticalOffsetMultiplier,\r\n\t\t\t\tverticalOffset;\r\n\r\n\t\t\tif( typeof this.Reveal.getConfig().parallaxBackgroundVertical === 'number' ) {\r\n\t\t\t\tverticalOffsetMultiplier = this.Reveal.getConfig().parallaxBackgroundVertical;\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tverticalOffsetMultiplier = ( backgroundHeight - slideHeight ) / ( verticalSlideCount-1 );\r\n\t\t\t}\r\n\r\n\t\t\tverticalOffset = verticalSlideCount > 0 ? verticalOffsetMultiplier * indices.v : 0;\r\n\r\n\t\t\tthis.element.style.backgroundPosition = horizontalOffset + 'px ' + -verticalOffset + 'px';\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tdestroy() {\r\n\r\n\t\tthis.element.remove();\r\n\r\n\t}\r\n\r\n}\r\n","import { queryAll, extend, createStyleSheet, matches, closest } from '../utils/util.js'\r\nimport { FRAGMENT_STYLE_REGEX } from '../utils/constants.js'\r\n\r\n// Counter used to generate unique IDs for auto-animated elements\r\nlet autoAnimateCounter = 0;\r\n\r\n/**\r\n * Automatically animates matching elements across\r\n * slides with the [data-auto-animate] attribute.\r\n */\r\nexport default class AutoAnimate {\r\n\r\n\tconstructor( Reveal ) {\r\n\r\n\t\tthis.Reveal = Reveal;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Runs an auto-animation between the given slides.\r\n\t *\r\n\t * @param {HTMLElement} fromSlide\r\n\t * @param {HTMLElement} toSlide\r\n\t */\r\n\trun( fromSlide, toSlide ) {\r\n\r\n\t\t// Clean up after prior animations\r\n\t\tthis.reset();\r\n\r\n\t\tlet allSlides = this.Reveal.getSlides();\r\n\t\tlet toSlideIndex = allSlides.indexOf( toSlide );\r\n\t\tlet fromSlideIndex = allSlides.indexOf( fromSlide );\r\n\r\n\t\t// Ensure that both slides are auto-animate targets with the same data-auto-animate-id value\r\n\t\t// (including null if absent on both) and that data-auto-animate-restart isn't set on the\r\n\t\t// physically latter slide (independent of slide direction)\r\n\t\tif( fromSlide.hasAttribute( 'data-auto-animate' ) && toSlide.hasAttribute( 'data-auto-animate' )\r\n\t\t\t\t&& fromSlide.getAttribute( 'data-auto-animate-id' ) === toSlide.getAttribute( 'data-auto-animate-id' ) \r\n\t\t\t\t&& !( toSlideIndex > fromSlideIndex ? toSlide : fromSlide ).hasAttribute( 'data-auto-animate-restart' ) ) {\r\n\r\n\t\t\t// Create a new auto-animate sheet\r\n\t\t\tthis.autoAnimateStyleSheet = this.autoAnimateStyleSheet || createStyleSheet();\r\n\r\n\t\t\tlet animationOptions = this.getAutoAnimateOptions( toSlide );\r\n\r\n\t\t\t// Set our starting state\r\n\t\t\tfromSlide.dataset.autoAnimate = 'pending';\r\n\t\t\ttoSlide.dataset.autoAnimate = 'pending';\r\n\r\n\t\t\t// Flag the navigation direction, needed for fragment buildup\r\n\t\t\tanimationOptions.slideDirection = toSlideIndex > fromSlideIndex ? 'forward' : 'backward';\r\n\r\n\t\t\t// If the from-slide is hidden because it has moved outside\r\n\t\t\t// the view distance, we need to temporarily show it while\r\n\t\t\t// measuring\r\n\t\t\tlet fromSlideIsHidden = fromSlide.style.display === 'none';\r\n\t\t\tif( fromSlideIsHidden ) fromSlide.style.display = this.Reveal.getConfig().display;\r\n\r\n\t\t\t// Inject our auto-animate styles for this transition\r\n\t\t\tlet css = this.getAutoAnimatableElements( fromSlide, toSlide ).map( elements => {\r\n\t\t\t\treturn this.autoAnimateElements( elements.from, elements.to, elements.options || {}, animationOptions, autoAnimateCounter++ );\r\n\t\t\t} );\r\n\r\n\t\t\tif( fromSlideIsHidden ) fromSlide.style.display = 'none';\r\n\r\n\t\t\t// Animate unmatched elements, if enabled\r\n\t\t\tif( toSlide.dataset.autoAnimateUnmatched !== 'false' && this.Reveal.getConfig().autoAnimateUnmatched === true ) {\r\n\r\n\t\t\t\t// Our default timings for unmatched elements\r\n\t\t\t\tlet defaultUnmatchedDuration = animationOptions.duration * 0.8,\r\n\t\t\t\t\tdefaultUnmatchedDelay = animationOptions.duration * 0.2;\r\n\r\n\t\t\t\tthis.getUnmatchedAutoAnimateElements( toSlide ).forEach( unmatchedElement => {\r\n\r\n\t\t\t\t\tlet unmatchedOptions = this.getAutoAnimateOptions( unmatchedElement, animationOptions );\r\n\t\t\t\t\tlet id = 'unmatched';\r\n\r\n\t\t\t\t\t// If there is a duration or delay set specifically for this\r\n\t\t\t\t\t// element our unmatched elements should adhere to those\r\n\t\t\t\t\tif( unmatchedOptions.duration !== animationOptions.duration || unmatchedOptions.delay !== animationOptions.delay ) {\r\n\t\t\t\t\t\tid = 'unmatched-' + autoAnimateCounter++;\r\n\t\t\t\t\t\tcss.push( `[data-auto-animate=\"running\"] [data-auto-animate-target=\"${id}\"] { transition: opacity ${unmatchedOptions.duration}s ease ${unmatchedOptions.delay}s; }` );\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tunmatchedElement.dataset.autoAnimateTarget = id;\r\n\r\n\t\t\t\t}, this );\r\n\r\n\t\t\t\t// Our default transition for unmatched elements\r\n\t\t\t\tcss.push( `[data-auto-animate=\"running\"] [data-auto-animate-target=\"unmatched\"] { transition: opacity ${defaultUnmatchedDuration}s ease ${defaultUnmatchedDelay}s; }` );\r\n\r\n\t\t\t}\r\n\r\n\t\t\t// Setting the whole chunk of CSS at once is the most\r\n\t\t\t// efficient way to do this. Using sheet.insertRule\r\n\t\t\t// is multiple factors slower.\r\n\t\t\tthis.autoAnimateStyleSheet.innerHTML = css.join( '' );\r\n\r\n\t\t\t// Start the animation next cycle\r\n\t\t\trequestAnimationFrame( () => {\r\n\t\t\t\tif( this.autoAnimateStyleSheet ) {\r\n\t\t\t\t\t// This forces our newly injected styles to be applied in Firefox\r\n\t\t\t\t\tgetComputedStyle( this.autoAnimateStyleSheet ).fontWeight;\r\n\r\n\t\t\t\t\ttoSlide.dataset.autoAnimate = 'running';\r\n\t\t\t\t}\r\n\t\t\t} );\r\n\r\n\t\t\tthis.Reveal.dispatchEvent({\r\n\t\t\t\ttype: 'autoanimate',\r\n\t\t\t\tdata: {\r\n\t\t\t\t\tfromSlide,\r\n\t\t\t\t\ttoSlide,\r\n\t\t\t\t\tsheet: this.autoAnimateStyleSheet\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Rolls back all changes that we've made to the DOM so\r\n\t * that as part of animating.\r\n\t */\r\n\treset() {\r\n\r\n\t\t// Reset slides\r\n\t\tqueryAll( this.Reveal.getRevealElement(), '[data-auto-animate]:not([data-auto-animate=\"\"])' ).forEach( element => {\r\n\t\t\telement.dataset.autoAnimate = '';\r\n\t\t} );\r\n\r\n\t\t// Reset elements\r\n\t\tqueryAll( this.Reveal.getRevealElement(), '[data-auto-animate-target]' ).forEach( element => {\r\n\t\t\tdelete element.dataset.autoAnimateTarget;\r\n\t\t} );\r\n\r\n\t\t// Remove the animation sheet\r\n\t\tif( this.autoAnimateStyleSheet && this.autoAnimateStyleSheet.parentNode ) {\r\n\t\t\tthis.autoAnimateStyleSheet.parentNode.removeChild( this.autoAnimateStyleSheet );\r\n\t\t\tthis.autoAnimateStyleSheet = null;\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Creates a FLIP animation where the `to` element starts out\r\n\t * in the `from` element position and animates to its original\r\n\t * state.\r\n\t *\r\n\t * @param {HTMLElement} from\r\n\t * @param {HTMLElement} to\r\n\t * @param {Object} elementOptions Options for this element pair\r\n\t * @param {Object} animationOptions Options set at the slide level\r\n\t * @param {String} id Unique ID that we can use to identify this\r\n\t * auto-animate element in the DOM\r\n\t */\r\n\tautoAnimateElements( from, to, elementOptions, animationOptions, id ) {\r\n\r\n\t\t// 'from' elements are given a data-auto-animate-target with no value,\r\n\t\t// 'to' elements are are given a data-auto-animate-target with an ID\r\n\t\tfrom.dataset.autoAnimateTarget = '';\r\n\t\tto.dataset.autoAnimateTarget = id;\r\n\r\n\t\t// Each element may override any of the auto-animate options\r\n\t\t// like transition easing, duration and delay via data-attributes\r\n\t\tlet options = this.getAutoAnimateOptions( to, animationOptions );\r\n\r\n\t\t// If we're using a custom element matcher the element options\r\n\t\t// may contain additional transition overrides\r\n\t\tif( typeof elementOptions.delay !== 'undefined' ) options.delay = elementOptions.delay;\r\n\t\tif( typeof elementOptions.duration !== 'undefined' ) options.duration = elementOptions.duration;\r\n\t\tif( typeof elementOptions.easing !== 'undefined' ) options.easing = elementOptions.easing;\r\n\r\n\t\tlet fromProps = this.getAutoAnimatableProperties( 'from', from, elementOptions ),\r\n\t\t\ttoProps = this.getAutoAnimatableProperties( 'to', to, elementOptions );\r\n\r\n\t\t// Maintain fragment visibility for matching elements when\r\n\t\t// we're navigating forwards, this way the viewer won't need\r\n\t\t// to step through the same fragments twice\r\n\t\tif( to.classList.contains( 'fragment' ) ) {\r\n\r\n\t\t\t// Don't auto-animate the opacity of fragments to avoid\r\n\t\t\t// conflicts with fragment animations\r\n\t\t\tdelete toProps.styles['opacity'];\r\n\r\n\t\t\tif( from.classList.contains( 'fragment' ) ) {\r\n\r\n\t\t\t\tlet fromFragmentStyle = ( from.className.match( FRAGMENT_STYLE_REGEX ) || [''] )[0];\r\n\t\t\t\tlet toFragmentStyle = ( to.className.match( FRAGMENT_STYLE_REGEX ) || [''] )[0];\r\n\r\n\t\t\t\t// Only skip the fragment if the fragment animation style\r\n\t\t\t\t// remains unchanged\r\n\t\t\t\tif( fromFragmentStyle === toFragmentStyle && animationOptions.slideDirection === 'forward' ) {\r\n\t\t\t\t\tto.classList.add( 'visible', 'disabled' );\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// If translation and/or scaling are enabled, css transform\r\n\t\t// the 'to' element so that it matches the position and size\r\n\t\t// of the 'from' element\r\n\t\tif( elementOptions.translate !== false || elementOptions.scale !== false ) {\r\n\r\n\t\t\tlet presentationScale = this.Reveal.getScale();\r\n\r\n\t\t\tlet delta = {\r\n\t\t\t\tx: ( fromProps.x - toProps.x ) / presentationScale,\r\n\t\t\t\ty: ( fromProps.y - toProps.y ) / presentationScale,\r\n\t\t\t\tscaleX: fromProps.width / toProps.width,\r\n\t\t\t\tscaleY: fromProps.height / toProps.height\r\n\t\t\t};\r\n\r\n\t\t\t// Limit decimal points to avoid 0.0001px blur and stutter\r\n\t\t\tdelta.x = Math.round( delta.x * 1000 ) / 1000;\r\n\t\t\tdelta.y = Math.round( delta.y * 1000 ) / 1000;\r\n\t\t\tdelta.scaleX = Math.round( delta.scaleX * 1000 ) / 1000;\r\n\t\t\tdelta.scaleX = Math.round( delta.scaleX * 1000 ) / 1000;\r\n\r\n\t\t\tlet translate = elementOptions.translate !== false && ( delta.x !== 0 || delta.y !== 0 ),\r\n\t\t\t\tscale = elementOptions.scale !== false && ( delta.scaleX !== 0 || delta.scaleY !== 0 );\r\n\r\n\t\t\t// No need to transform if nothing's changed\r\n\t\t\tif( translate || scale ) {\r\n\r\n\t\t\t\tlet transform = [];\r\n\r\n\t\t\t\tif( translate ) transform.push( `translate(${delta.x}px, ${delta.y}px)` );\r\n\t\t\t\tif( scale ) transform.push( `scale(${delta.scaleX}, ${delta.scaleY})` );\r\n\r\n\t\t\t\tfromProps.styles['transform'] = transform.join( ' ' );\r\n\t\t\t\tfromProps.styles['transform-origin'] = 'top left';\r\n\r\n\t\t\t\ttoProps.styles['transform'] = 'none';\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// Delete all unchanged 'to' styles\r\n\t\tfor( let propertyName in toProps.styles ) {\r\n\t\t\tconst toValue = toProps.styles[propertyName];\r\n\t\t\tconst fromValue = fromProps.styles[propertyName];\r\n\r\n\t\t\tif( toValue === fromValue ) {\r\n\t\t\t\tdelete toProps.styles[propertyName];\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\t// If these property values were set via a custom matcher providing\r\n\t\t\t\t// an explicit 'from' and/or 'to' value, we always inject those values.\r\n\t\t\t\tif( toValue.explicitValue === true ) {\r\n\t\t\t\t\ttoProps.styles[propertyName] = toValue.value;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif( fromValue.explicitValue === true ) {\r\n\t\t\t\t\tfromProps.styles[propertyName] = fromValue.value;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet css = '';\r\n\r\n\t\tlet toStyleProperties = Object.keys( toProps.styles );\r\n\r\n\t\t// Only create animate this element IF at least one style\r\n\t\t// property has changed\r\n\t\tif( toStyleProperties.length > 0 ) {\r\n\r\n\t\t\t// Instantly move to the 'from' state\r\n\t\t\tfromProps.styles['transition'] = 'none';\r\n\r\n\t\t\t// Animate towards the 'to' state\r\n\t\t\ttoProps.styles['transition'] = `all ${options.duration}s ${options.easing} ${options.delay}s`;\r\n\t\t\ttoProps.styles['transition-property'] = toStyleProperties.join( ', ' );\r\n\t\t\ttoProps.styles['will-change'] = toStyleProperties.join( ', ' );\r\n\r\n\t\t\t// Build up our custom CSS. We need to override inline styles\r\n\t\t\t// so we need to make our styles vErY IMPORTANT!1!!\r\n\t\t\tlet fromCSS = Object.keys( fromProps.styles ).map( propertyName => {\r\n\t\t\t\treturn propertyName + ': ' + fromProps.styles[propertyName] + ' !important;';\r\n\t\t\t} ).join( '' );\r\n\r\n\t\t\tlet toCSS = Object.keys( toProps.styles ).map( propertyName => {\r\n\t\t\t\treturn propertyName + ': ' + toProps.styles[propertyName] + ' !important;';\r\n\t\t\t} ).join( '' );\r\n\r\n\t\t\tcss = \t'[data-auto-animate-target=\"'+ id +'\"] {'+ fromCSS +'}' +\r\n\t\t\t\t\t'[data-auto-animate=\"running\"] [data-auto-animate-target=\"'+ id +'\"] {'+ toCSS +'}';\r\n\r\n\t\t}\r\n\r\n\t\treturn css;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the auto-animate options for the given element.\r\n\t *\r\n\t * @param {HTMLElement} element Element to pick up options\r\n\t * from, either a slide or an animation target\r\n\t * @param {Object} [inheritedOptions] Optional set of existing\r\n\t * options\r\n\t */\r\n\tgetAutoAnimateOptions( element, inheritedOptions ) {\r\n\r\n\t\tlet options = {\r\n\t\t\teasing: this.Reveal.getConfig().autoAnimateEasing,\r\n\t\t\tduration: this.Reveal.getConfig().autoAnimateDuration,\r\n\t\t\tdelay: 0\r\n\t\t};\r\n\r\n\t\toptions = extend( options, inheritedOptions );\r\n\r\n\t\t// Inherit options from parent elements\r\n\t\tif( element.parentNode ) {\r\n\t\t\tlet autoAnimatedParent = closest( element.parentNode, '[data-auto-animate-target]' );\r\n\t\t\tif( autoAnimatedParent ) {\r\n\t\t\t\toptions = this.getAutoAnimateOptions( autoAnimatedParent, options );\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif( element.dataset.autoAnimateEasing ) {\r\n\t\t\toptions.easing = element.dataset.autoAnimateEasing;\r\n\t\t}\r\n\r\n\t\tif( element.dataset.autoAnimateDuration ) {\r\n\t\t\toptions.duration = parseFloat( element.dataset.autoAnimateDuration );\r\n\t\t}\r\n\r\n\t\tif( element.dataset.autoAnimateDelay ) {\r\n\t\t\toptions.delay = parseFloat( element.dataset.autoAnimateDelay );\r\n\t\t}\r\n\r\n\t\treturn options;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Returns an object containing all of the properties\r\n\t * that can be auto-animated for the given element and\r\n\t * their current computed values.\r\n\t *\r\n\t * @param {String} direction 'from' or 'to'\r\n\t */\r\n\tgetAutoAnimatableProperties( direction, element, elementOptions ) {\r\n\r\n\t\tlet config = this.Reveal.getConfig();\r\n\r\n\t\tlet properties = { styles: [] };\r\n\r\n\t\t// Position and size\r\n\t\tif( elementOptions.translate !== false || elementOptions.scale !== false ) {\r\n\t\t\tlet bounds;\r\n\r\n\t\t\t// Custom auto-animate may optionally return a custom tailored\r\n\t\t\t// measurement function\r\n\t\t\tif( typeof elementOptions.measure === 'function' ) {\r\n\t\t\t\tbounds = elementOptions.measure( element );\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tif( config.center ) {\r\n\t\t\t\t\t// More precise, but breaks when used in combination\r\n\t\t\t\t\t// with zoom for scaling the deck ¯\\_(ツ)_/¯\r\n\t\t\t\t\tbounds = element.getBoundingClientRect();\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\tlet scale = this.Reveal.getScale();\r\n\t\t\t\t\tbounds = {\r\n\t\t\t\t\t\tx: element.offsetLeft * scale,\r\n\t\t\t\t\t\ty: element.offsetTop * scale,\r\n\t\t\t\t\t\twidth: element.offsetWidth * scale,\r\n\t\t\t\t\t\theight: element.offsetHeight * scale\r\n\t\t\t\t\t};\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tproperties.x = bounds.x;\r\n\t\t\tproperties.y = bounds.y;\r\n\t\t\tproperties.width = bounds.width;\r\n\t\t\tproperties.height = bounds.height;\r\n\t\t}\r\n\r\n\t\tconst computedStyles = getComputedStyle( element );\r\n\r\n\t\t// CSS styles\r\n\t\t( elementOptions.styles || config.autoAnimateStyles ).forEach( style => {\r\n\t\t\tlet value;\r\n\r\n\t\t\t// `style` is either the property name directly, or an object\r\n\t\t\t// definition of a style property\r\n\t\t\tif( typeof style === 'string' ) style = { property: style };\r\n\r\n\t\t\tif( typeof style.from !== 'undefined' && direction === 'from' ) {\r\n\t\t\t\tvalue = { value: style.from, explicitValue: true };\r\n\t\t\t}\r\n\t\t\telse if( typeof style.to !== 'undefined' && direction === 'to' ) {\r\n\t\t\t\tvalue = { value: style.to, explicitValue: true };\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\t// Use a unitless value for line-height so that it inherits properly\r\n\t\t\t\tif( style.property === 'line-height' ) {\r\n\t\t\t\t\tvalue = parseFloat( computedStyles['line-height'] ) / parseFloat( computedStyles['font-size'] );\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif( isNaN(value) ) {\r\n\t\t\t\t\tvalue = computedStyles[style.property];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif( value !== '' ) {\r\n\t\t\t\tproperties.styles[style.property] = value;\r\n\t\t\t}\r\n\t\t} );\r\n\r\n\t\treturn properties;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Get a list of all element pairs that we can animate\r\n\t * between the given slides.\r\n\t *\r\n\t * @param {HTMLElement} fromSlide\r\n\t * @param {HTMLElement} toSlide\r\n\t *\r\n\t * @return {Array} Each value is an array where [0] is\r\n\t * the element we're animating from and [1] is the\r\n\t * element we're animating to\r\n\t */\r\n\tgetAutoAnimatableElements( fromSlide, toSlide ) {\r\n\r\n\t\tlet matcher = typeof this.Reveal.getConfig().autoAnimateMatcher === 'function' ? this.Reveal.getConfig().autoAnimateMatcher : this.getAutoAnimatePairs;\r\n\r\n\t\tlet pairs = matcher.call( this, fromSlide, toSlide );\r\n\r\n\t\tlet reserved = [];\r\n\r\n\t\t// Remove duplicate pairs\r\n\t\treturn pairs.filter( ( pair, index ) => {\r\n\t\t\tif( reserved.indexOf( pair.to ) === -1 ) {\r\n\t\t\t\treserved.push( pair.to );\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t} );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Identifies matching elements between slides.\r\n\t *\r\n\t * You can specify a custom matcher function by using\r\n\t * the `autoAnimateMatcher` config option.\r\n\t */\r\n\tgetAutoAnimatePairs( fromSlide, toSlide ) {\r\n\r\n\t\tlet pairs = [];\r\n\r\n\t\tconst codeNodes = 'pre';\r\n\t\tconst textNodes = 'h1, h2, h3, h4, h5, h6, p, li';\r\n\t\tconst mediaNodes = 'img, video, iframe';\r\n\r\n\t\t// Explicit matches via data-id\r\n\t\tthis.findAutoAnimateMatches( pairs, fromSlide, toSlide, '[data-id]', node => {\r\n\t\t\treturn node.nodeName + ':::' + node.getAttribute( 'data-id' );\r\n\t\t} );\r\n\r\n\t\t// Text\r\n\t\tthis.findAutoAnimateMatches( pairs, fromSlide, toSlide, textNodes, node => {\r\n\t\t\treturn node.nodeName + ':::' + node.innerText;\r\n\t\t} );\r\n\r\n\t\t// Media\r\n\t\tthis.findAutoAnimateMatches( pairs, fromSlide, toSlide, mediaNodes, node => {\r\n\t\t\treturn node.nodeName + ':::' + ( node.getAttribute( 'src' ) || node.getAttribute( 'data-src' ) );\r\n\t\t} );\r\n\r\n\t\t// Code\r\n\t\tthis.findAutoAnimateMatches( pairs, fromSlide, toSlide, codeNodes, node => {\r\n\t\t\treturn node.nodeName + ':::' + node.innerText;\r\n\t\t} );\r\n\r\n\t\tpairs.forEach( pair => {\r\n\t\t\t// Disable scale transformations on text nodes, we transition\r\n\t\t\t// each individual text property instead\r\n\t\t\tif( matches( pair.from, textNodes ) ) {\r\n\t\t\t\tpair.options = { scale: false };\r\n\t\t\t}\r\n\t\t\t// Animate individual lines of code\r\n\t\t\telse if( matches( pair.from, codeNodes ) ) {\r\n\r\n\t\t\t\t// Transition the code block's width and height instead of scaling\r\n\t\t\t\t// to prevent its content from being squished\r\n\t\t\t\tpair.options = { scale: false, styles: [ 'width', 'height' ] };\r\n\r\n\t\t\t\t// Lines of code\r\n\t\t\t\tthis.findAutoAnimateMatches( pairs, pair.from, pair.to, '.hljs .hljs-ln-code', node => {\r\n\t\t\t\t\treturn node.textContent;\r\n\t\t\t\t}, {\r\n\t\t\t\t\tscale: false,\r\n\t\t\t\t\tstyles: [],\r\n\t\t\t\t\tmeasure: this.getLocalBoundingBox.bind( this )\r\n\t\t\t\t} );\r\n\r\n\t\t\t\t// Line numbers\r\n\t\t\t\tthis.findAutoAnimateMatches( pairs, pair.from, pair.to, '.hljs .hljs-ln-numbers[data-line-number]', node => {\r\n\t\t\t\t\treturn node.getAttribute( 'data-line-number' );\r\n\t\t\t\t}, {\r\n\t\t\t\t\tscale: false,\r\n\t\t\t\t\tstyles: [ 'width' ],\r\n\t\t\t\t\tmeasure: this.getLocalBoundingBox.bind( this )\r\n\t\t\t\t} );\r\n\r\n\t\t\t}\r\n\r\n\t\t}, this );\r\n\r\n\t\treturn pairs;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Helper method which returns a bounding box based on\r\n\t * the given elements offset coordinates.\r\n\t *\r\n\t * @param {HTMLElement} element\r\n\t * @return {Object} x, y, width, height\r\n\t */\r\n\tgetLocalBoundingBox( element ) {\r\n\r\n\t\tconst presentationScale = this.Reveal.getScale();\r\n\r\n\t\treturn {\r\n\t\t\tx: Math.round( ( element.offsetLeft * presentationScale ) * 100 ) / 100,\r\n\t\t\ty: Math.round( ( element.offsetTop * presentationScale ) * 100 ) / 100,\r\n\t\t\twidth: Math.round( ( element.offsetWidth * presentationScale ) * 100 ) / 100,\r\n\t\t\theight: Math.round( ( element.offsetHeight * presentationScale ) * 100 ) / 100\r\n\t\t};\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Finds matching elements between two slides.\r\n\t *\r\n\t * @param {Array} pairs \tList of pairs to push matches to\r\n\t * @param {HTMLElement} fromScope Scope within the from element exists\r\n\t * @param {HTMLElement} toScope Scope within the to element exists\r\n\t * @param {String} selector CSS selector of the element to match\r\n\t * @param {Function} serializer A function that accepts an element and returns\r\n\t * a stringified ID based on its contents\r\n\t * @param {Object} animationOptions Optional config options for this pair\r\n\t */\r\n\tfindAutoAnimateMatches( pairs, fromScope, toScope, selector, serializer, animationOptions ) {\r\n\r\n\t\tlet fromMatches = {};\r\n\t\tlet toMatches = {};\r\n\r\n\t\t[].slice.call( fromScope.querySelectorAll( selector ) ).forEach( ( element, i ) => {\r\n\t\t\tconst key = serializer( element );\r\n\t\t\tif( typeof key === 'string' && key.length ) {\r\n\t\t\t\tfromMatches[key] = fromMatches[key] || [];\r\n\t\t\t\tfromMatches[key].push( element );\r\n\t\t\t}\r\n\t\t} );\r\n\r\n\t\t[].slice.call( toScope.querySelectorAll( selector ) ).forEach( ( element, i ) => {\r\n\t\t\tconst key = serializer( element );\r\n\t\t\ttoMatches[key] = toMatches[key] || [];\r\n\t\t\ttoMatches[key].push( element );\r\n\r\n\t\t\tlet fromElement;\r\n\r\n\t\t\t// Retrieve the 'from' element\r\n\t\t\tif( fromMatches[key] ) {\r\n\t\t\t\tconst primaryIndex = toMatches[key].length - 1;\r\n\t\t\t\tconst secondaryIndex = fromMatches[key].length - 1;\r\n\r\n\t\t\t\t// If there are multiple identical from elements, retrieve\r\n\t\t\t\t// the one at the same index as our to-element.\r\n\t\t\t\tif( fromMatches[key][ primaryIndex ] ) {\r\n\t\t\t\t\tfromElement = fromMatches[key][ primaryIndex ];\r\n\t\t\t\t\tfromMatches[key][ primaryIndex ] = null;\r\n\t\t\t\t}\r\n\t\t\t\t// If there are no matching from-elements at the same index,\r\n\t\t\t\t// use the last one.\r\n\t\t\t\telse if( fromMatches[key][ secondaryIndex ] ) {\r\n\t\t\t\t\tfromElement = fromMatches[key][ secondaryIndex ];\r\n\t\t\t\t\tfromMatches[key][ secondaryIndex ] = null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// If we've got a matching pair, push it to the list of pairs\r\n\t\t\tif( fromElement ) {\r\n\t\t\t\tpairs.push({\r\n\t\t\t\t\tfrom: fromElement,\r\n\t\t\t\t\tto: element,\r\n\t\t\t\t\toptions: animationOptions\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t} );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Returns a all elements within the given scope that should\r\n\t * be considered unmatched in an auto-animate transition. If\r\n\t * fading of unmatched elements is turned on, these elements\r\n\t * will fade when going between auto-animate slides.\r\n\t *\r\n\t * Note that parents of auto-animate targets are NOT considered\r\n\t * unmatched since fading them would break the auto-animation.\r\n\t *\r\n\t * @param {HTMLElement} rootElement\r\n\t * @return {Array}\r\n\t */\r\n\tgetUnmatchedAutoAnimateElements( rootElement ) {\r\n\r\n\t\treturn [].slice.call( rootElement.children ).reduce( ( result, element ) => {\r\n\r\n\t\t\tconst containsAnimatedElements = element.querySelector( '[data-auto-animate-target]' );\r\n\r\n\t\t\t// The element is unmatched if\r\n\t\t\t// - It is not an auto-animate target\r\n\t\t\t// - It does not contain any auto-animate targets\r\n\t\t\tif( !element.hasAttribute( 'data-auto-animate-target' ) && !containsAnimatedElements ) {\r\n\t\t\t\tresult.push( element );\r\n\t\t\t}\r\n\r\n\t\t\tif( element.querySelector( '[data-auto-animate-target]' ) ) {\r\n\t\t\t\tresult = result.concat( this.getUnmatchedAutoAnimateElements( element ) );\r\n\t\t\t}\r\n\r\n\t\t\treturn result;\r\n\r\n\t\t}, [] );\r\n\r\n\t}\r\n\r\n}\r\n","import { HORIZONTAL_SLIDES_SELECTOR } from '../utils/constants.js'\r\nimport { queryAll } from '../utils/util.js'\r\n\r\nconst HIDE_SCROLLBAR_TIMEOUT = 500;\r\nconst MAX_PROGRESS_SPACING = 4;\r\nconst MIN_PROGRESS_SEGMENT_HEIGHT = 6;\r\nconst MIN_PLAYHEAD_HEIGHT = 8;\r\n\r\n/**\r\n * The scroll view lets you read a reveal.js presentation\r\n * as a linear scrollable page.\r\n */\r\nexport default class ScrollView {\r\n\r\n\tconstructor( Reveal ) {\r\n\r\n\t\tthis.Reveal = Reveal;\r\n\r\n\t\tthis.active = false;\r\n\t\tthis.activatedCallbacks = [];\r\n\r\n\t\tthis.onScroll = this.onScroll.bind( this );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Activates the scroll view. This rearranges the presentation DOM\r\n\t * by—among other things—wrapping each slide in a page element.\r\n\t */\r\n\tactivate() {\r\n\r\n\t\tif( this.active ) return;\r\n\r\n\t\tconst stateBeforeActivation = this.Reveal.getState();\r\n\r\n\t\tthis.active = true;\r\n\r\n\t\t// Store the full presentation HTML so that we can restore it\r\n\t\t// when/if the scroll view is deactivated\r\n\t\tthis.slideHTMLBeforeActivation = this.Reveal.getSlidesElement().innerHTML;\r\n\r\n\t\tconst horizontalSlides = queryAll( this.Reveal.getRevealElement(), HORIZONTAL_SLIDES_SELECTOR );\r\n\r\n\t\tthis.viewportElement.classList.add( 'loading-scroll-mode', 'reveal-scroll' );\r\n\r\n\t\tlet presentationBackground;\r\n\r\n\t\tconst viewportStyles = window.getComputedStyle( this.viewportElement );\r\n\t\tif( viewportStyles && viewportStyles.background ) {\r\n\t\t\tpresentationBackground = viewportStyles.background;\r\n\t\t}\r\n\r\n\t\tconst pageElements = [];\r\n\t\tconst pageContainer = horizontalSlides[0].parentNode;\r\n\r\n\t\tlet previousSlide;\r\n\r\n\t\t// Creates a new page element and appends the given slide/bg\r\n\t\t// to it.\r\n\t\tconst createPageElement = ( slide, h, v ) => {\r\n\r\n\t\t\tlet contentContainer;\r\n\r\n\t\t\t// If this slide is part of an auto-animation sequence, we\r\n\t\t\t// group it under the same page element as the previous slide\r\n\t\t\tif( previousSlide && this.Reveal.shouldAutoAnimateBetween( previousSlide, slide ) ) {\r\n\t\t\t\tcontentContainer = document.createElement( 'div' );\r\n\t\t\t\tcontentContainer.className = 'scroll-page-content scroll-auto-animate-page';\r\n\t\t\t\tcontentContainer.style.display = 'none';\r\n\t\t\t\tpreviousSlide.closest( '.scroll-page-content' ).parentNode.appendChild( contentContainer );\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\t// Wrap the slide in a page element and hide its overflow\r\n\t\t\t\t// so that no page ever flows onto another\r\n\t\t\t\tconst page = document.createElement( 'div' );\r\n\t\t\t\tpage.className = 'scroll-page';\r\n\t\t\t\tpageElements.push( page );\r\n\r\n\t\t\t\t// Copy the presentation-wide background to each page\r\n\t\t\t\tif( presentationBackground ) {\r\n\t\t\t\t\tpage.style.background = presentationBackground;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst stickyContainer = document.createElement( 'div' );\r\n\t\t\t\tstickyContainer.className = 'scroll-page-sticky';\r\n\t\t\t\tpage.appendChild( stickyContainer );\r\n\r\n\t\t\t\tcontentContainer = document.createElement( 'div' );\r\n\t\t\t\tcontentContainer.className = 'scroll-page-content';\r\n\t\t\t\tstickyContainer.appendChild( contentContainer );\r\n\t\t\t}\r\n\r\n\t\t\tcontentContainer.appendChild( slide );\r\n\r\n\t\t\tslide.classList.remove( 'past', 'future' );\r\n\t\t\tslide.setAttribute( 'data-index-h', h );\r\n\t\t\tslide.setAttribute( 'data-index-v', v );\r\n\r\n\t\t\tif( slide.slideBackgroundElement ) {\r\n\t\t\t\tslide.slideBackgroundElement.remove( 'past', 'future' );\r\n\t\t\t\tcontentContainer.insertBefore( slide.slideBackgroundElement, slide );\r\n\t\t\t}\r\n\r\n\t\t\tpreviousSlide = slide;\r\n\r\n\t\t}\r\n\r\n\t\t// Slide and slide background layout\r\n\t\thorizontalSlides.forEach( ( horizontalSlide, h ) => {\r\n\r\n\t\t\tif( this.Reveal.isVerticalStack( horizontalSlide ) ) {\r\n\t\t\t\thorizontalSlide.querySelectorAll( 'section' ).forEach( ( verticalSlide, v ) => {\r\n\t\t\t\t\tcreatePageElement( verticalSlide, h, v );\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tcreatePageElement( horizontalSlide, h, 0 );\r\n\t\t\t}\r\n\r\n\t\t}, this );\r\n\r\n\t\tthis.createProgressBar();\r\n\r\n\t\t// Remove leftover stacks\r\n\t\tqueryAll( this.Reveal.getRevealElement(), '.stack' ).forEach( stack => stack.remove() );\r\n\r\n\t\t// Add our newly created pages to the DOM\r\n\t\tpageElements.forEach( page => pageContainer.appendChild( page ) );\r\n\r\n\t\t// Re-run JS-based content layout after the slide is added to page DOM\r\n\t\tthis.Reveal.slideContent.layout( this.Reveal.getSlidesElement() );\r\n\r\n\t\tthis.Reveal.layout();\r\n\t\tthis.Reveal.setState( stateBeforeActivation );\r\n\r\n\t\tthis.activatedCallbacks.forEach( callback => callback() );\r\n\t\tthis.activatedCallbacks = [];\r\n\r\n\t\tthis.restoreScrollPosition();\r\n\r\n\t\tthis.viewportElement.classList.remove( 'loading-scroll-mode' );\r\n\t\tthis.viewportElement.addEventListener( 'scroll', this.onScroll, { passive: true } );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Deactivates the scroll view and restores the standard slide-based\r\n\t * presentation.\r\n\t */\r\n\tdeactivate() {\r\n\r\n\t\tif( !this.active ) return;\r\n\r\n\t\tconst stateBeforeDeactivation = this.Reveal.getState();\r\n\r\n\t\tthis.active = false;\r\n\r\n\t\tthis.viewportElement.removeEventListener( 'scroll', this.onScroll );\r\n\t\tthis.viewportElement.classList.remove( 'reveal-scroll' );\r\n\r\n\t\tthis.removeProgressBar();\r\n\r\n\t\tthis.Reveal.getSlidesElement().innerHTML = this.slideHTMLBeforeActivation;\r\n\t\tthis.Reveal.sync();\r\n\t\tthis.Reveal.setState( stateBeforeDeactivation );\r\n\r\n\t\tthis.slideHTMLBeforeActivation = null;\r\n\r\n\t}\r\n\r\n\ttoggle( override ) {\r\n\r\n\t\tif( typeof override === 'boolean' ) {\r\n\t\t\toverride ? this.activate() : this.deactivate();\r\n\t\t}\r\n\t\telse {\r\n\t\t\tthis.isActive() ? this.deactivate() : this.activate();\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Checks if the scroll view is currently active.\r\n\t */\r\n\tisActive() {\r\n\r\n\t\treturn this.active;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Renders the progress bar component.\r\n\t */\r\n\tcreateProgressBar() {\r\n\r\n\t\tthis.progressBar = document.createElement( 'div' );\r\n\t\tthis.progressBar.className = 'scrollbar';\r\n\r\n\t\tthis.progressBarInner = document.createElement( 'div' );\r\n\t\tthis.progressBarInner.className = 'scrollbar-inner';\r\n\t\tthis.progressBar.appendChild( this.progressBarInner );\r\n\r\n\t\tthis.progressBarPlayhead = document.createElement( 'div' );\r\n\t\tthis.progressBarPlayhead.className = 'scrollbar-playhead';\r\n\t\tthis.progressBarInner.appendChild( this.progressBarPlayhead );\r\n\r\n\t\tthis.viewportElement.insertBefore( this.progressBar, this.viewportElement.firstChild );\r\n\r\n\t\tconst handleDocumentMouseMove\t= ( event ) => {\r\n\r\n\t\t\tlet progress = ( event.clientY - this.progressBarInner.getBoundingClientRect().top ) / this.progressBarHeight;\r\n\t\t\tprogress = Math.max( Math.min( progress, 1 ), 0 );\r\n\r\n\t\t\tthis.viewportElement.scrollTop = progress * ( this.viewportElement.scrollHeight - this.viewportElement.offsetHeight );\r\n\r\n\t\t};\r\n\r\n\t\tconst handleDocumentMouseUp = ( event ) => {\r\n\r\n\t\t\tthis.draggingProgressBar = false;\r\n\t\t\tthis.showProgressBar();\r\n\r\n\t\t\tdocument.removeEventListener( 'mousemove', handleDocumentMouseMove );\r\n\t\t\tdocument.removeEventListener( 'mouseup', handleDocumentMouseUp );\r\n\r\n\t\t};\r\n\r\n\t\tconst handleMouseDown = ( event ) => {\r\n\r\n\t\t\tevent.preventDefault();\r\n\r\n\t\t\tthis.draggingProgressBar = true;\r\n\r\n\t\t\tdocument.addEventListener( 'mousemove', handleDocumentMouseMove );\r\n\t\t\tdocument.addEventListener( 'mouseup', handleDocumentMouseUp );\r\n\r\n\t\t\thandleDocumentMouseMove( event );\r\n\r\n\t\t};\r\n\r\n\t\tthis.progressBarInner.addEventListener( 'mousedown', handleMouseDown );\r\n\r\n\t}\r\n\r\n\tremoveProgressBar() {\r\n\r\n\t\tif( this.progressBar ) {\r\n\t\t\tthis.progressBar.remove();\r\n\t\t\tthis.progressBar = null;\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tlayout() {\r\n\r\n\t\tif( this.isActive() ) {\r\n\t\t\tthis.syncPages();\r\n\t\t\tthis.syncScrollPosition();\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Updates our pages to match the latest configuration and\r\n\t * presentation size.\r\n\t */\r\n\tsyncPages() {\r\n\r\n\t\tconst config = this.Reveal.getConfig();\r\n\r\n\t\tconst slideSize = this.Reveal.getComputedSlideSize( window.innerWidth, window.innerHeight );\r\n\t\tconst scale = this.Reveal.getScale();\r\n\t\tconst useCompactLayout = config.scrollLayout === 'compact';\r\n\r\n\t\tconst viewportHeight = this.viewportElement.offsetHeight;\r\n\t\tconst compactHeight = slideSize.height * scale;\r\n\t\tconst pageHeight = useCompactLayout ? compactHeight : viewportHeight;\r\n\r\n\t\t// The height that needs to be scrolled between scroll triggers\r\n\t\tthis.scrollTriggerHeight = useCompactLayout ? compactHeight : viewportHeight;\r\n\r\n\t\tthis.viewportElement.style.setProperty( '--page-height', pageHeight + 'px' );\r\n\t\tthis.viewportElement.style.scrollSnapType = typeof config.scrollSnap === 'string' ? `y ${config.scrollSnap}` : '';\r\n\r\n\t\t// This will hold all scroll triggers used to show/hide slides\r\n\t\tthis.slideTriggers = [];\r\n\r\n\t\tconst pageElements = Array.from( this.Reveal.getRevealElement().querySelectorAll( '.scroll-page' ) );\r\n\r\n\t\tthis.pages = pageElements.map( pageElement => {\r\n\t\t\tconst page = this.createPage({\r\n\t\t\t\tpageElement,\r\n\t\t\t\tslideElement: pageElement.querySelector( 'section' ),\r\n\t\t\t\tstickyElement: pageElement.querySelector( '.scroll-page-sticky' ),\r\n\t\t\t\tcontentElement: pageElement.querySelector( '.scroll-page-content' ),\r\n\t\t\t\tbackgroundElement: pageElement.querySelector( '.slide-background' ),\r\n\t\t\t\tautoAnimateElements: pageElement.querySelectorAll( '.scroll-auto-animate-page' ),\r\n\t\t\t\tautoAnimatePages: []\r\n\t\t\t});\r\n\r\n\t\t\tpage.pageElement.style.setProperty( '--slide-height', config.center === true ? 'auto' : slideSize.height + 'px' );\r\n\r\n\t\t\tthis.slideTriggers.push({\r\n\t\t\t\tpage: page,\r\n\t\t\t\tactivate: () => this.activatePage( page ),\r\n\t\t\t\tdeactivate: () => this.deactivatePage( page )\r\n\t\t\t});\r\n\r\n\t\t\t// Create scroll triggers that show/hide fragments\r\n\t\t\tthis.createFragmentTriggersForPage( page );\r\n\r\n\t\t\t// Create scroll triggers for triggering auto-animate steps\r\n\t\t\tif( page.autoAnimateElements.length > 0 ) {\r\n\t\t\t\tthis.createAutoAnimateTriggersForPage( page );\r\n\t\t\t}\r\n\r\n\t\t\tlet totalScrollTriggerCount = Math.max( page.scrollTriggers.length - 1, 0 );\r\n\r\n\t\t\t// Each auto-animate step may include its own scroll triggers\r\n\t\t\t// for fragments, ensure we count those as well\r\n\t\t\ttotalScrollTriggerCount += page.autoAnimatePages.reduce( ( total, page ) => {\r\n\t\t\t\treturn total + Math.max( page.scrollTriggers.length - 1, 0 );\r\n\t\t\t}, page.autoAnimatePages.length );\r\n\r\n\t\t\t// Clean up from previous renders\r\n\t\t\tpage.pageElement.querySelectorAll( '.scroll-snap-point' ).forEach( el => el.remove() );\r\n\r\n\t\t\t// Create snap points for all scroll triggers\r\n\t\t\t// - Can't be absolute in FF\r\n\t\t\t// - Can't be 0-height in Safari\r\n\t\t\t// - Can't use snap-align on parent in Safari because then\r\n\t\t\t// inner triggers won't work\r\n\t\t\tfor( let i = 0; i < totalScrollTriggerCount + 1; i++ ) {\r\n\t\t\t\tconst triggerStick = document.createElement( 'div' );\r\n\t\t\t\ttriggerStick.className = 'scroll-snap-point';\r\n\t\t\t\ttriggerStick.style.height = this.scrollTriggerHeight + 'px';\r\n\t\t\t\ttriggerStick.style.scrollSnapAlign = useCompactLayout ? 'center' : 'start';\r\n\t\t\t\tpage.pageElement.appendChild( triggerStick );\r\n\r\n\t\t\t\tif( i === 0 ) {\r\n\t\t\t\t\ttriggerStick.style.marginTop = -this.scrollTriggerHeight + 'px';\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// In the compact layout, only slides with scroll triggers cover the\r\n\t\t\t// full viewport height. This helps avoid empty gaps before or after\r\n\t\t\t// a sticky slide.\r\n\t\t\tif( useCompactLayout && page.scrollTriggers.length > 0 ) {\r\n\t\t\t\tpage.pageHeight = viewportHeight;\r\n\t\t\t\tpage.pageElement.style.setProperty( '--page-height', viewportHeight + 'px' );\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tpage.pageHeight = pageHeight;\r\n\t\t\t\tpage.pageElement.style.removeProperty( '--page-height' );\r\n\t\t\t}\r\n\r\n\t\t\t// Add scroll padding based on how many scroll triggers we have\r\n\t\t\tpage.scrollPadding = this.scrollTriggerHeight * totalScrollTriggerCount;\r\n\r\n\t\t\t// The total height including scrollable space\r\n\t\t\tpage.totalHeight = page.pageHeight + page.scrollPadding;\r\n\r\n\t\t\t// This is used to pad the height of our page in CSS\r\n\t\t\tpage.pageElement.style.setProperty( '--page-scroll-padding', page.scrollPadding + 'px' );\r\n\r\n\t\t\t// If this is a sticky page, stick it to the vertical center\r\n\t\t\tif( totalScrollTriggerCount > 0 ) {\r\n\t\t\t\tpage.stickyElement.style.position = 'sticky';\r\n\t\t\t\tpage.stickyElement.style.top = Math.max( ( viewportHeight - page.pageHeight ) / 2, 0 ) + 'px';\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tpage.stickyElement.style.position = 'relative';\r\n\t\t\t\tpage.pageElement.style.scrollSnapAlign = page.pageHeight < viewportHeight ? 'center' : 'start';\r\n\t\t\t}\r\n\r\n\t\t\treturn page;\r\n\t\t} );\r\n\r\n\t\tthis.setTriggerRanges();\r\n\r\n\t\t/*\r\n\t\tconsole.log(this.slideTriggers.map( t => {\r\n\t\t\treturn {\r\n\t\t\t\trange: `${t.range[0].toFixed(2)}-${t.range[1].toFixed(2)}`,\r\n\t\t\t\ttriggers: t.page.scrollTriggers.map( t => {\r\n\t\t\t\t\treturn `${t.range[0].toFixed(2)}-${t.range[1].toFixed(2)}`\r\n\t\t\t\t}).join( ', ' ),\r\n\t\t\t}\r\n\t\t}))\r\n\t\t*/\r\n\r\n\t\tthis.viewportElement.setAttribute( 'data-scrollbar', config.scrollProgress );\r\n\r\n\t\tif( config.scrollProgress && this.totalScrollTriggerCount > 1 ) {\r\n\t\t\t// Create the progress bar if it doesn't already exist\r\n\t\t\tif( !this.progressBar ) this.createProgressBar();\r\n\r\n\t\t\tthis.syncProgressBar();\r\n\t\t}\r\n\t\telse {\r\n\t\t\tthis.removeProgressBar();\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Calculates and sets the scroll range for all of our scroll\r\n\t * triggers.\r\n\t */\r\n\tsetTriggerRanges() {\r\n\r\n\t\t// Calculate the total number of scroll triggers\r\n\t\tthis.totalScrollTriggerCount = this.slideTriggers.reduce( ( total, trigger ) => {\r\n\t\t\treturn total + Math.max( trigger.page.scrollTriggers.length, 1 );\r\n\t\t}, 0 );\r\n\r\n\t\tlet rangeStart = 0;\r\n\r\n\t\t// Calculate the scroll range of each scroll trigger on a scale\r\n\t\t// of 0-1\r\n\t\tthis.slideTriggers.forEach( ( trigger, i ) => {\r\n\t\t\ttrigger.range = [\r\n\t\t\t\trangeStart,\r\n\t\t\t\trangeStart + Math.max( trigger.page.scrollTriggers.length, 1 ) / this.totalScrollTriggerCount\r\n\t\t\t];\r\n\r\n\t\t\tconst scrollTriggerSegmentSize = ( trigger.range[1] - trigger.range[0] ) / trigger.page.scrollTriggers.length;\r\n\t\t\t// Set the range for each inner scroll trigger\r\n\t\t\ttrigger.page.scrollTriggers.forEach( ( scrollTrigger, i ) => {\r\n\t\t\t\tscrollTrigger.range = [\r\n\t\t\t\t\trangeStart + i * scrollTriggerSegmentSize,\r\n\t\t\t\t\trangeStart + ( i + 1 ) * scrollTriggerSegmentSize\r\n\t\t\t\t];\r\n\t\t\t} );\r\n\r\n\t\t\trangeStart = trigger.range[1];\r\n\t\t} );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Creates one scroll trigger for each fragments in the given page.\r\n\t *\r\n\t * @param {*} page\r\n\t */\r\n\tcreateFragmentTriggersForPage( page, slideElement ) {\r\n\r\n\t\tslideElement = slideElement || page.slideElement;\r\n\r\n\t\t// Each fragment 'group' is an array containing one or more\r\n\t\t// fragments. Multiple fragments that appear at the same time\r\n\t\t// are part of the same group.\r\n\t\tconst fragmentGroups = this.Reveal.fragments.sort( slideElement.querySelectorAll( '.fragment' ), true );\r\n\r\n\t\t// Create scroll triggers that show/hide fragments\r\n\t\tif( fragmentGroups.length ) {\r\n\t\t\tpage.fragments = this.Reveal.fragments.sort( slideElement.querySelectorAll( '.fragment:not(.disabled)' ) );\r\n\t\t\tpage.scrollTriggers.push(\r\n\t\t\t\t// Trigger for the initial state with no fragments visible\r\n\t\t\t\t{\r\n\t\t\t\t\tactivate: () => {\r\n\t\t\t\t\t\tthis.Reveal.fragments.update( -1, page.fragments, slideElement );\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t);\r\n\r\n\t\t\t// Triggers for each fragment group\r\n\t\t\tfragmentGroups.forEach( ( fragments, i ) => {\r\n\t\t\t\tpage.scrollTriggers.push({\r\n\t\t\t\t\tactivate: () => {\r\n\t\t\t\t\t\tthis.Reveal.fragments.update( i, page.fragments, slideElement );\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t} );\r\n\t\t}\r\n\r\n\r\n\t\treturn page.scrollTriggers.length;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Creates scroll triggers for the auto-animate steps in the\r\n\t * given page.\r\n\t *\r\n\t * @param {*} page\r\n\t */\r\n\tcreateAutoAnimateTriggersForPage( page ) {\r\n\r\n\t\tif( page.autoAnimateElements.length > 0 ) {\r\n\r\n\t\t\t// Triggers for each subsequent auto-animate slide\r\n\t\t\tthis.slideTriggers.push( ...Array.from( page.autoAnimateElements ).map( ( autoAnimateElement, i ) => {\r\n\t\t\t\tlet autoAnimatePage = this.createPage({\r\n\t\t\t\t\tslideElement: autoAnimateElement.querySelector( 'section' ),\r\n\t\t\t\t\tcontentElement: autoAnimateElement,\r\n\t\t\t\t\tbackgroundElement: autoAnimateElement.querySelector( '.slide-background' )\r\n\t\t\t\t});\r\n\r\n\t\t\t\t// Create fragment scroll triggers for the auto-animate slide\r\n\t\t\t\tthis.createFragmentTriggersForPage( autoAnimatePage, autoAnimatePage.slideElement );\r\n\r\n\t\t\t\tpage.autoAnimatePages.push( autoAnimatePage );\r\n\r\n\t\t\t\t// Return our slide trigger\r\n\t\t\t\treturn {\r\n\t\t\t\t\tpage: autoAnimatePage,\r\n\t\t\t\t\tactivate: () => this.activatePage( autoAnimatePage ),\r\n\t\t\t\t\tdeactivate: () => this.deactivatePage( autoAnimatePage )\r\n\t\t\t\t};\r\n\t\t\t}));\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Helper method for creating a page definition and adding\r\n\t * required fields. A \"page\" is a slide or auto-animate step.\r\n\t */\r\n\tcreatePage( page ) {\r\n\r\n\t\tpage.scrollTriggers = [];\r\n\t\tpage.indexh = parseInt( page.slideElement.getAttribute( 'data-index-h' ), 10 );\r\n\t\tpage.indexv = parseInt( page.slideElement.getAttribute( 'data-index-v' ), 10 );\r\n\r\n\t\treturn page;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Rerenders progress bar segments so that they match the current\r\n\t * reveal.js config and size.\r\n\t */\r\n\tsyncProgressBar() {\r\n\r\n\t\tthis.progressBarInner.querySelectorAll( '.scrollbar-slide' ).forEach( slide => slide.remove() );\r\n\r\n\t\tconst scrollHeight = this.viewportElement.scrollHeight;\r\n\t\tconst viewportHeight = this.viewportElement.offsetHeight;\r\n\t\tconst viewportHeightFactor = viewportHeight / scrollHeight;\r\n\r\n\t\tthis.progressBarHeight = this.progressBarInner.offsetHeight;\r\n\t\tthis.playheadHeight = Math.max( viewportHeightFactor * this.progressBarHeight, MIN_PLAYHEAD_HEIGHT );\r\n\t\tthis.progressBarScrollableHeight = this.progressBarHeight - this.playheadHeight;\r\n\r\n\t\tconst progressSegmentHeight = viewportHeight / scrollHeight * this.progressBarHeight;\r\n\t\tconst spacing = Math.min( progressSegmentHeight / 8, MAX_PROGRESS_SPACING );\r\n\r\n\t\tthis.progressBarPlayhead.style.height = this.playheadHeight - spacing + 'px';\r\n\r\n\t\t// Don't show individual segments if they're too small\r\n\t\tif( progressSegmentHeight > MIN_PROGRESS_SEGMENT_HEIGHT ) {\r\n\r\n\t\t\tthis.slideTriggers.forEach( slideTrigger => {\r\n\r\n\t\t\t\tconst { page } = slideTrigger;\r\n\r\n\t\t\t\t// Visual representation of a slide\r\n\t\t\t\tpage.progressBarSlide = document.createElement( 'div' );\r\n\t\t\t\tpage.progressBarSlide.className = 'scrollbar-slide';\r\n\t\t\t\tpage.progressBarSlide.style.top = slideTrigger.range[0] * this.progressBarHeight + 'px';\r\n\t\t\t\tpage.progressBarSlide.style.height = ( slideTrigger.range[1] - slideTrigger.range[0] ) * this.progressBarHeight - spacing + 'px';\r\n\t\t\t\tpage.progressBarSlide.classList.toggle( 'has-triggers', page.scrollTriggers.length > 0 );\r\n\t\t\t\tthis.progressBarInner.appendChild( page.progressBarSlide );\r\n\r\n\t\t\t\t// Visual representations of each scroll trigger\r\n\t\t\t\tpage.scrollTriggerElements = page.scrollTriggers.map( ( trigger, i ) => {\r\n\r\n\t\t\t\t\tconst triggerElement = document.createElement( 'div' );\r\n\t\t\t\t\ttriggerElement.className = 'scrollbar-trigger';\r\n\t\t\t\t\ttriggerElement.style.top = ( trigger.range[0] - slideTrigger.range[0] ) * this.progressBarHeight + 'px';\r\n\t\t\t\t\ttriggerElement.style.height = ( trigger.range[1] - trigger.range[0] ) * this.progressBarHeight - spacing + 'px';\r\n\t\t\t\t\tpage.progressBarSlide.appendChild( triggerElement );\r\n\r\n\t\t\t\t\tif( i === 0 ) triggerElement.style.display = 'none';\r\n\r\n\t\t\t\t\treturn triggerElement;\r\n\r\n\t\t\t\t} );\r\n\r\n\t\t\t} );\r\n\r\n\t\t}\r\n\t\telse {\r\n\r\n\t\t\tthis.pages.forEach( page => page.progressBarSlide = null );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Reads the current scroll position and updates our active\r\n\t * trigger states accordingly.\r\n\t */\r\n\tsyncScrollPosition() {\r\n\r\n\t\tconst viewportHeight = this.viewportElement.offsetHeight;\r\n\t\tconst viewportHeightFactor = viewportHeight / this.viewportElement.scrollHeight;\r\n\r\n\t\tconst scrollTop = this.viewportElement.scrollTop;\r\n\t\tconst scrollHeight = this.viewportElement.scrollHeight - viewportHeight\r\n\t\tconst scrollProgress = Math.max( Math.min( scrollTop / scrollHeight, 1 ), 0 );\r\n\t\tconst scrollProgressMid = Math.max( Math.min( ( scrollTop + viewportHeight / 2 ) / this.viewportElement.scrollHeight, 1 ), 0 );\r\n\r\n\t\tlet activePage;\r\n\r\n\t\tthis.slideTriggers.forEach( ( trigger ) => {\r\n\t\t\tconst { page } = trigger;\r\n\r\n\t\t\tconst shouldPreload = scrollProgress >= trigger.range[0] - viewportHeightFactor*2 &&\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tscrollProgress <= trigger.range[1] + viewportHeightFactor*2;\r\n\r\n\t\t\t// Load slides that are within the preload range\r\n\t\t\tif( shouldPreload && !page.loaded ) {\r\n\t\t\t\tpage.loaded = true;\r\n\t\t\t\tthis.Reveal.slideContent.load( page.slideElement );\r\n\t\t\t}\r\n\t\t\telse if( page.loaded ) {\r\n\t\t\t\tpage.loaded = false;\r\n\t\t\t\tthis.Reveal.slideContent.unload( page.slideElement );\r\n\t\t\t}\r\n\r\n\t\t\t// If we're within this trigger range, activate it\r\n\t\t\tif( scrollProgress >= trigger.range[0] && scrollProgress <= trigger.range[1] ) {\r\n\t\t\t\tthis.activateTrigger( trigger );\r\n\t\t\t\tactivePage = trigger.page;\r\n\t\t\t}\r\n\t\t\t// .. otherwise deactivate\r\n\t\t\telse if( trigger.active ) {\r\n\t\t\t\tthis.deactivateTrigger( trigger );\r\n\t\t\t}\r\n\t\t} );\r\n\r\n\t\t// Each page can have its own scroll triggers, check if any of those\r\n\t\t// need to be activated/deactivated\r\n\t\tif( activePage ) {\r\n\t\t\tactivePage.scrollTriggers.forEach( ( trigger ) => {\r\n\t\t\t\tif( scrollProgressMid >= trigger.range[0] && scrollProgressMid <= trigger.range[1] ) {\r\n\t\t\t\t\tthis.activateTrigger( trigger );\r\n\t\t\t\t}\r\n\t\t\t\telse if( trigger.active ) {\r\n\t\t\t\t\tthis.deactivateTrigger( trigger );\r\n\t\t\t\t}\r\n\t\t\t} );\r\n\t\t}\r\n\r\n\t\t// Update our visual progress indication\r\n\t\tthis.setProgressBarValue( scrollTop / ( this.viewportElement.scrollHeight - viewportHeight ) );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Moves the progress bar playhead to the specified position.\r\n\t *\r\n\t * @param {number} progress 0-1\r\n\t */\r\n\tsetProgressBarValue( progress ) {\r\n\r\n\t\tif( this.progressBar ) {\r\n\r\n\t\t\tthis.progressBarPlayhead.style.transform = `translateY(${progress * this.progressBarScrollableHeight}px)`;\r\n\r\n\t\t\tthis.getAllPages()\r\n\t\t\t\t.filter( page => page.progressBarSlide )\r\n\t\t\t\t.forEach( ( page ) => {\r\n\t\t\t\t\tpage.progressBarSlide.classList.toggle( 'active', page.active === true );\r\n\r\n\t\t\t\t\tpage.scrollTriggers.forEach( ( trigger, i ) => {\r\n\t\t\t\t\t\tpage.scrollTriggerElements[i].classList.toggle( 'active', page.active === true && trigger.active === true );\r\n\t\t\t\t\t} );\r\n\t\t\t\t} );\r\n\r\n\t\t\tthis.showProgressBar();\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Show the progress bar and, if configured, automatically hide\r\n\t * it after a delay.\r\n\t */\r\n\tshowProgressBar() {\r\n\r\n\t\tthis.progressBar.classList.add( 'visible' );\r\n\r\n\t\tclearTimeout( this.hideProgressBarTimeout );\r\n\r\n\t\tif( this.Reveal.getConfig().scrollProgress === 'auto' && !this.draggingProgressBar ) {\r\n\r\n\t\t\tthis.hideProgressBarTimeout = setTimeout( () => {\r\n\t\t\t\tif( this.progressBar ) {\r\n\t\t\t\t\tthis.progressBar.classList.remove( 'visible' );\r\n\t\t\t\t}\r\n\t\t\t}, HIDE_SCROLLBAR_TIMEOUT );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Scroll to the previous page.\r\n\t */\r\n\tprev() {\r\n\r\n\t\tthis.viewportElement.scrollTop -= this.scrollTriggerHeight;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Scroll to the next page.\r\n\t */\r\n\tnext() {\r\n\r\n\t\tthis.viewportElement.scrollTop += this.scrollTriggerHeight;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Scrolls the given slide element into view.\r\n\t *\r\n\t * @param {HTMLElement} slideElement\r\n\t */\r\n\tscrollToSlide( slideElement ) {\r\n\r\n\t\t// If the scroll view isn't active yet, queue this action\r\n\t\tif( !this.active ) {\r\n\t\t\tthis.activatedCallbacks.push( () => this.scrollToSlide( slideElement ) );\r\n\t\t}\r\n\t\telse {\r\n\t\t\t// Find the trigger for this slide\r\n\t\t\tconst trigger = this.getScrollTriggerBySlide( slideElement );\r\n\r\n\t\t\tif( trigger ) {\r\n\t\t\t\t// Use the trigger's range to calculate the scroll position\r\n\t\t\t\tthis.viewportElement.scrollTop = trigger.range[0] * ( this.viewportElement.scrollHeight - this.viewportElement.offsetHeight );\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Persists the current scroll position to session storage\r\n\t * so that it can be restored.\r\n\t */\r\n\tstoreScrollPosition() {\r\n\r\n\t\tclearTimeout( this.storeScrollPositionTimeout );\r\n\r\n\t\tthis.storeScrollPositionTimeout = setTimeout( () => {\r\n\t\t\tsessionStorage.setItem( 'reveal-scroll-top', this.viewportElement.scrollTop );\r\n\t\t\tsessionStorage.setItem( 'reveal-scroll-origin', location.origin + location.pathname );\r\n\r\n\t\t\tthis.storeScrollPositionTimeout = null;\r\n\t\t}, 50 );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Restores the scroll position when a deck is reloader.\r\n\t */\r\n\trestoreScrollPosition() {\r\n\r\n\t\tconst scrollPosition = sessionStorage.getItem( 'reveal-scroll-top' );\r\n\t\tconst scrollOrigin = sessionStorage.getItem( 'reveal-scroll-origin' );\r\n\r\n\t\tif( scrollPosition && scrollOrigin === location.origin + location.pathname ) {\r\n\t\t\tthis.viewportElement.scrollTop = parseInt( scrollPosition, 10 );\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Activates the given page and starts its embedded content\r\n\t * if there is any.\r\n\t *\r\n\t * @param {object} page\r\n\t */\r\n\tactivatePage( page ) {\r\n\r\n\t\tif( !page.active ) {\r\n\r\n\t\t\tpage.active = true;\r\n\r\n\t\t\tconst { slideElement, backgroundElement, contentElement, indexh, indexv } = page;\r\n\r\n\t\t\tcontentElement.style.display = 'block';\r\n\r\n\t\t\tslideElement.classList.add( 'present' );\r\n\r\n\t\t\tif( backgroundElement ) {\r\n\t\t\t\tbackgroundElement.classList.add( 'present' );\r\n\t\t\t}\r\n\r\n\t\t\tthis.Reveal.setCurrentScrollPage( slideElement, indexh, indexv );\r\n\t\t\tthis.Reveal.backgrounds.bubbleSlideContrastClassToElement( slideElement, this.viewportElement );\r\n\r\n\t\t\t// If this page is part of an auto-animation there will be one\r\n\t\t\t// content element per auto-animated page. We need to show the\r\n\t\t\t// current page and hide all others.\r\n\t\t\tArray.from( contentElement.parentNode.querySelectorAll( '.scroll-page-content' ) ).forEach( sibling => {\r\n\t\t\t\tif( sibling !== contentElement ) {\r\n\t\t\t\t\tsibling.style.display = 'none';\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Deactivates the page after it has been visible.\r\n\t *\r\n\t * @param {object} page\r\n\t */\r\n\tdeactivatePage( page ) {\r\n\r\n\t\tif( page.active ) {\r\n\r\n\t\t\tpage.active = false;\r\n\t\t\tif( page.slideElement ) page.slideElement.classList.remove( 'present' );\r\n\t\t\tif( page.backgroundElement ) page.backgroundElement.classList.remove( 'present' );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tactivateTrigger( trigger ) {\r\n\r\n\t\tif( !trigger.active ) {\r\n\t\t\ttrigger.active = true;\r\n\t\t\ttrigger.activate();\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tdeactivateTrigger( trigger ) {\r\n\r\n\t\tif( trigger.active ) {\r\n\t\t\ttrigger.active = false;\r\n\r\n\t\t\tif( trigger.deactivate ) {\r\n\t\t\t\ttrigger.deactivate();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Retrieve a slide by its original h/v index (i.e. the indices the\r\n\t * slide had before being linearized).\r\n\t *\r\n\t * @param {number} h\r\n\t * @param {number} v\r\n\t * @returns {HTMLElement}\r\n\t */\r\n\tgetSlideByIndices( h, v ) {\r\n\r\n\t\tconst page = this.getAllPages().find( page => {\r\n\t\t\treturn page.indexh === h && page.indexv === v;\r\n\t\t} );\r\n\r\n\t\treturn page ? page.slideElement : null;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Retrieve a list of all scroll triggers for the given slide\r\n\t * DOM element.\r\n\t *\r\n\t * @param {HTMLElement} slide\r\n\t * @returns {Array}\r\n\t */\r\n\tgetScrollTriggerBySlide( slide ) {\r\n\r\n\t\treturn this.slideTriggers.find( trigger => trigger.page.slideElement === slide );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Get a list of all pages in the scroll view. This includes\r\n\t * both top-level slides and auto-animate steps.\r\n\t *\r\n\t * @returns {Array}\r\n\t */\r\n\tgetAllPages() {\r\n\r\n\t\treturn this.pages.flatMap( page => [page, ...(page.autoAnimatePages || [])] );\r\n\r\n\t}\r\n\r\n\tonScroll() {\r\n\r\n\t\tthis.syncScrollPosition();\r\n\t\tthis.storeScrollPosition();\r\n\r\n\t}\r\n\r\n\tget viewportElement() {\r\n\r\n\t\treturn this.Reveal.getViewportElement();\r\n\r\n\t}\r\n\r\n}\r\n","import { SLIDES_SELECTOR } from '../utils/constants.js'\r\nimport { queryAll, createStyleSheet } from '../utils/util.js'\r\n\r\n/**\r\n * Setups up our presentation for printing/exporting to PDF.\r\n */\r\nexport default class PrintView {\r\n\r\n\tconstructor( Reveal ) {\r\n\r\n\t\tthis.Reveal = Reveal;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Configures the presentation for printing to a static\r\n\t * PDF.\r\n\t */\r\n\tasync activate() {\r\n\r\n\t\tconst config = this.Reveal.getConfig();\r\n\t\tconst slides = queryAll( this.Reveal.getRevealElement(), SLIDES_SELECTOR )\r\n\r\n\t\t// Compute slide numbers now, before we start duplicating slides\r\n\t\tconst injectPageNumbers = config.slideNumber && /all|print/i.test( config.showSlideNumber );\r\n\r\n\t\tconst slideSize = this.Reveal.getComputedSlideSize( window.innerWidth, window.innerHeight );\r\n\r\n\t\t// Dimensions of the PDF pages\r\n\t\tconst pageWidth = Math.floor( slideSize.width * ( 1 + config.margin ) ),\r\n\t\t\tpageHeight = Math.floor( slideSize.height * ( 1 + config.margin ) );\r\n\r\n\t\t// Dimensions of slides within the pages\r\n\t\tconst slideWidth = slideSize.width,\r\n\t\t\tslideHeight = slideSize.height;\r\n\r\n\t\tawait new Promise( requestAnimationFrame );\r\n\r\n\t\t// Let the browser know what page size we want to print\r\n\t\tcreateStyleSheet( '@page{size:'+ pageWidth +'px '+ pageHeight +'px; margin: 0px;}' );\r\n\r\n\t\t// Limit the size of certain elements to the dimensions of the slide\r\n\t\tcreateStyleSheet( '.reveal section>img, .reveal section>video, .reveal section>iframe{max-width: '+ slideWidth +'px; max-height:'+ slideHeight +'px}' );\r\n\r\n\t\tdocument.documentElement.classList.add( 'reveal-print', 'print-pdf' );\r\n\t\tdocument.body.style.width = pageWidth + 'px';\r\n\t\tdocument.body.style.height = pageHeight + 'px';\r\n\r\n\t\tconst viewportElement = this.Reveal.getViewportElement();\r\n\t\tlet presentationBackground;\r\n\t\tif( viewportElement ) {\r\n\t\t\tconst viewportStyles = window.getComputedStyle( viewportElement );\r\n\t\t\tif( viewportStyles && viewportStyles.background ) {\r\n\t\t\t\tpresentationBackground = viewportStyles.background;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Make sure stretch elements fit on slide\r\n\t\tawait new Promise( requestAnimationFrame );\r\n\t\tthis.Reveal.layoutSlideContents( slideWidth, slideHeight );\r\n\r\n\t\t// Batch scrollHeight access to prevent layout thrashing\r\n\t\tawait new Promise( requestAnimationFrame );\r\n\r\n\t\tconst slideScrollHeights = slides.map( slide => slide.scrollHeight );\r\n\r\n\t\tconst pages = [];\r\n\t\tconst pageContainer = slides[0].parentNode;\r\n\t\tlet slideNumber = 1;\r\n\r\n\t\t// Slide and slide background layout\r\n\t\tslides.forEach( function( slide, index ) {\r\n\r\n\t\t\t// Vertical stacks are not centred since their section\r\n\t\t\t// children will be\r\n\t\t\tif( slide.classList.contains( 'stack' ) === false ) {\r\n\t\t\t\t// Center the slide inside of the page, giving the slide some margin\r\n\t\t\t\tlet left = ( pageWidth - slideWidth ) / 2;\r\n\t\t\t\tlet top = ( pageHeight - slideHeight ) / 2;\r\n\r\n\t\t\t\tconst contentHeight = slideScrollHeights[ index ];\r\n\t\t\t\tlet numberOfPages = Math.max( Math.ceil( contentHeight / pageHeight ), 1 );\r\n\r\n\t\t\t\t// Adhere to configured pages per slide limit\r\n\t\t\t\tnumberOfPages = Math.min( numberOfPages, config.pdfMaxPagesPerSlide );\r\n\r\n\t\t\t\t// Center slides vertically\r\n\t\t\t\tif( numberOfPages === 1 && config.center || slide.classList.contains( 'center' ) ) {\r\n\t\t\t\t\ttop = Math.max( ( pageHeight - contentHeight ) / 2, 0 );\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Wrap the slide in a page element and hide its overflow\r\n\t\t\t\t// so that no page ever flows onto another\r\n\t\t\t\tconst page = document.createElement( 'div' );\r\n\t\t\t\tpages.push( page );\r\n\r\n\t\t\t\tpage.className = 'pdf-page';\r\n\t\t\t\tpage.style.height = ( ( pageHeight + config.pdfPageHeightOffset ) * numberOfPages ) + 'px';\r\n\r\n\t\t\t\t// Copy the presentation-wide background to each individual\r\n\t\t\t\t// page when printing\r\n\t\t\t\tif( presentationBackground ) {\r\n\t\t\t\t\tpage.style.background = presentationBackground;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tpage.appendChild( slide );\r\n\r\n\t\t\t\t// Position the slide inside of the page\r\n\t\t\t\tslide.style.left = left + 'px';\r\n\t\t\t\tslide.style.top = top + 'px';\r\n\t\t\t\tslide.style.width = slideWidth + 'px';\r\n\r\n\t\t\t\tthis.Reveal.slideContent.layout( slide );\r\n\r\n\t\t\t\tif( slide.slideBackgroundElement ) {\r\n\t\t\t\t\tpage.insertBefore( slide.slideBackgroundElement, slide );\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Inject notes if `showNotes` is enabled\r\n\t\t\t\tif( config.showNotes ) {\r\n\r\n\t\t\t\t\t// Are there notes for this slide?\r\n\t\t\t\t\tconst notes = this.Reveal.getSlideNotes( slide );\r\n\t\t\t\t\tif( notes ) {\r\n\r\n\t\t\t\t\t\tconst notesSpacing = 8;\r\n\t\t\t\t\t\tconst notesLayout = typeof config.showNotes === 'string' ? config.showNotes : 'inline';\r\n\t\t\t\t\t\tconst notesElement = document.createElement( 'div' );\r\n\t\t\t\t\t\tnotesElement.classList.add( 'speaker-notes' );\r\n\t\t\t\t\t\tnotesElement.classList.add( 'speaker-notes-pdf' );\r\n\t\t\t\t\t\tnotesElement.setAttribute( 'data-layout', notesLayout );\r\n\t\t\t\t\t\tnotesElement.innerHTML = notes;\r\n\r\n\t\t\t\t\t\tif( notesLayout === 'separate-page' ) {\r\n\t\t\t\t\t\t\tpages.push( notesElement );\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\tnotesElement.style.left = notesSpacing + 'px';\r\n\t\t\t\t\t\t\tnotesElement.style.bottom = notesSpacing + 'px';\r\n\t\t\t\t\t\t\tnotesElement.style.width = ( pageWidth - notesSpacing*2 ) + 'px';\r\n\t\t\t\t\t\t\tpage.appendChild( notesElement );\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Inject page numbers if `slideNumbers` are enabled\r\n\t\t\t\tif( injectPageNumbers ) {\r\n\t\t\t\t\tconst numberElement = document.createElement( 'div' );\r\n\t\t\t\t\tnumberElement.classList.add( 'slide-number' );\r\n\t\t\t\t\tnumberElement.classList.add( 'slide-number-pdf' );\r\n\t\t\t\t\tnumberElement.innerHTML = slideNumber++;\r\n\t\t\t\t\tpage.appendChild( numberElement );\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Copy page and show fragments one after another\r\n\t\t\t\tif( config.pdfSeparateFragments ) {\r\n\r\n\t\t\t\t\t// Each fragment 'group' is an array containing one or more\r\n\t\t\t\t\t// fragments. Multiple fragments that appear at the same time\r\n\t\t\t\t\t// are part of the same group.\r\n\t\t\t\t\tconst fragmentGroups = this.Reveal.fragments.sort( page.querySelectorAll( '.fragment' ), true );\r\n\r\n\t\t\t\t\tlet previousFragmentStep;\r\n\r\n\t\t\t\t\tfragmentGroups.forEach( function( fragments, index ) {\r\n\r\n\t\t\t\t\t\t// Remove 'current-fragment' from the previous group\r\n\t\t\t\t\t\tif( previousFragmentStep ) {\r\n\t\t\t\t\t\t\tpreviousFragmentStep.forEach( function( fragment ) {\r\n\t\t\t\t\t\t\t\tfragment.classList.remove( 'current-fragment' );\r\n\t\t\t\t\t\t\t} );\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// Show the fragments for the current index\r\n\t\t\t\t\t\tfragments.forEach( function( fragment ) {\r\n\t\t\t\t\t\t\tfragment.classList.add( 'visible', 'current-fragment' );\r\n\t\t\t\t\t\t}, this );\r\n\r\n\t\t\t\t\t\t// Create a separate page for the current fragment state\r\n\t\t\t\t\t\tconst clonedPage = page.cloneNode( true );\r\n\r\n\t\t\t\t\t\t// Inject unique page numbers for fragments\r\n\t\t\t\t\t\tif( injectPageNumbers ) {\r\n\t\t\t\t\t\t\tconst numberElement = clonedPage.querySelector( '.slide-number-pdf' );\r\n\t\t\t\t\t\t\tconst fragmentNumber = index + 1;\r\n\t\t\t\t\t\t\tnumberElement.innerHTML += '.' + fragmentNumber;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tpages.push( clonedPage );\r\n\r\n\t\t\t\t\t\tpreviousFragmentStep = fragments;\r\n\r\n\t\t\t\t\t}, this );\r\n\r\n\t\t\t\t\t// Reset the first/original page so that all fragments are hidden\r\n\t\t\t\t\tfragmentGroups.forEach( function( fragments ) {\r\n\t\t\t\t\t\tfragments.forEach( function( fragment ) {\r\n\t\t\t\t\t\t\tfragment.classList.remove( 'visible', 'current-fragment' );\r\n\t\t\t\t\t\t} );\r\n\t\t\t\t\t} );\r\n\r\n\t\t\t\t}\r\n\t\t\t\t// Show all fragments\r\n\t\t\t\telse {\r\n\t\t\t\t\tqueryAll( page, '.fragment:not(.fade-out)' ).forEach( function( fragment ) {\r\n\t\t\t\t\t\tfragment.classList.add( 'visible' );\r\n\t\t\t\t\t} );\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}, this );\r\n\r\n\t\tawait new Promise( requestAnimationFrame );\r\n\r\n\t\tpages.forEach( page => pageContainer.appendChild( page ) );\r\n\r\n\t\t// Re-run JS-based content layout after the slide is added to page DOM\r\n\t\tthis.Reveal.slideContent.layout( this.Reveal.getSlidesElement() );\r\n\r\n\t\t// Notify subscribers that the PDF layout is good to go\r\n\t\tthis.Reveal.dispatchEvent({ type: 'pdf-ready' });\r\n\r\n\t\tviewportElement.classList.remove( 'loading-scroll-mode' );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Checks if the print mode is/should be activated.\r\n\t */\r\n\tisActive() {\r\n\r\n\t\treturn this.Reveal.getConfig().view === 'print';\r\n\r\n\t}\r\n\r\n}","import { extend, queryAll } from '../utils/util.js'\r\n\r\n/**\r\n * Handles sorting and navigation of slide fragments.\r\n * Fragments are elements within a slide that are\r\n * revealed/animated incrementally.\r\n */\r\nexport default class Fragments {\r\n\r\n\tconstructor( Reveal ) {\r\n\r\n\t\tthis.Reveal = Reveal;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Called when the reveal.js config is updated.\r\n\t */\r\n\tconfigure( config, oldConfig ) {\r\n\r\n\t\tif( config.fragments === false ) {\r\n\t\t\tthis.disable();\r\n\t\t}\r\n\t\telse if( oldConfig.fragments === false ) {\r\n\t\t\tthis.enable();\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * If fragments are disabled in the deck, they should all be\r\n\t * visible rather than stepped through.\r\n\t */\r\n\tdisable() {\r\n\r\n\t\tqueryAll( this.Reveal.getSlidesElement(), '.fragment' ).forEach( element => {\r\n\t\t\telement.classList.add( 'visible' );\r\n\t\t\telement.classList.remove( 'current-fragment' );\r\n\t\t} );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Reverse of #disable(). Only called if fragments have\r\n\t * previously been disabled.\r\n\t */\r\n\tenable() {\r\n\r\n\t\tqueryAll( this.Reveal.getSlidesElement(), '.fragment' ).forEach( element => {\r\n\t\t\telement.classList.remove( 'visible' );\r\n\t\t\telement.classList.remove( 'current-fragment' );\r\n\t\t} );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Returns an object describing the available fragment\r\n\t * directions.\r\n\t *\r\n\t * @return {{prev: boolean, next: boolean}}\r\n\t */\r\n\tavailableRoutes() {\r\n\r\n\t\tlet currentSlide = this.Reveal.getCurrentSlide();\r\n\t\tif( currentSlide && this.Reveal.getConfig().fragments ) {\r\n\t\t\tlet fragments = currentSlide.querySelectorAll( '.fragment:not(.disabled)' );\r\n\t\t\tlet hiddenFragments = currentSlide.querySelectorAll( '.fragment:not(.disabled):not(.visible)' );\r\n\r\n\t\t\treturn {\r\n\t\t\t\tprev: fragments.length - hiddenFragments.length > 0,\r\n\t\t\t\tnext: !!hiddenFragments.length\r\n\t\t\t};\r\n\t\t}\r\n\t\telse {\r\n\t\t\treturn { prev: false, next: false };\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Return a sorted fragments list, ordered by an increasing\r\n\t * \"data-fragment-index\" attribute.\r\n\t *\r\n\t * Fragments will be revealed in the order that they are returned by\r\n\t * this function, so you can use the index attributes to control the\r\n\t * order of fragment appearance.\r\n\t *\r\n\t * To maintain a sensible default fragment order, fragments are presumed\r\n\t * to be passed in document order. This function adds a \"fragment-index\"\r\n\t * attribute to each node if such an attribute is not already present,\r\n\t * and sets that attribute to an integer value which is the position of\r\n\t * the fragment within the fragments list.\r\n\t *\r\n\t * @param {object[]|*} fragments\r\n\t * @param {boolean} grouped If true the returned array will contain\r\n\t * nested arrays for all fragments with the same index\r\n\t * @return {object[]} sorted Sorted array of fragments\r\n\t */\r\n\tsort( fragments, grouped = false ) {\r\n\r\n\t\tfragments = Array.from( fragments );\r\n\r\n\t\tlet ordered = [],\r\n\t\t\tunordered = [],\r\n\t\t\tsorted = [];\r\n\r\n\t\t// Group ordered and unordered elements\r\n\t\tfragments.forEach( fragment => {\r\n\t\t\tif( fragment.hasAttribute( 'data-fragment-index' ) ) {\r\n\t\t\t\tlet index = parseInt( fragment.getAttribute( 'data-fragment-index' ), 10 );\r\n\r\n\t\t\t\tif( !ordered[index] ) {\r\n\t\t\t\t\tordered[index] = [];\r\n\t\t\t\t}\r\n\r\n\t\t\t\tordered[index].push( fragment );\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tunordered.push( [ fragment ] );\r\n\t\t\t}\r\n\t\t} );\r\n\r\n\t\t// Append fragments without explicit indices in their\r\n\t\t// DOM order\r\n\t\tordered = ordered.concat( unordered );\r\n\r\n\t\t// Manually count the index up per group to ensure there\r\n\t\t// are no gaps\r\n\t\tlet index = 0;\r\n\r\n\t\t// Push all fragments in their sorted order to an array,\r\n\t\t// this flattens the groups\r\n\t\tordered.forEach( group => {\r\n\t\t\tgroup.forEach( fragment => {\r\n\t\t\t\tsorted.push( fragment );\r\n\t\t\t\tfragment.setAttribute( 'data-fragment-index', index );\r\n\t\t\t} );\r\n\r\n\t\t\tindex ++;\r\n\t\t} );\r\n\r\n\t\treturn grouped === true ? ordered : sorted;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Sorts and formats all of fragments in the\r\n\t * presentation.\r\n\t */\r\n\tsortAll() {\r\n\r\n\t\tthis.Reveal.getHorizontalSlides().forEach( horizontalSlide => {\r\n\r\n\t\t\tlet verticalSlides = queryAll( horizontalSlide, 'section' );\r\n\t\t\tverticalSlides.forEach( ( verticalSlide, y ) => {\r\n\r\n\t\t\t\tthis.sort( verticalSlide.querySelectorAll( '.fragment' ) );\r\n\r\n\t\t\t}, this );\r\n\r\n\t\t\tif( verticalSlides.length === 0 ) this.sort( horizontalSlide.querySelectorAll( '.fragment' ) );\r\n\r\n\t\t} );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Refreshes the fragments on the current slide so that they\r\n\t * have the appropriate classes (.visible + .current-fragment).\r\n\t *\r\n\t * @param {number} [index] The index of the current fragment\r\n\t * @param {array} [fragments] Array containing all fragments\r\n\t * in the current slide\r\n\t *\r\n\t * @return {{shown: array, hidden: array}}\r\n\t */\r\n\tupdate( index, fragments, slide = this.Reveal.getCurrentSlide() ) {\r\n\r\n\t\tlet changedFragments = {\r\n\t\t\tshown: [],\r\n\t\t\thidden: []\r\n\t\t};\r\n\r\n\t\tif( slide && this.Reveal.getConfig().fragments ) {\r\n\r\n\t\t\tfragments = fragments || this.sort( slide.querySelectorAll( '.fragment' ) );\r\n\r\n\t\t\tif( fragments.length ) {\r\n\r\n\t\t\t\tlet maxIndex = 0;\r\n\r\n\t\t\t\tif( typeof index !== 'number' ) {\r\n\t\t\t\t\tlet currentFragment = this.sort( slide.querySelectorAll( '.fragment.visible' ) ).pop();\r\n\t\t\t\t\tif( currentFragment ) {\r\n\t\t\t\t\t\tindex = parseInt( currentFragment.getAttribute( 'data-fragment-index' ) || 0, 10 );\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tArray.from( fragments ).forEach( ( el, i ) => {\r\n\r\n\t\t\t\t\tif( el.hasAttribute( 'data-fragment-index' ) ) {\r\n\t\t\t\t\t\ti = parseInt( el.getAttribute( 'data-fragment-index' ), 10 );\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tmaxIndex = Math.max( maxIndex, i );\r\n\r\n\t\t\t\t\t// Visible fragments\r\n\t\t\t\t\tif( i <= index ) {\r\n\t\t\t\t\t\tlet wasVisible = el.classList.contains( 'visible' )\r\n\t\t\t\t\t\tel.classList.add( 'visible' );\r\n\t\t\t\t\t\tel.classList.remove( 'current-fragment' );\r\n\r\n\t\t\t\t\t\tif( i === index ) {\r\n\t\t\t\t\t\t\t// Announce the fragments one by one to the Screen Reader\r\n\t\t\t\t\t\t\tthis.Reveal.announceStatus( this.Reveal.getStatusText( el ) );\r\n\r\n\t\t\t\t\t\t\tel.classList.add( 'current-fragment' );\r\n\t\t\t\t\t\t\tthis.Reveal.slideContent.startEmbeddedContent( el );\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif( !wasVisible ) {\r\n\t\t\t\t\t\t\tchangedFragments.shown.push( el )\r\n\t\t\t\t\t\t\tthis.Reveal.dispatchEvent({\r\n\t\t\t\t\t\t\t\ttarget: el,\r\n\t\t\t\t\t\t\t\ttype: 'visible',\r\n\t\t\t\t\t\t\t\tbubbles: false\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\t// Hidden fragments\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tlet wasVisible = el.classList.contains( 'visible' )\r\n\t\t\t\t\t\tel.classList.remove( 'visible' );\r\n\t\t\t\t\t\tel.classList.remove( 'current-fragment' );\r\n\r\n\t\t\t\t\t\tif( wasVisible ) {\r\n\t\t\t\t\t\t\tthis.Reveal.slideContent.stopEmbeddedContent( el );\r\n\t\t\t\t\t\t\tchangedFragments.hidden.push( el );\r\n\t\t\t\t\t\t\tthis.Reveal.dispatchEvent({\r\n\t\t\t\t\t\t\t\ttarget: el,\r\n\t\t\t\t\t\t\t\ttype: 'hidden',\r\n\t\t\t\t\t\t\t\tbubbles: false\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t} );\r\n\r\n\t\t\t\t// Write the current fragment index to the slide
.\r\n\t\t\t\t// This can be used by end users to apply styles based on\r\n\t\t\t\t// the current fragment index.\r\n\t\t\t\tindex = typeof index === 'number' ? index : -1;\r\n\t\t\t\tindex = Math.max( Math.min( index, maxIndex ), -1 );\r\n\t\t\t\tslide.setAttribute( 'data-fragment', index );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn changedFragments;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Formats the fragments on the given slide so that they have\r\n\t * valid indices. Call this if fragments are changed in the DOM\r\n\t * after reveal.js has already initialized.\r\n\t *\r\n\t * @param {HTMLElement} slide\r\n\t * @return {Array} a list of the HTML fragments that were synced\r\n\t */\r\n\tsync( slide = this.Reveal.getCurrentSlide() ) {\r\n\r\n\t\treturn this.sort( slide.querySelectorAll( '.fragment' ) );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Navigate to the specified slide fragment.\r\n\t *\r\n\t * @param {?number} index The index of the fragment that\r\n\t * should be shown, -1 means all are invisible\r\n\t * @param {number} offset Integer offset to apply to the\r\n\t * fragment index\r\n\t *\r\n\t * @return {boolean} true if a change was made in any\r\n\t * fragments visibility as part of this call\r\n\t */\r\n\tgoto( index, offset = 0 ) {\r\n\r\n\t\tlet currentSlide = this.Reveal.getCurrentSlide();\r\n\t\tif( currentSlide && this.Reveal.getConfig().fragments ) {\r\n\r\n\t\t\tlet fragments = this.sort( currentSlide.querySelectorAll( '.fragment:not(.disabled)' ) );\r\n\t\t\tif( fragments.length ) {\r\n\r\n\t\t\t\t// If no index is specified, find the current\r\n\t\t\t\tif( typeof index !== 'number' ) {\r\n\t\t\t\t\tlet lastVisibleFragment = this.sort( currentSlide.querySelectorAll( '.fragment:not(.disabled).visible' ) ).pop();\r\n\r\n\t\t\t\t\tif( lastVisibleFragment ) {\r\n\t\t\t\t\t\tindex = parseInt( lastVisibleFragment.getAttribute( 'data-fragment-index' ) || 0, 10 );\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tindex = -1;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Apply the offset if there is one\r\n\t\t\t\tindex += offset;\r\n\r\n\t\t\t\tlet changedFragments = this.update( index, fragments );\r\n\r\n\t\t\t\tif( changedFragments.hidden.length ) {\r\n\t\t\t\t\tthis.Reveal.dispatchEvent({\r\n\t\t\t\t\t\ttype: 'fragmenthidden',\r\n\t\t\t\t\t\tdata: {\r\n\t\t\t\t\t\t\tfragment: changedFragments.hidden[0],\r\n\t\t\t\t\t\t\tfragments: changedFragments.hidden\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif( changedFragments.shown.length ) {\r\n\t\t\t\t\tthis.Reveal.dispatchEvent({\r\n\t\t\t\t\t\ttype: 'fragmentshown',\r\n\t\t\t\t\t\tdata: {\r\n\t\t\t\t\t\t\tfragment: changedFragments.shown[0],\r\n\t\t\t\t\t\t\tfragments: changedFragments.shown\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis.Reveal.controls.update();\r\n\t\t\t\tthis.Reveal.progress.update();\r\n\r\n\t\t\t\tif( this.Reveal.getConfig().fragmentInURL ) {\r\n\t\t\t\t\tthis.Reveal.location.writeURL();\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn !!( changedFragments.shown.length || changedFragments.hidden.length );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Navigate to the next slide fragment.\r\n\t *\r\n\t * @return {boolean} true if there was a next fragment,\r\n\t * false otherwise\r\n\t */\r\n\tnext() {\r\n\r\n\t\treturn this.goto( null, 1 );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Navigate to the previous slide fragment.\r\n\t *\r\n\t * @return {boolean} true if there was a previous fragment,\r\n\t * false otherwise\r\n\t */\r\n\tprev() {\r\n\r\n\t\treturn this.goto( null, -1 );\r\n\r\n\t}\r\n\r\n}","import { SLIDES_SELECTOR } from '../utils/constants.js'\r\nimport { extend, queryAll, transformElement } from '../utils/util.js'\r\n\r\n/**\r\n * Handles all logic related to the overview mode\r\n * (birds-eye view of all slides).\r\n */\r\nexport default class Overview {\r\n\r\n\tconstructor( Reveal ) {\r\n\r\n\t\tthis.Reveal = Reveal;\r\n\r\n\t\tthis.active = false;\r\n\r\n\t\tthis.onSlideClicked = this.onSlideClicked.bind( this );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Displays the overview of slides (quick nav) by scaling\r\n\t * down and arranging all slide elements.\r\n\t */\r\n\tactivate() {\r\n\r\n\t\t// Only proceed if enabled in config\r\n\t\tif( this.Reveal.getConfig().overview && !this.Reveal.isScrollView() && !this.isActive() ) {\r\n\r\n\t\t\tthis.active = true;\r\n\r\n\t\t\tthis.Reveal.getRevealElement().classList.add( 'overview' );\r\n\r\n\t\t\t// Don't auto-slide while in overview mode\r\n\t\t\tthis.Reveal.cancelAutoSlide();\r\n\r\n\t\t\t// Move the backgrounds element into the slide container to\r\n\t\t\t// that the same scaling is applied\r\n\t\t\tthis.Reveal.getSlidesElement().appendChild( this.Reveal.getBackgroundsElement() );\r\n\r\n\t\t\t// Clicking on an overview slide navigates to it\r\n\t\t\tqueryAll( this.Reveal.getRevealElement(), SLIDES_SELECTOR ).forEach( slide => {\r\n\t\t\t\tif( !slide.classList.contains( 'stack' ) ) {\r\n\t\t\t\t\tslide.addEventListener( 'click', this.onSlideClicked, true );\r\n\t\t\t\t}\r\n\t\t\t} );\r\n\r\n\t\t\t// Calculate slide sizes\r\n\t\t\tconst margin = 70;\r\n\t\t\tconst slideSize = this.Reveal.getComputedSlideSize();\r\n\t\t\tthis.overviewSlideWidth = slideSize.width + margin;\r\n\t\t\tthis.overviewSlideHeight = slideSize.height + margin;\r\n\r\n\t\t\t// Reverse in RTL mode\r\n\t\t\tif( this.Reveal.getConfig().rtl ) {\r\n\t\t\t\tthis.overviewSlideWidth = -this.overviewSlideWidth;\r\n\t\t\t}\r\n\r\n\t\t\tthis.Reveal.updateSlidesVisibility();\r\n\r\n\t\t\tthis.layout();\r\n\t\t\tthis.update();\r\n\r\n\t\t\tthis.Reveal.layout();\r\n\r\n\t\t\tconst indices = this.Reveal.getIndices();\r\n\r\n\t\t\t// Notify observers of the overview showing\r\n\t\t\tthis.Reveal.dispatchEvent({\r\n\t\t\t\ttype: 'overviewshown',\r\n\t\t\t\tdata: {\r\n\t\t\t\t\t'indexh': indices.h,\r\n\t\t\t\t\t'indexv': indices.v,\r\n\t\t\t\t\t'currentSlide': this.Reveal.getCurrentSlide()\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Uses CSS transforms to position all slides in a grid for\r\n\t * display inside of the overview mode.\r\n\t */\r\n\tlayout() {\r\n\r\n\t\t// Layout slides\r\n\t\tthis.Reveal.getHorizontalSlides().forEach( ( hslide, h ) => {\r\n\t\t\thslide.setAttribute( 'data-index-h', h );\r\n\t\t\ttransformElement( hslide, 'translate3d(' + ( h * this.overviewSlideWidth ) + 'px, 0, 0)' );\r\n\r\n\t\t\tif( hslide.classList.contains( 'stack' ) ) {\r\n\r\n\t\t\t\tqueryAll( hslide, 'section' ).forEach( ( vslide, v ) => {\r\n\t\t\t\t\tvslide.setAttribute( 'data-index-h', h );\r\n\t\t\t\t\tvslide.setAttribute( 'data-index-v', v );\r\n\r\n\t\t\t\t\ttransformElement( vslide, 'translate3d(0, ' + ( v * this.overviewSlideHeight ) + 'px, 0)' );\r\n\t\t\t\t} );\r\n\r\n\t\t\t}\r\n\t\t} );\r\n\r\n\t\t// Layout slide backgrounds\r\n\t\tArray.from( this.Reveal.getBackgroundsElement().childNodes ).forEach( ( hbackground, h ) => {\r\n\t\t\ttransformElement( hbackground, 'translate3d(' + ( h * this.overviewSlideWidth ) + 'px, 0, 0)' );\r\n\r\n\t\t\tqueryAll( hbackground, '.slide-background' ).forEach( ( vbackground, v ) => {\r\n\t\t\t\ttransformElement( vbackground, 'translate3d(0, ' + ( v * this.overviewSlideHeight ) + 'px, 0)' );\r\n\t\t\t} );\r\n\t\t} );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Moves the overview viewport to the current slides.\r\n\t * Called each time the current slide changes.\r\n\t */\r\n\tupdate() {\r\n\r\n\t\tconst vmin = Math.min( window.innerWidth, window.innerHeight );\r\n\t\tconst scale = Math.max( vmin / 5, 150 ) / vmin;\r\n\t\tconst indices = this.Reveal.getIndices();\r\n\r\n\t\tthis.Reveal.transformSlides( {\r\n\t\t\toverview: [\r\n\t\t\t\t'scale('+ scale +')',\r\n\t\t\t\t'translateX('+ ( -indices.h * this.overviewSlideWidth ) +'px)',\r\n\t\t\t\t'translateY('+ ( -indices.v * this.overviewSlideHeight ) +'px)'\r\n\t\t\t].join( ' ' )\r\n\t\t} );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Exits the slide overview and enters the currently\r\n\t * active slide.\r\n\t */\r\n\tdeactivate() {\r\n\r\n\t\t// Only proceed if enabled in config\r\n\t\tif( this.Reveal.getConfig().overview ) {\r\n\r\n\t\t\tthis.active = false;\r\n\r\n\t\t\tthis.Reveal.getRevealElement().classList.remove( 'overview' );\r\n\r\n\t\t\t// Temporarily add a class so that transitions can do different things\r\n\t\t\t// depending on whether they are exiting/entering overview, or just\r\n\t\t\t// moving from slide to slide\r\n\t\t\tthis.Reveal.getRevealElement().classList.add( 'overview-deactivating' );\r\n\r\n\t\t\tsetTimeout( () => {\r\n\t\t\t\tthis.Reveal.getRevealElement().classList.remove( 'overview-deactivating' );\r\n\t\t\t}, 1 );\r\n\r\n\t\t\t// Move the background element back out\r\n\t\t\tthis.Reveal.getRevealElement().appendChild( this.Reveal.getBackgroundsElement() );\r\n\r\n\t\t\t// Clean up changes made to slides\r\n\t\t\tqueryAll( this.Reveal.getRevealElement(), SLIDES_SELECTOR ).forEach( slide => {\r\n\t\t\t\ttransformElement( slide, '' );\r\n\r\n\t\t\t\tslide.removeEventListener( 'click', this.onSlideClicked, true );\r\n\t\t\t} );\r\n\r\n\t\t\t// Clean up changes made to backgrounds\r\n\t\t\tqueryAll( this.Reveal.getBackgroundsElement(), '.slide-background' ).forEach( background => {\r\n\t\t\t\ttransformElement( background, '' );\r\n\t\t\t} );\r\n\r\n\t\t\tthis.Reveal.transformSlides( { overview: '' } );\r\n\r\n\t\t\tconst indices = this.Reveal.getIndices();\r\n\r\n\t\t\tthis.Reveal.slide( indices.h, indices.v );\r\n\t\t\tthis.Reveal.layout();\r\n\t\t\tthis.Reveal.cueAutoSlide();\r\n\r\n\t\t\t// Notify observers of the overview hiding\r\n\t\t\tthis.Reveal.dispatchEvent({\r\n\t\t\t\ttype: 'overviewhidden',\r\n\t\t\t\tdata: {\r\n\t\t\t\t\t'indexh': indices.h,\r\n\t\t\t\t\t'indexv': indices.v,\r\n\t\t\t\t\t'currentSlide': this.Reveal.getCurrentSlide()\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Toggles the slide overview mode on and off.\r\n\t *\r\n\t * @param {Boolean} [override] Flag which overrides the\r\n\t * toggle logic and forcibly sets the desired state. True means\r\n\t * overview is open, false means it's closed.\r\n\t */\r\n\ttoggle( override ) {\r\n\r\n\t\tif( typeof override === 'boolean' ) {\r\n\t\t\toverride ? this.activate() : this.deactivate();\r\n\t\t}\r\n\t\telse {\r\n\t\t\tthis.isActive() ? this.deactivate() : this.activate();\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Checks if the overview is currently active.\r\n\t *\r\n\t * @return {Boolean} true if the overview is active,\r\n\t * false otherwise\r\n\t */\r\n\tisActive() {\r\n\r\n\t\treturn this.active;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Invoked when a slide is and we're in the overview.\r\n\t *\r\n\t * @param {object} event\r\n\t */\r\n\tonSlideClicked( event ) {\r\n\r\n\t\tif( this.isActive() ) {\r\n\t\t\tevent.preventDefault();\r\n\r\n\t\t\tlet element = event.target;\r\n\r\n\t\t\twhile( element && !element.nodeName.match( /section/gi ) ) {\r\n\t\t\t\telement = element.parentNode;\r\n\t\t\t}\r\n\r\n\t\t\tif( element && !element.classList.contains( 'disabled' ) ) {\r\n\r\n\t\t\t\tthis.deactivate();\r\n\r\n\t\t\t\tif( element.nodeName.match( /section/gi ) ) {\r\n\t\t\t\t\tlet h = parseInt( element.getAttribute( 'data-index-h' ), 10 ),\r\n\t\t\t\t\t\tv = parseInt( element.getAttribute( 'data-index-v' ), 10 );\r\n\r\n\t\t\t\t\tthis.Reveal.slide( h, v );\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t}\r\n\r\n}","import { enterFullscreen } from '../utils/util.js'\r\n\r\n/**\r\n * Handles all reveal.js keyboard interactions.\r\n */\r\nexport default class Keyboard {\r\n\r\n\tconstructor( Reveal ) {\r\n\r\n\t\tthis.Reveal = Reveal;\r\n\r\n\t\t// A key:value map of keyboard keys and descriptions of\r\n\t\t// the actions they trigger\r\n\t\tthis.shortcuts = {};\r\n\r\n\t\t// Holds custom key code mappings\r\n\t\tthis.bindings = {};\r\n\r\n\t\tthis.onDocumentKeyDown = this.onDocumentKeyDown.bind( this );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Called when the reveal.js config is updated.\r\n\t */\r\n\tconfigure( config, oldConfig ) {\r\n\r\n\t\tif( config.navigationMode === 'linear' ) {\r\n\t\t\tthis.shortcuts['→ , ↓ , SPACE , N , L , J'] = 'Next slide';\r\n\t\t\tthis.shortcuts['← , ↑ , P , H , K'] = 'Previous slide';\r\n\t\t}\r\n\t\telse {\r\n\t\t\tthis.shortcuts['N , SPACE'] = 'Next slide';\r\n\t\t\tthis.shortcuts['P , Shift SPACE'] = 'Previous slide';\r\n\t\t\tthis.shortcuts['← , H'] = 'Navigate left';\r\n\t\t\tthis.shortcuts['→ , L'] = 'Navigate right';\r\n\t\t\tthis.shortcuts['↑ , K'] = 'Navigate up';\r\n\t\t\tthis.shortcuts['↓ , J'] = 'Navigate down';\r\n\t\t}\r\n\r\n\t\tthis.shortcuts['Alt + ←/↑/→/↓'] = 'Navigate without fragments';\r\n\t\tthis.shortcuts['Shift + ←/↑/→/↓'] = 'Jump to first/last slide';\r\n\t\tthis.shortcuts['B , .'] = 'Pause';\r\n\t\tthis.shortcuts['F'] = 'Fullscreen';\r\n\t\tthis.shortcuts['G'] = 'Jump to slide';\r\n\t\tthis.shortcuts['ESC, O'] = 'Slide overview';\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Starts listening for keyboard events.\r\n\t */\r\n\tbind() {\r\n\r\n\t\tdocument.addEventListener( 'keydown', this.onDocumentKeyDown, false );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Stops listening for keyboard events.\r\n\t */\r\n\tunbind() {\r\n\r\n\t\tdocument.removeEventListener( 'keydown', this.onDocumentKeyDown, false );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Add a custom key binding with optional description to\r\n\t * be added to the help screen.\r\n\t */\r\n\taddKeyBinding( binding, callback ) {\r\n\r\n\t\tif( typeof binding === 'object' && binding.keyCode ) {\r\n\t\t\tthis.bindings[binding.keyCode] = {\r\n\t\t\t\tcallback: callback,\r\n\t\t\t\tkey: binding.key,\r\n\t\t\t\tdescription: binding.description\r\n\t\t\t};\r\n\t\t}\r\n\t\telse {\r\n\t\t\tthis.bindings[binding] = {\r\n\t\t\t\tcallback: callback,\r\n\t\t\t\tkey: null,\r\n\t\t\t\tdescription: null\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Removes the specified custom key binding.\r\n\t */\r\n\tremoveKeyBinding( keyCode ) {\r\n\r\n\t\tdelete this.bindings[keyCode];\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Programmatically triggers a keyboard event\r\n\t *\r\n\t * @param {int} keyCode\r\n\t */\r\n\ttriggerKey( keyCode ) {\r\n\r\n\t\tthis.onDocumentKeyDown( { keyCode } );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Registers a new shortcut to include in the help overlay\r\n\t *\r\n\t * @param {String} key\r\n\t * @param {String} value\r\n\t */\r\n\tregisterKeyboardShortcut( key, value ) {\r\n\r\n\t\tthis.shortcuts[key] = value;\r\n\r\n\t}\r\n\r\n\tgetShortcuts() {\r\n\r\n\t\treturn this.shortcuts;\r\n\r\n\t}\r\n\r\n\tgetBindings() {\r\n\r\n\t\treturn this.bindings;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Handler for the document level 'keydown' event.\r\n\t *\r\n\t * @param {object} event\r\n\t */\r\n\tonDocumentKeyDown( event ) {\r\n\r\n\t\tlet config = this.Reveal.getConfig();\r\n\r\n\t\t// If there's a condition specified and it returns false,\r\n\t\t// ignore this event\r\n\t\tif( typeof config.keyboardCondition === 'function' && config.keyboardCondition(event) === false ) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\t// If keyboardCondition is set, only capture keyboard events\r\n\t\t// for embedded decks when they are focused\r\n\t\tif( config.keyboardCondition === 'focused' && !this.Reveal.isFocused() ) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\t// Shorthand\r\n\t\tlet keyCode = event.keyCode;\r\n\r\n\t\t// Remember if auto-sliding was paused so we can toggle it\r\n\t\tlet autoSlideWasPaused = !this.Reveal.isAutoSliding();\r\n\r\n\t\tthis.Reveal.onUserInput( event );\r\n\r\n\t\t// Is there a focused element that could be using the keyboard?\r\n\t\tlet activeElementIsCE = document.activeElement && document.activeElement.isContentEditable === true;\r\n\t\tlet activeElementIsInput = document.activeElement && document.activeElement.tagName && /input|textarea/i.test( document.activeElement.tagName );\r\n\t\tlet activeElementIsNotes = document.activeElement && document.activeElement.className && /speaker-notes/i.test( document.activeElement.className);\r\n\r\n\t\t// Whitelist certain modifiers for slide navigation shortcuts\r\n\t\tlet keyCodeUsesModifier = [32, 37, 38, 39, 40, 78, 80, 191].indexOf( event.keyCode ) !== -1;\r\n\r\n\t\t// Prevent all other events when a modifier is pressed\r\n\t\tlet unusedModifier = \t!( keyCodeUsesModifier && event.shiftKey || event.altKey ) &&\r\n\t\t\t\t\t\t\t\t( event.shiftKey || event.altKey || event.ctrlKey || event.metaKey );\r\n\r\n\t\t// Disregard the event if there's a focused element or a\r\n\t\t// keyboard modifier key is present\r\n\t\tif( activeElementIsCE || activeElementIsInput || activeElementIsNotes || unusedModifier ) return;\r\n\r\n\t\t// While paused only allow resume keyboard events; 'b', 'v', '.'\r\n\t\tlet resumeKeyCodes = [66,86,190,191];\r\n\t\tlet key;\r\n\r\n\t\t// Custom key bindings for togglePause should be able to resume\r\n\t\tif( typeof config.keyboard === 'object' ) {\r\n\t\t\tfor( key in config.keyboard ) {\r\n\t\t\t\tif( config.keyboard[key] === 'togglePause' ) {\r\n\t\t\t\t\tresumeKeyCodes.push( parseInt( key, 10 ) );\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif( this.Reveal.isPaused() && resumeKeyCodes.indexOf( keyCode ) === -1 ) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\t// Use linear navigation if we're configured to OR if\r\n\t\t// the presentation is one-dimensional\r\n\t\tlet useLinearMode = config.navigationMode === 'linear' || !this.Reveal.hasHorizontalSlides() || !this.Reveal.hasVerticalSlides();\r\n\r\n\t\tlet triggered = false;\r\n\r\n\t\t// 1. User defined key bindings\r\n\t\tif( typeof config.keyboard === 'object' ) {\r\n\r\n\t\t\tfor( key in config.keyboard ) {\r\n\r\n\t\t\t\t// Check if this binding matches the pressed key\r\n\t\t\t\tif( parseInt( key, 10 ) === keyCode ) {\r\n\r\n\t\t\t\t\tlet value = config.keyboard[ key ];\r\n\r\n\t\t\t\t\t// Callback function\r\n\t\t\t\t\tif( typeof value === 'function' ) {\r\n\t\t\t\t\t\tvalue.apply( null, [ event ] );\r\n\t\t\t\t\t}\r\n\t\t\t\t\t// String shortcuts to reveal.js API\r\n\t\t\t\t\telse if( typeof value === 'string' && typeof this.Reveal[ value ] === 'function' ) {\r\n\t\t\t\t\t\tthis.Reveal[ value ].call();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\ttriggered = true;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// 2. Registered custom key bindings\r\n\t\tif( triggered === false ) {\r\n\r\n\t\t\tfor( key in this.bindings ) {\r\n\r\n\t\t\t\t// Check if this binding matches the pressed key\r\n\t\t\t\tif( parseInt( key, 10 ) === keyCode ) {\r\n\r\n\t\t\t\t\tlet action = this.bindings[ key ].callback;\r\n\r\n\t\t\t\t\t// Callback function\r\n\t\t\t\t\tif( typeof action === 'function' ) {\r\n\t\t\t\t\t\taction.apply( null, [ event ] );\r\n\t\t\t\t\t}\r\n\t\t\t\t\t// String shortcuts to reveal.js API\r\n\t\t\t\t\telse if( typeof action === 'string' && typeof this.Reveal[ action ] === 'function' ) {\r\n\t\t\t\t\t\tthis.Reveal[ action ].call();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\ttriggered = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// 3. System defined key bindings\r\n\t\tif( triggered === false ) {\r\n\r\n\t\t\t// Assume true and try to prove false\r\n\t\t\ttriggered = true;\r\n\r\n\t\t\t// P, PAGE UP\r\n\t\t\tif( keyCode === 80 || keyCode === 33 ) {\r\n\t\t\t\tthis.Reveal.prev({skipFragments: event.altKey});\r\n\t\t\t}\r\n\t\t\t// N, PAGE DOWN\r\n\t\t\telse if( keyCode === 78 || keyCode === 34 ) {\r\n\t\t\t\tthis.Reveal.next({skipFragments: event.altKey});\r\n\t\t\t}\r\n\t\t\t// H, LEFT\r\n\t\t\telse if( keyCode === 72 || keyCode === 37 ) {\r\n\t\t\t\tif( event.shiftKey ) {\r\n\t\t\t\t\tthis.Reveal.slide( 0 );\r\n\t\t\t\t}\r\n\t\t\t\telse if( !this.Reveal.overview.isActive() && useLinearMode ) {\r\n\t\t\t\t\tthis.Reveal.prev({skipFragments: event.altKey});\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\tthis.Reveal.left({skipFragments: event.altKey});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t// L, RIGHT\r\n\t\t\telse if( keyCode === 76 || keyCode === 39 ) {\r\n\t\t\t\tif( event.shiftKey ) {\r\n\t\t\t\t\tthis.Reveal.slide( this.Reveal.getHorizontalSlides().length - 1 );\r\n\t\t\t\t}\r\n\t\t\t\telse if( !this.Reveal.overview.isActive() && useLinearMode ) {\r\n\t\t\t\t\tthis.Reveal.next({skipFragments: event.altKey});\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\tthis.Reveal.right({skipFragments: event.altKey});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t// K, UP\r\n\t\t\telse if( keyCode === 75 || keyCode === 38 ) {\r\n\t\t\t\tif( event.shiftKey ) {\r\n\t\t\t\t\tthis.Reveal.slide( undefined, 0 );\r\n\t\t\t\t}\r\n\t\t\t\telse if( !this.Reveal.overview.isActive() && useLinearMode ) {\r\n\t\t\t\t\tthis.Reveal.prev({skipFragments: event.altKey});\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\tthis.Reveal.up({skipFragments: event.altKey});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t// J, DOWN\r\n\t\t\telse if( keyCode === 74 || keyCode === 40 ) {\r\n\t\t\t\tif( event.shiftKey ) {\r\n\t\t\t\t\tthis.Reveal.slide( undefined, Number.MAX_VALUE );\r\n\t\t\t\t}\r\n\t\t\t\telse if( !this.Reveal.overview.isActive() && useLinearMode ) {\r\n\t\t\t\t\tthis.Reveal.next({skipFragments: event.altKey});\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\tthis.Reveal.down({skipFragments: event.altKey});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t// HOME\r\n\t\t\telse if( keyCode === 36 ) {\r\n\t\t\t\tthis.Reveal.slide( 0 );\r\n\t\t\t}\r\n\t\t\t// END\r\n\t\t\telse if( keyCode === 35 ) {\r\n\t\t\t\tthis.Reveal.slide( this.Reveal.getHorizontalSlides().length - 1 );\r\n\t\t\t}\r\n\t\t\t// SPACE\r\n\t\t\telse if( keyCode === 32 ) {\r\n\t\t\t\tif( this.Reveal.overview.isActive() ) {\r\n\t\t\t\t\tthis.Reveal.overview.deactivate();\r\n\t\t\t\t}\r\n\t\t\t\tif( event.shiftKey ) {\r\n\t\t\t\t\tthis.Reveal.prev({skipFragments: event.altKey});\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\tthis.Reveal.next({skipFragments: event.altKey});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t// TWO-SPOT, SEMICOLON, B, V, PERIOD, LOGITECH PRESENTER TOOLS \"BLACK SCREEN\" BUTTON\r\n\t\t\telse if( [58, 59, 66, 86, 190].includes( keyCode ) || ( keyCode === 191 && !event.shiftKey ) ) {\r\n\t\t\t\tthis.Reveal.togglePause();\r\n\t\t\t}\r\n\t\t\t// F\r\n\t\t\telse if( keyCode === 70 ) {\r\n\t\t\t\tenterFullscreen( config.embedded ? this.Reveal.getViewportElement() : document.documentElement );\r\n\t\t\t}\r\n\t\t\t// A\r\n\t\t\telse if( keyCode === 65 ) {\r\n\t\t\t\tif( config.autoSlideStoppable ) {\r\n\t\t\t\t\tthis.Reveal.toggleAutoSlide( autoSlideWasPaused );\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t// G\r\n\t\t\telse if( keyCode === 71 ) {\r\n\t\t\t\tif( config.jumpToSlide ) {\r\n\t\t\t\t\tthis.Reveal.toggleJumpToSlide();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t// ?\r\n\t\t\telse if( keyCode === 191 && event.shiftKey ) {\r\n\t\t\t\tthis.Reveal.toggleHelp();\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\ttriggered = false;\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// If the input resulted in a triggered action we should prevent\r\n\t\t// the browsers default behavior\r\n\t\tif( triggered ) {\r\n\t\t\tevent.preventDefault && event.preventDefault();\r\n\t\t}\r\n\t\t// ESC or O key\r\n\t\telse if( keyCode === 27 || keyCode === 79 ) {\r\n\t\t\tif( this.Reveal.closeOverlay() === false ) {\r\n\t\t\t\tthis.Reveal.overview.toggle();\r\n\t\t\t}\r\n\r\n\t\t\tevent.preventDefault && event.preventDefault();\r\n\t\t}\r\n\r\n\t\t// If auto-sliding is enabled we need to cue up\r\n\t\t// another timeout\r\n\t\tthis.Reveal.cueAutoSlide();\r\n\r\n\t}\r\n\r\n}","/**\r\n * Reads and writes the URL based on reveal.js' current state.\r\n */\r\nexport default class Location {\r\n\r\n\t// The minimum number of milliseconds that must pass between\r\n\t// calls to history.replaceState\r\n\tMAX_REPLACE_STATE_FREQUENCY = 1000\r\n\r\n\tconstructor( Reveal ) {\r\n\r\n\t\tthis.Reveal = Reveal;\r\n\r\n\t\t// Delays updates to the URL due to a Chrome thumbnailer bug\r\n\t\tthis.writeURLTimeout = 0;\r\n\r\n\t\tthis.replaceStateTimestamp = 0;\r\n\r\n\t\tthis.onWindowHashChange = this.onWindowHashChange.bind( this );\r\n\r\n\t}\r\n\r\n\tbind() {\r\n\r\n\t\twindow.addEventListener( 'hashchange', this.onWindowHashChange, false );\r\n\r\n\t}\r\n\r\n\tunbind() {\r\n\r\n\t\twindow.removeEventListener( 'hashchange', this.onWindowHashChange, false );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the slide indices for the given hash link.\r\n\t *\r\n\t * @param {string} [hash] the hash string that we want to\r\n\t * find the indices for\r\n\t *\r\n\t * @returns slide indices or null\r\n\t */\r\n\tgetIndicesFromHash( hash=window.location.hash, options={} ) {\r\n\r\n\t\t// Attempt to parse the hash as either an index or name\r\n\t\tlet name = hash.replace( /^#\\/?/, '' );\r\n\t\tlet bits = name.split( '/' );\r\n\r\n\t\t// If the first bit is not fully numeric and there is a name we\r\n\t\t// can assume that this is a named link\r\n\t\tif( !/^[0-9]*$/.test( bits[0] ) && name.length ) {\r\n\t\t\tlet slide;\r\n\r\n\t\t\tlet f;\r\n\r\n\t\t\t// Parse named links with fragments (#/named-link/2)\r\n\t\t\tif( /\\/[-\\d]+$/g.test( name ) ) {\r\n\t\t\t\tf = parseInt( name.split( '/' ).pop(), 10 );\r\n\t\t\t\tf = isNaN(f) ? undefined : f;\r\n\t\t\t\tname = name.split( '/' ).shift();\r\n\t\t\t}\r\n\r\n\t\t\t// Ensure the named link is a valid HTML ID attribute\r\n\t\t\ttry {\r\n\t\t\t\tslide = document\r\n\t\t\t\t\t.getElementById( decodeURIComponent( name ) )\r\n\t\t\t\t\t.closest('.slides section');\r\n\t\t\t}\r\n\t\t\tcatch ( error ) { }\r\n\r\n\t\t\tif( slide ) {\r\n\t\t\t\treturn { ...this.Reveal.getIndices( slide ), f };\r\n\t\t\t}\r\n\t\t}\r\n\t\telse {\r\n\t\t\tconst config = this.Reveal.getConfig();\r\n\t\t\tlet hashIndexBase = config.hashOneBasedIndex || options.oneBasedIndex ? 1 : 0;\r\n\r\n\t\t\t// Read the index components of the hash\r\n\t\t\tlet h = ( parseInt( bits[0], 10 ) - hashIndexBase ) || 0,\r\n\t\t\t\tv = ( parseInt( bits[1], 10 ) - hashIndexBase ) || 0,\r\n\t\t\t\tf;\r\n\r\n\t\t\tif( config.fragmentInURL ) {\r\n\t\t\t\tf = parseInt( bits[2], 10 );\r\n\t\t\t\tif( isNaN( f ) ) {\r\n\t\t\t\t\tf = undefined;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn { h, v, f };\r\n\t\t}\r\n\r\n\t\t// The hash couldn't be parsed or no matching named link was found\r\n\t\treturn null\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Reads the current URL (hash) and navigates accordingly.\r\n\t */\r\n\treadURL() {\r\n\r\n\t\tconst currentIndices = this.Reveal.getIndices();\r\n\t\tconst newIndices = this.getIndicesFromHash();\r\n\r\n\t\tif( newIndices ) {\r\n\t\t\tif( ( newIndices.h !== currentIndices.h || newIndices.v !== currentIndices.v || newIndices.f !== undefined ) ) {\r\n\t\t\t\t\tthis.Reveal.slide( newIndices.h, newIndices.v, newIndices.f );\r\n\t\t\t}\r\n\t\t}\r\n\t\t// If no new indices are available, we're trying to navigate to\r\n\t\t// a slide hash that does not exist\r\n\t\telse {\r\n\t\t\tthis.Reveal.slide( currentIndices.h || 0, currentIndices.v || 0 );\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Updates the page URL (hash) to reflect the current\r\n\t * state.\r\n\t *\r\n\t * @param {number} delay The time in ms to wait before\r\n\t * writing the hash\r\n\t */\r\n\twriteURL( delay ) {\r\n\r\n\t\tlet config = this.Reveal.getConfig();\r\n\t\tlet currentSlide = this.Reveal.getCurrentSlide();\r\n\r\n\t\t// Make sure there's never more than one timeout running\r\n\t\tclearTimeout( this.writeURLTimeout );\r\n\r\n\t\t// If a delay is specified, timeout this call\r\n\t\tif( typeof delay === 'number' ) {\r\n\t\t\tthis.writeURLTimeout = setTimeout( this.writeURL, delay );\r\n\t\t}\r\n\t\telse if( currentSlide ) {\r\n\r\n\t\t\tlet hash = this.getHash();\r\n\r\n\t\t\t// If we're configured to push to history OR the history\r\n\t\t\t// API is not available.\r\n\t\t\tif( config.history ) {\r\n\t\t\t\twindow.location.hash = hash;\r\n\t\t\t}\r\n\t\t\t// If we're configured to reflect the current slide in the\r\n\t\t\t// URL without pushing to history.\r\n\t\t\telse if( config.hash ) {\r\n\t\t\t\t// If the hash is empty, don't add it to the URL\r\n\t\t\t\tif( hash === '/' ) {\r\n\t\t\t\t\tthis.debouncedReplaceState( window.location.pathname + window.location.search );\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\tthis.debouncedReplaceState( '#' + hash );\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t// UPDATE: The below nuking of all hash changes breaks\r\n\t\t\t// anchors on pages where reveal.js is running. Removed\r\n\t\t\t// in 4.0. Why was it here in the first place? ¯\\_(ツ)_/¯\r\n\t\t\t//\r\n\t\t\t// If history and hash are both disabled, a hash may still\r\n\t\t\t// be added to the URL by clicking on a href with a hash\r\n\t\t\t// target. Counter this by always removing the hash.\r\n\t\t\t// else {\r\n\t\t\t// \twindow.history.replaceState( null, null, window.location.pathname + window.location.search );\r\n\t\t\t// }\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\treplaceState( url ) {\r\n\r\n\t\twindow.history.replaceState( null, null, url );\r\n\t\tthis.replaceStateTimestamp = Date.now();\r\n\r\n\t}\r\n\r\n\tdebouncedReplaceState( url ) {\r\n\r\n\t\tclearTimeout( this.replaceStateTimeout );\r\n\r\n\t\tif( Date.now() - this.replaceStateTimestamp > this.MAX_REPLACE_STATE_FREQUENCY ) {\r\n\t\t\tthis.replaceState( url );\r\n\t\t}\r\n\t\telse {\r\n\t\t\tthis.replaceStateTimeout = setTimeout( () => this.replaceState( url ), this.MAX_REPLACE_STATE_FREQUENCY );\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Return a hash URL that will resolve to the given slide location.\r\n\t *\r\n\t * @param {HTMLElement} [slide=currentSlide] The slide to link to\r\n\t */\r\n\tgetHash( slide ) {\r\n\r\n\t\tlet url = '/';\r\n\r\n\t\t// Attempt to create a named link based on the slide's ID\r\n\t\tlet s = slide || this.Reveal.getCurrentSlide();\r\n\t\tlet id = s ? s.getAttribute( 'id' ) : null;\r\n\t\tif( id ) {\r\n\t\t\tid = encodeURIComponent( id );\r\n\t\t}\r\n\r\n\t\tlet index = this.Reveal.getIndices( slide );\r\n\t\tif( !this.Reveal.getConfig().fragmentInURL ) {\r\n\t\t\tindex.f = undefined;\r\n\t\t}\r\n\r\n\t\t// If the current slide has an ID, use that as a named link,\r\n\t\t// but we don't support named links with a fragment index\r\n\t\tif( typeof id === 'string' && id.length ) {\r\n\t\t\turl = '/' + id;\r\n\r\n\t\t\t// If there is also a fragment, append that at the end\r\n\t\t\t// of the named link, like: #/named-link/2\r\n\t\t\tif( index.f >= 0 ) url += '/' + index.f;\r\n\t\t}\r\n\t\t// Otherwise use the /h/v index\r\n\t\telse {\r\n\t\t\tlet hashIndexBase = this.Reveal.getConfig().hashOneBasedIndex ? 1 : 0;\r\n\t\t\tif( index.h > 0 || index.v > 0 || index.f >= 0 ) url += index.h + hashIndexBase;\r\n\t\t\tif( index.v > 0 || index.f >= 0 ) url += '/' + (index.v + hashIndexBase );\r\n\t\t\tif( index.f >= 0 ) url += '/' + index.f;\r\n\t\t}\r\n\r\n\t\treturn url;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Handler for the window level 'hashchange' event.\r\n\t *\r\n\t * @param {object} [event]\r\n\t */\r\n\tonWindowHashChange( event ) {\r\n\r\n\t\tthis.readURL();\r\n\r\n\t}\r\n\r\n}","import { queryAll } from '../utils/util.js'\r\nimport { isAndroid } from '../utils/device.js'\r\n\r\n/**\r\n * Manages our presentation controls. This includes both\r\n * the built-in control arrows as well as event monitoring\r\n * of any elements within the presentation with either of the\r\n * following helper classes:\r\n * - .navigate-up\r\n * - .navigate-right\r\n * - .navigate-down\r\n * - .navigate-left\r\n * - .navigate-next\r\n * - .navigate-prev\r\n */\r\nexport default class Controls {\r\n\r\n\tconstructor( Reveal ) {\r\n\r\n\t\tthis.Reveal = Reveal;\r\n\r\n\t\tthis.onNavigateLeftClicked = this.onNavigateLeftClicked.bind( this );\r\n\t\tthis.onNavigateRightClicked = this.onNavigateRightClicked.bind( this );\r\n\t\tthis.onNavigateUpClicked = this.onNavigateUpClicked.bind( this );\r\n\t\tthis.onNavigateDownClicked = this.onNavigateDownClicked.bind( this );\r\n\t\tthis.onNavigatePrevClicked = this.onNavigatePrevClicked.bind( this );\r\n\t\tthis.onNavigateNextClicked = this.onNavigateNextClicked.bind( this );\r\n\r\n\t}\r\n\r\n\trender() {\r\n\r\n\t\tconst rtl = this.Reveal.getConfig().rtl;\r\n\t\tconst revealElement = this.Reveal.getRevealElement();\r\n\r\n\t\tthis.element = document.createElement( 'aside' );\r\n\t\tthis.element.className = 'controls';\r\n\t\tthis.element.innerHTML =\r\n\t\t\t`\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t`;\r\n\r\n\t\tthis.Reveal.getRevealElement().appendChild( this.element );\r\n\r\n\t\t// There can be multiple instances of controls throughout the page\r\n\t\tthis.controlsLeft = queryAll( revealElement, '.navigate-left' );\r\n\t\tthis.controlsRight = queryAll( revealElement, '.navigate-right' );\r\n\t\tthis.controlsUp = queryAll( revealElement, '.navigate-up' );\r\n\t\tthis.controlsDown = queryAll( revealElement, '.navigate-down' );\r\n\t\tthis.controlsPrev = queryAll( revealElement, '.navigate-prev' );\r\n\t\tthis.controlsNext = queryAll( revealElement, '.navigate-next' );\r\n\r\n\t\t// The left, right and down arrows in the standard reveal.js controls\r\n\t\tthis.controlsRightArrow = this.element.querySelector( '.navigate-right' );\r\n\t\tthis.controlsLeftArrow = this.element.querySelector( '.navigate-left' );\r\n\t\tthis.controlsDownArrow = this.element.querySelector( '.navigate-down' );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Called when the reveal.js config is updated.\r\n\t */\r\n\tconfigure( config, oldConfig ) {\r\n\r\n\t\tthis.element.style.display = config.controls ? 'block' : 'none';\r\n\r\n\t\tthis.element.setAttribute( 'data-controls-layout', config.controlsLayout );\r\n\t\tthis.element.setAttribute( 'data-controls-back-arrows', config.controlsBackArrows );\r\n\r\n\t}\r\n\r\n\tbind() {\r\n\r\n\t\t// Listen to both touch and click events, in case the device\r\n\t\t// supports both\r\n\t\tlet pointerEvents = [ 'touchstart', 'click' ];\r\n\r\n\t\t// Only support touch for Android, fixes double navigations in\r\n\t\t// stock browser\r\n\t\tif( isAndroid ) {\r\n\t\t\tpointerEvents = [ 'touchstart' ];\r\n\t\t}\r\n\r\n\t\tpointerEvents.forEach( eventName => {\r\n\t\t\tthis.controlsLeft.forEach( el => el.addEventListener( eventName, this.onNavigateLeftClicked, false ) );\r\n\t\t\tthis.controlsRight.forEach( el => el.addEventListener( eventName, this.onNavigateRightClicked, false ) );\r\n\t\t\tthis.controlsUp.forEach( el => el.addEventListener( eventName, this.onNavigateUpClicked, false ) );\r\n\t\t\tthis.controlsDown.forEach( el => el.addEventListener( eventName, this.onNavigateDownClicked, false ) );\r\n\t\t\tthis.controlsPrev.forEach( el => el.addEventListener( eventName, this.onNavigatePrevClicked, false ) );\r\n\t\t\tthis.controlsNext.forEach( el => el.addEventListener( eventName, this.onNavigateNextClicked, false ) );\r\n\t\t} );\r\n\r\n\t}\r\n\r\n\tunbind() {\r\n\r\n\t\t[ 'touchstart', 'click' ].forEach( eventName => {\r\n\t\t\tthis.controlsLeft.forEach( el => el.removeEventListener( eventName, this.onNavigateLeftClicked, false ) );\r\n\t\t\tthis.controlsRight.forEach( el => el.removeEventListener( eventName, this.onNavigateRightClicked, false ) );\r\n\t\t\tthis.controlsUp.forEach( el => el.removeEventListener( eventName, this.onNavigateUpClicked, false ) );\r\n\t\t\tthis.controlsDown.forEach( el => el.removeEventListener( eventName, this.onNavigateDownClicked, false ) );\r\n\t\t\tthis.controlsPrev.forEach( el => el.removeEventListener( eventName, this.onNavigatePrevClicked, false ) );\r\n\t\t\tthis.controlsNext.forEach( el => el.removeEventListener( eventName, this.onNavigateNextClicked, false ) );\r\n\t\t} );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Updates the state of all control/navigation arrows.\r\n\t */\r\n\tupdate() {\r\n\r\n\t\tlet routes = this.Reveal.availableRoutes();\r\n\r\n\t\t// Remove the 'enabled' class from all directions\r\n\t\t[...this.controlsLeft, ...this.controlsRight, ...this.controlsUp, ...this.controlsDown, ...this.controlsPrev, ...this.controlsNext].forEach( node => {\r\n\t\t\tnode.classList.remove( 'enabled', 'fragmented' );\r\n\r\n\t\t\t// Set 'disabled' attribute on all directions\r\n\t\t\tnode.setAttribute( 'disabled', 'disabled' );\r\n\t\t} );\r\n\r\n\t\t// Add the 'enabled' class to the available routes; remove 'disabled' attribute to enable buttons\r\n\t\tif( routes.left ) this.controlsLeft.forEach( el => { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } );\r\n\t\tif( routes.right ) this.controlsRight.forEach( el => { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } );\r\n\t\tif( routes.up ) this.controlsUp.forEach( el => { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } );\r\n\t\tif( routes.down ) this.controlsDown.forEach( el => { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } );\r\n\r\n\t\t// Prev/next buttons\r\n\t\tif( routes.left || routes.up ) this.controlsPrev.forEach( el => { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } );\r\n\t\tif( routes.right || routes.down ) this.controlsNext.forEach( el => { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } );\r\n\r\n\t\t// Highlight fragment directions\r\n\t\tlet currentSlide = this.Reveal.getCurrentSlide();\r\n\t\tif( currentSlide ) {\r\n\r\n\t\t\tlet fragmentsRoutes = this.Reveal.fragments.availableRoutes();\r\n\r\n\t\t\t// Always apply fragment decorator to prev/next buttons\r\n\t\t\tif( fragmentsRoutes.prev ) this.controlsPrev.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );\r\n\t\t\tif( fragmentsRoutes.next ) this.controlsNext.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );\r\n\r\n\t\t\t// Apply fragment decorators to directional buttons based on\r\n\t\t\t// what slide axis they are in\r\n\t\t\tif( this.Reveal.isVerticalSlide( currentSlide ) ) {\r\n\t\t\t\tif( fragmentsRoutes.prev ) this.controlsUp.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );\r\n\t\t\t\tif( fragmentsRoutes.next ) this.controlsDown.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tif( fragmentsRoutes.prev ) this.controlsLeft.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );\r\n\t\t\t\tif( fragmentsRoutes.next ) this.controlsRight.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } );\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tif( this.Reveal.getConfig().controlsTutorial ) {\r\n\r\n\t\t\tlet indices = this.Reveal.getIndices();\r\n\r\n\t\t\t// Highlight control arrows with an animation to ensure\r\n\t\t\t// that the viewer knows how to navigate\r\n\t\t\tif( !this.Reveal.hasNavigatedVertically() && routes.down ) {\r\n\t\t\t\tthis.controlsDownArrow.classList.add( 'highlight' );\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tthis.controlsDownArrow.classList.remove( 'highlight' );\r\n\r\n\t\t\t\tif( this.Reveal.getConfig().rtl ) {\r\n\r\n\t\t\t\t\tif( !this.Reveal.hasNavigatedHorizontally() && routes.left && indices.v === 0 ) {\r\n\t\t\t\t\t\tthis.controlsLeftArrow.classList.add( 'highlight' );\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tthis.controlsLeftArrow.classList.remove( 'highlight' );\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tif( !this.Reveal.hasNavigatedHorizontally() && routes.right && indices.v === 0 ) {\r\n\t\t\t\t\t\tthis.controlsRightArrow.classList.add( 'highlight' );\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tthis.controlsRightArrow.classList.remove( 'highlight' );\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tdestroy() {\r\n\r\n\t\tthis.unbind();\r\n\t\tthis.element.remove();\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Event handlers for navigation control buttons.\r\n\t */\r\n\tonNavigateLeftClicked( event ) {\r\n\r\n\t\tevent.preventDefault();\r\n\t\tthis.Reveal.onUserInput();\r\n\r\n\t\tif( this.Reveal.getConfig().navigationMode === 'linear' ) {\r\n\t\t\tthis.Reveal.prev();\r\n\t\t}\r\n\t\telse {\r\n\t\t\tthis.Reveal.left();\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tonNavigateRightClicked( event ) {\r\n\r\n\t\tevent.preventDefault();\r\n\t\tthis.Reveal.onUserInput();\r\n\r\n\t\tif( this.Reveal.getConfig().navigationMode === 'linear' ) {\r\n\t\t\tthis.Reveal.next();\r\n\t\t}\r\n\t\telse {\r\n\t\t\tthis.Reveal.right();\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tonNavigateUpClicked( event ) {\r\n\r\n\t\tevent.preventDefault();\r\n\t\tthis.Reveal.onUserInput();\r\n\r\n\t\tthis.Reveal.up();\r\n\r\n\t}\r\n\r\n\tonNavigateDownClicked( event ) {\r\n\r\n\t\tevent.preventDefault();\r\n\t\tthis.Reveal.onUserInput();\r\n\r\n\t\tthis.Reveal.down();\r\n\r\n\t}\r\n\r\n\tonNavigatePrevClicked( event ) {\r\n\r\n\t\tevent.preventDefault();\r\n\t\tthis.Reveal.onUserInput();\r\n\r\n\t\tthis.Reveal.prev();\r\n\r\n\t}\r\n\r\n\tonNavigateNextClicked( event ) {\r\n\r\n\t\tevent.preventDefault();\r\n\t\tthis.Reveal.onUserInput();\r\n\r\n\t\tthis.Reveal.next();\r\n\r\n\t}\r\n\r\n\r\n}","/**\r\n * Creates a visual progress bar for the presentation.\r\n */\r\nexport default class Progress {\r\n\r\n\tconstructor( Reveal ) {\r\n\r\n\t\tthis.Reveal = Reveal;\r\n\r\n\t\tthis.onProgressClicked = this.onProgressClicked.bind( this );\r\n\r\n\t}\r\n\r\n\trender() {\r\n\r\n\t\tthis.element = document.createElement( 'div' );\r\n\t\tthis.element.className = 'progress';\r\n\t\tthis.Reveal.getRevealElement().appendChild( this.element );\r\n\r\n\t\tthis.bar = document.createElement( 'span' );\r\n\t\tthis.element.appendChild( this.bar );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Called when the reveal.js config is updated.\r\n\t */\r\n\tconfigure( config, oldConfig ) {\r\n\r\n\t\tthis.element.style.display = config.progress ? 'block' : 'none';\r\n\r\n\t}\r\n\r\n\tbind() {\r\n\r\n\t\tif( this.Reveal.getConfig().progress && this.element ) {\r\n\t\t\tthis.element.addEventListener( 'click', this.onProgressClicked, false );\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tunbind() {\r\n\r\n\t\tif ( this.Reveal.getConfig().progress && this.element ) {\r\n\t\t\tthis.element.removeEventListener( 'click', this.onProgressClicked, false );\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Updates the progress bar to reflect the current slide.\r\n\t */\r\n\tupdate() {\r\n\r\n\t\t// Update progress if enabled\r\n\t\tif( this.Reveal.getConfig().progress && this.bar ) {\r\n\r\n\t\t\tlet scale = this.Reveal.getProgress();\r\n\r\n\t\t\t// Don't fill the progress bar if there's only one slide\r\n\t\t\tif( this.Reveal.getTotalSlides() < 2 ) {\r\n\t\t\t\tscale = 0;\r\n\t\t\t}\r\n\r\n\t\t\tthis.bar.style.transform = 'scaleX('+ scale +')';\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tgetMaxWidth() {\r\n\r\n\t\treturn this.Reveal.getRevealElement().offsetWidth;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Clicking on the progress bar results in a navigation to the\r\n\t * closest approximate horizontal slide using this equation:\r\n\t *\r\n\t * ( clickX / presentationWidth ) * numberOfSlides\r\n\t *\r\n\t * @param {object} event\r\n\t */\r\n\tonProgressClicked( event ) {\r\n\r\n\t\tthis.Reveal.onUserInput( event );\r\n\r\n\t\tevent.preventDefault();\r\n\r\n\t\tlet slides = this.Reveal.getSlides();\r\n\t\tlet slidesTotal = slides.length;\r\n\t\tlet slideIndex = Math.floor( ( event.clientX / this.getMaxWidth() ) * slidesTotal );\r\n\r\n\t\tif( this.Reveal.getConfig().rtl ) {\r\n\t\t\tslideIndex = slidesTotal - slideIndex;\r\n\t\t}\r\n\r\n\t\tlet targetIndices = this.Reveal.getIndices(slides[slideIndex]);\r\n\t\tthis.Reveal.slide( targetIndices.h, targetIndices.v );\r\n\r\n\t}\r\n\r\n\tdestroy() {\r\n\r\n\t\tthis.element.remove();\r\n\r\n\t}\r\n\r\n}","/**\r\n * Handles hiding of the pointer/cursor when inactive.\r\n */\r\nexport default class Pointer {\r\n\r\n\tconstructor( Reveal ) {\r\n\r\n\t\tthis.Reveal = Reveal;\r\n\r\n\t\t// Throttles mouse wheel navigation\r\n\t\tthis.lastMouseWheelStep = 0;\r\n\r\n\t\t// Is the mouse pointer currently hidden from view\r\n\t\tthis.cursorHidden = false;\r\n\r\n\t\t// Timeout used to determine when the cursor is inactive\r\n\t\tthis.cursorInactiveTimeout = 0;\r\n\r\n\t\tthis.onDocumentCursorActive = this.onDocumentCursorActive.bind( this );\r\n\t\tthis.onDocumentMouseScroll = this.onDocumentMouseScroll.bind( this );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Called when the reveal.js config is updated.\r\n\t */\r\n\tconfigure( config, oldConfig ) {\r\n\r\n\t\tif( config.mouseWheel ) {\r\n\t\t\tdocument.addEventListener( 'wheel', this.onDocumentMouseScroll, false );\r\n\t\t}\r\n\t\telse {\r\n\t\t\tdocument.removeEventListener( 'wheel', this.onDocumentMouseScroll, false );\r\n\t\t}\r\n\r\n\t\t// Auto-hide the mouse pointer when its inactive\r\n\t\tif( config.hideInactiveCursor ) {\r\n\t\t\tdocument.addEventListener( 'mousemove', this.onDocumentCursorActive, false );\r\n\t\t\tdocument.addEventListener( 'mousedown', this.onDocumentCursorActive, false );\r\n\t\t}\r\n\t\telse {\r\n\t\t\tthis.showCursor();\r\n\r\n\t\t\tdocument.removeEventListener( 'mousemove', this.onDocumentCursorActive, false );\r\n\t\t\tdocument.removeEventListener( 'mousedown', this.onDocumentCursorActive, false );\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Shows the mouse pointer after it has been hidden with\r\n\t * #hideCursor.\r\n\t */\r\n\tshowCursor() {\r\n\r\n\t\tif( this.cursorHidden ) {\r\n\t\t\tthis.cursorHidden = false;\r\n\t\t\tthis.Reveal.getRevealElement().style.cursor = '';\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Hides the mouse pointer when it's on top of the .reveal\r\n\t * container.\r\n\t */\r\n\thideCursor() {\r\n\r\n\t\tif( this.cursorHidden === false ) {\r\n\t\t\tthis.cursorHidden = true;\r\n\t\t\tthis.Reveal.getRevealElement().style.cursor = 'none';\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tdestroy() {\r\n\r\n\t\tthis.showCursor();\r\n\r\n\t\tdocument.removeEventListener( 'wheel', this.onDocumentMouseScroll, false );\r\n\t\tdocument.removeEventListener( 'mousemove', this.onDocumentCursorActive, false );\r\n\t\tdocument.removeEventListener( 'mousedown', this.onDocumentCursorActive, false );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Called whenever there is mouse input at the document level\r\n\t * to determine if the cursor is active or not.\r\n\t *\r\n\t * @param {object} event\r\n\t */\r\n\tonDocumentCursorActive( event ) {\r\n\r\n\t\tthis.showCursor();\r\n\r\n\t\tclearTimeout( this.cursorInactiveTimeout );\r\n\r\n\t\tthis.cursorInactiveTimeout = setTimeout( this.hideCursor.bind( this ), this.Reveal.getConfig().hideCursorTime );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Handles mouse wheel scrolling, throttled to avoid skipping\r\n\t * multiple slides.\r\n\t *\r\n\t * @param {object} event\r\n\t */\r\n\tonDocumentMouseScroll( event ) {\r\n\r\n\t\tif( Date.now() - this.lastMouseWheelStep > 1000 ) {\r\n\r\n\t\t\tthis.lastMouseWheelStep = Date.now();\r\n\r\n\t\t\tlet delta = event.detail || -event.wheelDelta;\r\n\t\t\tif( delta > 0 ) {\r\n\t\t\t\tthis.Reveal.next();\r\n\t\t\t}\r\n\t\t\telse if( delta < 0 ) {\r\n\t\t\t\tthis.Reveal.prev();\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n}\r\n","/**\r\n * Loads a JavaScript file from the given URL and executes it.\r\n *\r\n * @param {string} url Address of the .js file to load\r\n * @param {function} callback Method to invoke when the script\r\n * has loaded and executed\r\n */\r\nexport const loadScript = ( url, callback ) => {\r\n\r\n\tconst script = document.createElement( 'script' );\r\n\tscript.type = 'text/javascript';\r\n\tscript.async = false;\r\n\tscript.defer = false;\r\n\tscript.src = url;\r\n\r\n\tif( typeof callback === 'function' ) {\r\n\r\n\t\t// Success callback\r\n\t\tscript.onload = script.onreadystatechange = event => {\r\n\t\t\tif( event.type === 'load' || /loaded|complete/.test( script.readyState ) ) {\r\n\r\n\t\t\t\t// Kill event listeners\r\n\t\t\t\tscript.onload = script.onreadystatechange = script.onerror = null;\r\n\r\n\t\t\t\tcallback();\r\n\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t// Error callback\r\n\t\tscript.onerror = err => {\r\n\r\n\t\t\t// Kill event listeners\r\n\t\t\tscript.onload = script.onreadystatechange = script.onerror = null;\r\n\r\n\t\t\tcallback( new Error( 'Failed loading script: ' + script.src + '\\n' + err ) );\r\n\r\n\t\t};\r\n\r\n\t}\r\n\r\n\t// Append the script at the end of \r\n\tconst head = document.querySelector( 'head' );\r\n\thead.insertBefore( script, head.lastChild );\r\n\r\n}","import { loadScript } from '../utils/loader.js'\r\n\r\n/**\r\n * Manages loading and registering of reveal.js plugins.\r\n */\r\nexport default class Plugins {\r\n\r\n\tconstructor( reveal ) {\r\n\r\n\t\tthis.Reveal = reveal;\r\n\r\n\t\t// Flags our current state (idle -> loading -> loaded)\r\n\t\tthis.state = 'idle';\r\n\r\n\t\t// An id:instance map of currently registered plugins\r\n\t\tthis.registeredPlugins = {};\r\n\r\n\t\tthis.asyncDependencies = [];\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Loads reveal.js dependencies, registers and\r\n\t * initializes plugins.\r\n\t *\r\n\t * Plugins are direct references to a reveal.js plugin\r\n\t * object that we register and initialize after any\r\n\t * synchronous dependencies have loaded.\r\n\t *\r\n\t * Dependencies are defined via the 'dependencies' config\r\n\t * option and will be loaded prior to starting reveal.js.\r\n\t * Some dependencies may have an 'async' flag, if so they\r\n\t * will load after reveal.js has been started up.\r\n\t */\r\n\tload( plugins, dependencies ) {\r\n\r\n\t\tthis.state = 'loading';\r\n\r\n\t\tplugins.forEach( this.registerPlugin.bind( this ) );\r\n\r\n\t\treturn new Promise( resolve => {\r\n\r\n\t\t\tlet scripts = [],\r\n\t\t\t\tscriptsToLoad = 0;\r\n\r\n\t\t\tdependencies.forEach( s => {\r\n\t\t\t\t// Load if there's no condition or the condition is truthy\r\n\t\t\t\tif( !s.condition || s.condition() ) {\r\n\t\t\t\t\tif( s.async ) {\r\n\t\t\t\t\t\tthis.asyncDependencies.push( s );\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tscripts.push( s );\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} );\r\n\r\n\t\t\tif( scripts.length ) {\r\n\t\t\t\tscriptsToLoad = scripts.length;\r\n\r\n\t\t\t\tconst scriptLoadedCallback = (s) => {\r\n\t\t\t\t\tif( s && typeof s.callback === 'function' ) s.callback();\r\n\r\n\t\t\t\t\tif( --scriptsToLoad === 0 ) {\r\n\t\t\t\t\t\tthis.initPlugins().then( resolve );\r\n\t\t\t\t\t}\r\n\t\t\t\t};\r\n\r\n\t\t\t\t// Load synchronous scripts\r\n\t\t\t\tscripts.forEach( s => {\r\n\t\t\t\t\tif( typeof s.id === 'string' ) {\r\n\t\t\t\t\t\tthis.registerPlugin( s );\r\n\t\t\t\t\t\tscriptLoadedCallback( s );\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if( typeof s.src === 'string' ) {\r\n\t\t\t\t\t\tloadScript( s.src, () => scriptLoadedCallback(s) );\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tconsole.warn( 'Unrecognized plugin format', s );\r\n\t\t\t\t\t\tscriptLoadedCallback();\r\n\t\t\t\t\t}\r\n\t\t\t\t} );\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tthis.initPlugins().then( resolve );\r\n\t\t\t}\r\n\r\n\t\t} );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Initializes our plugins and waits for them to be ready\r\n\t * before proceeding.\r\n\t */\r\n\tinitPlugins() {\r\n\r\n\t\treturn new Promise( resolve => {\r\n\r\n\t\t\tlet pluginValues = Object.values( this.registeredPlugins );\r\n\t\t\tlet pluginsToInitialize = pluginValues.length;\r\n\r\n\t\t\t// If there are no plugins, skip this step\r\n\t\t\tif( pluginsToInitialize === 0 ) {\r\n\t\t\t\tthis.loadAsync().then( resolve );\r\n\t\t\t}\r\n\t\t\t// ... otherwise initialize plugins\r\n\t\t\telse {\r\n\r\n\t\t\t\tlet initNextPlugin;\r\n\r\n\t\t\t\tlet afterPlugInitialized = () => {\r\n\t\t\t\t\tif( --pluginsToInitialize === 0 ) {\r\n\t\t\t\t\t\tthis.loadAsync().then( resolve );\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tinitNextPlugin();\r\n\t\t\t\t\t}\r\n\t\t\t\t};\r\n\r\n\t\t\t\tlet i = 0;\r\n\r\n\t\t\t\t// Initialize plugins serially\r\n\t\t\t\tinitNextPlugin = () => {\r\n\r\n\t\t\t\t\tlet plugin = pluginValues[i++];\r\n\r\n\t\t\t\t\t// If the plugin has an 'init' method, invoke it\r\n\t\t\t\t\tif( typeof plugin.init === 'function' ) {\r\n\t\t\t\t\t\tlet promise = plugin.init( this.Reveal );\r\n\r\n\t\t\t\t\t\t// If the plugin returned a Promise, wait for it\r\n\t\t\t\t\t\tif( promise && typeof promise.then === 'function' ) {\r\n\t\t\t\t\t\t\tpromise.then( afterPlugInitialized );\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\tafterPlugInitialized();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tafterPlugInitialized();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tinitNextPlugin();\r\n\r\n\t\t\t}\r\n\r\n\t\t} )\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Loads all async reveal.js dependencies.\r\n\t */\r\n\tloadAsync() {\r\n\r\n\t\tthis.state = 'loaded';\r\n\r\n\t\tif( this.asyncDependencies.length ) {\r\n\t\t\tthis.asyncDependencies.forEach( s => {\r\n\t\t\t\tloadScript( s.src, s.callback );\r\n\t\t\t} );\r\n\t\t}\r\n\r\n\t\treturn Promise.resolve();\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Registers a new plugin with this reveal.js instance.\r\n\t *\r\n\t * reveal.js waits for all registered plugins to initialize\r\n\t * before considering itself ready, as long as the plugin\r\n\t * is registered before calling `Reveal.initialize()`.\r\n\t */\r\n\tregisterPlugin( plugin ) {\r\n\r\n\t\t// Backwards compatibility to make reveal.js ~3.9.0\r\n\t\t// plugins work with reveal.js 4.0.0\r\n\t\tif( arguments.length === 2 && typeof arguments[0] === 'string' ) {\r\n\t\t\tplugin = arguments[1];\r\n\t\t\tplugin.id = arguments[0];\r\n\t\t}\r\n\t\t// Plugin can optionally be a function which we call\r\n\t\t// to create an instance of the plugin\r\n\t\telse if( typeof plugin === 'function' ) {\r\n\t\t\tplugin = plugin();\r\n\t\t}\r\n\r\n\t\tlet id = plugin.id;\r\n\r\n\t\tif( typeof id !== 'string' ) {\r\n\t\t\tconsole.warn( 'Unrecognized plugin format; can\\'t find plugin.id', plugin );\r\n\t\t}\r\n\t\telse if( this.registeredPlugins[id] === undefined ) {\r\n\t\t\tthis.registeredPlugins[id] = plugin;\r\n\r\n\t\t\t// If a plugin is registered after reveal.js is loaded,\r\n\t\t\t// initialize it right away\r\n\t\t\tif( this.state === 'loaded' && typeof plugin.init === 'function' ) {\r\n\t\t\t\tplugin.init( this.Reveal );\r\n\t\t\t}\r\n\t\t}\r\n\t\telse {\r\n\t\t\tconsole.warn( 'reveal.js: \"'+ id +'\" plugin has already been registered' );\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Checks if a specific plugin has been registered.\r\n\t *\r\n\t * @param {String} id Unique plugin identifier\r\n\t */\r\n\thasPlugin( id ) {\r\n\r\n\t\treturn !!this.registeredPlugins[id];\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the specific plugin instance, if a plugin\r\n\t * with the given ID has been registered.\r\n\t *\r\n\t * @param {String} id Unique plugin identifier\r\n\t */\r\n\tgetPlugin( id ) {\r\n\r\n\t\treturn this.registeredPlugins[id];\r\n\r\n\t}\r\n\r\n\tgetRegisteredPlugins() {\r\n\r\n\t\treturn this.registeredPlugins;\r\n\r\n\t}\r\n\r\n\tdestroy() {\r\n\r\n\t\tObject.values( this.registeredPlugins ).forEach( plugin => {\r\n\t\t\tif( typeof plugin.destroy === 'function' ) {\r\n\t\t\t\tplugin.destroy();\r\n\t\t\t}\r\n\t\t} );\r\n\r\n\t\tthis.registeredPlugins = {};\r\n\t\tthis.asyncDependencies = [];\r\n\r\n\t}\r\n\r\n}\r\n","import { isAndroid } from '../utils/device.js'\r\nimport { matches } from '../utils/util.js'\r\n\r\nconst SWIPE_THRESHOLD = 40;\r\n\r\n/**\r\n * Controls all touch interactions and navigations for\r\n * a presentation.\r\n */\r\nexport default class Touch {\r\n\r\n\tconstructor( Reveal ) {\r\n\r\n\t\tthis.Reveal = Reveal;\r\n\r\n\t\t// Holds information about the currently ongoing touch interaction\r\n\t\tthis.touchStartX = 0;\r\n\t\tthis.touchStartY = 0;\r\n\t\tthis.touchStartCount = 0;\r\n\t\tthis.touchCaptured = false;\r\n\r\n\t\tthis.onPointerDown = this.onPointerDown.bind( this );\r\n\t\tthis.onPointerMove = this.onPointerMove.bind( this );\r\n\t\tthis.onPointerUp = this.onPointerUp.bind( this );\r\n\t\tthis.onTouchStart = this.onTouchStart.bind( this );\r\n\t\tthis.onTouchMove = this.onTouchMove.bind( this );\r\n\t\tthis.onTouchEnd = this.onTouchEnd.bind( this );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t *\r\n\t */\r\n\tbind() {\r\n\r\n\t\tlet revealElement = this.Reveal.getRevealElement();\r\n\r\n\t\tif( 'onpointerdown' in window ) {\r\n\t\t\t// Use W3C pointer events\r\n\t\t\trevealElement.addEventListener( 'pointerdown', this.onPointerDown, false );\r\n\t\t\trevealElement.addEventListener( 'pointermove', this.onPointerMove, false );\r\n\t\t\trevealElement.addEventListener( 'pointerup', this.onPointerUp, false );\r\n\t\t}\r\n\t\telse if( window.navigator.msPointerEnabled ) {\r\n\t\t\t// IE 10 uses prefixed version of pointer events\r\n\t\t\trevealElement.addEventListener( 'MSPointerDown', this.onPointerDown, false );\r\n\t\t\trevealElement.addEventListener( 'MSPointerMove', this.onPointerMove, false );\r\n\t\t\trevealElement.addEventListener( 'MSPointerUp', this.onPointerUp, false );\r\n\t\t}\r\n\t\telse {\r\n\t\t\t// Fall back to touch events\r\n\t\t\trevealElement.addEventListener( 'touchstart', this.onTouchStart, false );\r\n\t\t\trevealElement.addEventListener( 'touchmove', this.onTouchMove, false );\r\n\t\t\trevealElement.addEventListener( 'touchend', this.onTouchEnd, false );\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t *\r\n\t */\r\n\tunbind() {\r\n\r\n\t\tlet revealElement = this.Reveal.getRevealElement();\r\n\r\n\t\trevealElement.removeEventListener( 'pointerdown', this.onPointerDown, false );\r\n\t\trevealElement.removeEventListener( 'pointermove', this.onPointerMove, false );\r\n\t\trevealElement.removeEventListener( 'pointerup', this.onPointerUp, false );\r\n\r\n\t\trevealElement.removeEventListener( 'MSPointerDown', this.onPointerDown, false );\r\n\t\trevealElement.removeEventListener( 'MSPointerMove', this.onPointerMove, false );\r\n\t\trevealElement.removeEventListener( 'MSPointerUp', this.onPointerUp, false );\r\n\r\n\t\trevealElement.removeEventListener( 'touchstart', this.onTouchStart, false );\r\n\t\trevealElement.removeEventListener( 'touchmove', this.onTouchMove, false );\r\n\t\trevealElement.removeEventListener( 'touchend', this.onTouchEnd, false );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Checks if the target element prevents the triggering of\r\n\t * swipe navigation.\r\n\t */\r\n\tisSwipePrevented( target ) {\r\n\r\n\t\t// Prevent accidental swipes when scrubbing timelines\r\n\t\tif( matches( target, 'video, audio' ) ) return true;\r\n\r\n\t\twhile( target && typeof target.hasAttribute === 'function' ) {\r\n\t\t\tif( target.hasAttribute( 'data-prevent-swipe' ) ) return true;\r\n\t\t\ttarget = target.parentNode;\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Handler for the 'touchstart' event, enables support for\r\n\t * swipe and pinch gestures.\r\n\t *\r\n\t * @param {object} event\r\n\t */\r\n\tonTouchStart( event ) {\r\n\r\n\t\tif( this.isSwipePrevented( event.target ) ) return true;\r\n\r\n\t\tthis.touchStartX = event.touches[0].clientX;\r\n\t\tthis.touchStartY = event.touches[0].clientY;\r\n\t\tthis.touchStartCount = event.touches.length;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Handler for the 'touchmove' event.\r\n\t *\r\n\t * @param {object} event\r\n\t */\r\n\tonTouchMove( event ) {\r\n\r\n\t\tif( this.isSwipePrevented( event.target ) ) return true;\r\n\r\n\t\tlet config = this.Reveal.getConfig();\r\n\r\n\t\t// Each touch should only trigger one action\r\n\t\tif( !this.touchCaptured ) {\r\n\t\t\tthis.Reveal.onUserInput( event );\r\n\r\n\t\t\tlet currentX = event.touches[0].clientX;\r\n\t\t\tlet currentY = event.touches[0].clientY;\r\n\r\n\t\t\t// There was only one touch point, look for a swipe\r\n\t\t\tif( event.touches.length === 1 && this.touchStartCount !== 2 ) {\r\n\r\n\t\t\t\tlet availableRoutes = this.Reveal.availableRoutes({ includeFragments: true });\r\n\r\n\t\t\t\tlet deltaX = currentX - this.touchStartX,\r\n\t\t\t\t\tdeltaY = currentY - this.touchStartY;\r\n\r\n\t\t\t\tif( deltaX > SWIPE_THRESHOLD && Math.abs( deltaX ) > Math.abs( deltaY ) ) {\r\n\t\t\t\t\tthis.touchCaptured = true;\r\n\t\t\t\t\tif( config.navigationMode === 'linear' ) {\r\n\t\t\t\t\t\tif( config.rtl ) {\r\n\t\t\t\t\t\t\tthis.Reveal.next();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\tthis.Reveal.prev();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tthis.Reveal.left();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\telse if( deltaX < -SWIPE_THRESHOLD && Math.abs( deltaX ) > Math.abs( deltaY ) ) {\r\n\t\t\t\t\tthis.touchCaptured = true;\r\n\t\t\t\t\tif( config.navigationMode === 'linear' ) {\r\n\t\t\t\t\t\tif( config.rtl ) {\r\n\t\t\t\t\t\t\tthis.Reveal.prev();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\tthis.Reveal.next();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tthis.Reveal.right();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\telse if( deltaY > SWIPE_THRESHOLD && availableRoutes.up ) {\r\n\t\t\t\t\tthis.touchCaptured = true;\r\n\t\t\t\t\tif( config.navigationMode === 'linear' ) {\r\n\t\t\t\t\t\tthis.Reveal.prev();\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tthis.Reveal.up();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\telse if( deltaY < -SWIPE_THRESHOLD && availableRoutes.down ) {\r\n\t\t\t\t\tthis.touchCaptured = true;\r\n\t\t\t\t\tif( config.navigationMode === 'linear' ) {\r\n\t\t\t\t\t\tthis.Reveal.next();\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tthis.Reveal.down();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// If we're embedded, only block touch events if they have\r\n\t\t\t\t// triggered an action\r\n\t\t\t\tif( config.embedded ) {\r\n\t\t\t\t\tif( this.touchCaptured || this.Reveal.isVerticalSlide() ) {\r\n\t\t\t\t\t\tevent.preventDefault();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\t// Not embedded? Block them all to avoid needless tossing\r\n\t\t\t\t// around of the viewport in iOS\r\n\t\t\t\telse {\r\n\t\t\t\t\tevent.preventDefault();\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\t\t}\r\n\t\t// There's a bug with swiping on some Android devices unless\r\n\t\t// the default action is always prevented\r\n\t\telse if( isAndroid ) {\r\n\t\t\tevent.preventDefault();\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Handler for the 'touchend' event.\r\n\t *\r\n\t * @param {object} event\r\n\t */\r\n\tonTouchEnd( event ) {\r\n\r\n\t\tthis.touchCaptured = false;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Convert pointer down to touch start.\r\n\t *\r\n\t * @param {object} event\r\n\t */\r\n\tonPointerDown( event ) {\r\n\r\n\t\tif( event.pointerType === event.MSPOINTER_TYPE_TOUCH || event.pointerType === \"touch\" ) {\r\n\t\t\tevent.touches = [{ clientX: event.clientX, clientY: event.clientY }];\r\n\t\t\tthis.onTouchStart( event );\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Convert pointer move to touch move.\r\n\t *\r\n\t * @param {object} event\r\n\t */\r\n\tonPointerMove( event ) {\r\n\r\n\t\tif( event.pointerType === event.MSPOINTER_TYPE_TOUCH || event.pointerType === \"touch\" ) {\r\n\t\t\tevent.touches = [{ clientX: event.clientX, clientY: event.clientY }];\r\n\t\t\tthis.onTouchMove( event );\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Convert pointer up to touch end.\r\n\t *\r\n\t * @param {object} event\r\n\t */\r\n\tonPointerUp( event ) {\r\n\r\n\t\tif( event.pointerType === event.MSPOINTER_TYPE_TOUCH || event.pointerType === \"touch\" ) {\r\n\t\t\tevent.touches = [{ clientX: event.clientX, clientY: event.clientY }];\r\n\t\t\tthis.onTouchEnd( event );\r\n\t\t}\r\n\r\n\t}\r\n\r\n}","import { closest } from '../utils/util.js'\r\n\r\n/**\r\n * Manages focus when a presentation is embedded. This\r\n * helps us only capture keyboard from the presentation\r\n * a user is currently interacting with in a page where\r\n * multiple presentations are embedded.\r\n */\r\n\r\nconst STATE_FOCUS = 'focus';\r\nconst STATE_BLUR = 'blur';\r\n\r\nexport default class Focus {\r\n\r\n\tconstructor( Reveal ) {\r\n\r\n\t\tthis.Reveal = Reveal;\r\n\r\n\t\tthis.onRevealPointerDown = this.onRevealPointerDown.bind( this );\r\n\t\tthis.onDocumentPointerDown = this.onDocumentPointerDown.bind( this );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Called when the reveal.js config is updated.\r\n\t */\r\n\tconfigure( config, oldConfig ) {\r\n\r\n\t\tif( config.embedded ) {\r\n\t\t\tthis.blur();\r\n\t\t}\r\n\t\telse {\r\n\t\t\tthis.focus();\r\n\t\t\tthis.unbind();\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tbind() {\r\n\r\n\t\tif( this.Reveal.getConfig().embedded ) {\r\n\t\t\tthis.Reveal.getRevealElement().addEventListener( 'pointerdown', this.onRevealPointerDown, false );\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tunbind() {\r\n\r\n\t\tthis.Reveal.getRevealElement().removeEventListener( 'pointerdown', this.onRevealPointerDown, false );\r\n\t\tdocument.removeEventListener( 'pointerdown', this.onDocumentPointerDown, false );\r\n\r\n\t}\r\n\r\n\tfocus() {\r\n\r\n\t\tif( this.state !== STATE_FOCUS ) {\r\n\t\t\tthis.Reveal.getRevealElement().classList.add( 'focused' );\r\n\t\t\tdocument.addEventListener( 'pointerdown', this.onDocumentPointerDown, false );\r\n\t\t}\r\n\r\n\t\tthis.state = STATE_FOCUS;\r\n\r\n\t}\r\n\r\n\tblur() {\r\n\r\n\t\tif( this.state !== STATE_BLUR ) {\r\n\t\t\tthis.Reveal.getRevealElement().classList.remove( 'focused' );\r\n\t\t\tdocument.removeEventListener( 'pointerdown', this.onDocumentPointerDown, false );\r\n\t\t}\r\n\r\n\t\tthis.state = STATE_BLUR;\r\n\r\n\t}\r\n\r\n\tisFocused() {\r\n\r\n\t\treturn this.state === STATE_FOCUS;\r\n\r\n\t}\r\n\r\n\tdestroy() {\r\n\r\n\t\tthis.Reveal.getRevealElement().classList.remove( 'focused' );\r\n\r\n\t}\r\n\r\n\tonRevealPointerDown( event ) {\r\n\r\n\t\tthis.focus();\r\n\r\n\t}\r\n\r\n\tonDocumentPointerDown( event ) {\r\n\r\n\t\tlet revealElement = closest( event.target, '.reveal' );\r\n\t\tif( !revealElement || revealElement !== this.Reveal.getRevealElement() ) {\r\n\t\t\tthis.blur();\r\n\t\t}\r\n\r\n\t}\r\n\r\n}","/**\r\n * Handles the showing of speaker notes\r\n */\r\nexport default class Notes {\r\n\r\n\tconstructor( Reveal ) {\r\n\r\n\t\tthis.Reveal = Reveal;\r\n\r\n\t}\r\n\r\n\trender() {\r\n\r\n\t\tthis.element = document.createElement( 'div' );\r\n\t\tthis.element.className = 'speaker-notes';\r\n\t\tthis.element.setAttribute( 'data-prevent-swipe', '' );\r\n\t\tthis.element.setAttribute( 'tabindex', '0' );\r\n\t\tthis.Reveal.getRevealElement().appendChild( this.element );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Called when the reveal.js config is updated.\r\n\t */\r\n\tconfigure( config, oldConfig ) {\r\n\r\n\t\tif( config.showNotes ) {\r\n\t\t\tthis.element.setAttribute( 'data-layout', typeof config.showNotes === 'string' ? config.showNotes : 'inline' );\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Pick up notes from the current slide and display them\r\n\t * to the viewer.\r\n\t *\r\n\t * @see {@link config.showNotes}\r\n\t */\r\n\tupdate() {\r\n\r\n\t\tif( this.Reveal.getConfig().showNotes &&\r\n\t\t\tthis.element && this.Reveal.getCurrentSlide() &&\r\n\t\t\t!this.Reveal.isScrollView() &&\r\n\t\t\t!this.Reveal.isPrintView()\r\n\t\t) {\r\n\t\t\tthis.element.innerHTML = this.getSlideNotes() || 'No notes on this slide.';\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Updates the visibility of the speaker notes sidebar that\r\n\t * is used to share annotated slides. The notes sidebar is\r\n\t * only visible if showNotes is true and there are notes on\r\n\t * one or more slides in the deck.\r\n\t */\r\n\tupdateVisibility() {\r\n\r\n\t\tif( this.Reveal.getConfig().showNotes &&\r\n\t\t\tthis.hasNotes() &&\r\n\t\t\t!this.Reveal.isScrollView() &&\r\n\t\t\t!this.Reveal.isPrintView()\r\n\t\t) {\r\n\t\t\tthis.Reveal.getRevealElement().classList.add( 'show-notes' );\r\n\t\t}\r\n\t\telse {\r\n\t\t\tthis.Reveal.getRevealElement().classList.remove( 'show-notes' );\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Checks if there are speaker notes for ANY slide in the\r\n\t * presentation.\r\n\t */\r\n\thasNotes() {\r\n\r\n\t\treturn this.Reveal.getSlidesElement().querySelectorAll( '[data-notes], aside.notes' ).length > 0;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Checks if this presentation is running inside of the\r\n\t * speaker notes window.\r\n\t *\r\n\t * @return {boolean}\r\n\t */\r\n\tisSpeakerNotesWindow() {\r\n\r\n\t\treturn !!window.location.search.match( /receiver/gi );\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Retrieves the speaker notes from a slide. Notes can be\r\n\t * defined in two ways:\r\n\t * 1. As a data-notes attribute on the slide
\r\n\t * 2. With