├── .gitignore ├── LICENSE.md ├── Procfile ├── README ├── import_slides.sh ├── index.html ├── instructors ├── index.html └── slides │ ├── slides.md │ └── static │ ├── css │ ├── print │ │ └── paper.css │ ├── reveal.css │ └── theme │ │ ├── black.css │ │ └── simple.css │ ├── js │ ├── jquery-2.1.3.min.js │ └── reveal.js │ ├── lib │ ├── css │ │ └── zenburn.css │ ├── font │ │ └── source-sans-pro │ │ │ ├── source-sans-pro-italic.woff │ │ │ ├── source-sans-pro-regular.woff │ │ │ ├── source-sans-pro-semibold.woff │ │ │ └── source-sans-pro.css │ └── js │ │ └── head.min.js │ ├── plugin │ ├── markdown │ │ ├── markdown.js │ │ └── marked.js │ ├── notes │ │ ├── notes.html │ │ └── notes.js │ └── zoom-js │ │ └── zoom.js │ └── slides.html ├── requirements.txt ├── schedule ├── .gitignore └── index.html ├── static ├── bootstrap-4.1.3-dist │ ├── css │ │ ├── .DS_Store │ │ ├── bootstrap-grid.css │ │ ├── bootstrap-grid.css.map │ │ ├── bootstrap-grid.min.css │ │ ├── bootstrap-grid.min.css.map │ │ ├── bootstrap-reboot.css │ │ ├── bootstrap-reboot.css.map │ │ ├── bootstrap-reboot.min.css │ │ ├── bootstrap-reboot.min.css.map │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ ├── bootstrap.min.css │ │ └── bootstrap.min.css.map │ └── js │ │ ├── bootstrap.bundle.js │ │ ├── bootstrap.bundle.js.map │ │ ├── bootstrap.bundle.min.js │ │ ├── bootstrap.bundle.min.js.map │ │ ├── bootstrap.js │ │ ├── bootstrap.js.map │ │ ├── bootstrap.min.js │ │ └── bootstrap.min.js.map ├── images │ └── IMG_9232.jpg ├── jquery-2.1.3.js └── pets.css └── student-handout ├── slides.md └── static ├── css ├── print │ └── paper.css ├── reveal.css └── theme │ ├── black.css │ └── simple.css ├── js ├── jquery-2.1.3.min.js └── reveal.js ├── lib ├── css │ └── zenburn.css ├── font │ └── source-sans-pro │ │ ├── source-sans-pro-italic.woff │ │ ├── source-sans-pro-regular.woff │ │ ├── source-sans-pro-semibold.woff │ │ └── source-sans-pro.css └── js │ └── head.min.js ├── plugin ├── markdown │ ├── markdown.js │ └── marked.js ├── notes │ ├── notes.html │ └── notes.js └── zoom-js │ └── zoom.js └── slides.html /.gitignore: -------------------------------------------------------------------------------- 1 | *# 2 | .idea 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: python -m http.server $PORT 2 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This repository contains the lab material for the tutorial Web Application Security with Django. 2 | 3 | This tutorial was presented at PyCon 2015 and 2019, and DjangoCon 2018 and 2019. 4 | 5 | The PyCon versions were recorded and the videos can be found here: 6 | 7 | PyCon 2019 with Jacinda Shelly: https://www.youtube.com/watch?v=8W4MGggwgfM 8 | 9 | PyCon 2015 with Asheesh Laroia, Jacky Chang, and Nicole Zuckerman: https://www.youtube.com/watch?v=f9XVNIeRxUo 10 | -------------------------------------------------------------------------------- /import_slides.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Like 'use strict'; but for bash! 4 | set -euo pipefail 5 | 6 | # This script will import slides from the Hacker Slides instance that 7 | # Asheesh has been using into a directory structure that can live in 8 | # this repo. 9 | 10 | mkdir -p student-handout 11 | pushd student-handout 12 | 13 | # First, nab the slides. 14 | wget --header "Cookie: $2" "https://$1/slides.md" 15 | 16 | # Then, nab the static directory, and all that it references. 17 | mkdir -p static 18 | pushd static 19 | wget -nH --cut-dirs=1 --mirror --no-parent --header "Cookie: $2" "https://$1/static/slides.html" || true # OK if this fails. 20 | 21 | # Grab these extra dependencies. 22 | for thing in "plugin/markdown/markdown.js" "plugin/markdown/marked.js" "css/print/paper.css" "plugin/zoom-js/zoom.js" "plugin/notes/notes.js" "plugin/notes/notes.html" 23 | do 24 | wget -nH --cut-dirs=1 --mirror --no-parent --header "Cookie: $2" "https://$1/static/$thing" || true # OK if this fails. 25 | done 26 | 27 | # Prepare this for git commit, but let the user be the one to actually 28 | # commit it. 29 | popd; popd 30 | git add . 31 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 |

Welcome to pettwitter

12 |
13 |
14 |

About this site

15 | 16 |

This is a site to help you prepare for a DjangoCon 2019 tutorial called 17 | Web Application Security with Django. 18 |

19 | 20 |
21 |
22 |

Lab material

23 |
24 | 25 | 26 |
27 | 28 | 29 |
30 | 31 |
32 |
33 |

Tutorial Preparation

34 | 35 |

1. Bring a computer

36 | 37 |

2. Join your Slack channel.

38 | 39 |

By the time you see this page, you should have already received 40 | an invitation to our Slack workspace. If you haven't, email Jacinda. 41 |

42 | 43 |

44 | You should have access to a few public channels and exactly one private group channel for your group. 45 | Let Jacinda know if this isn't the case. 46 |

47 | 48 |

Small group environments


49 | 50 |

Group #1 Target Environment

51 |

Group #2 Target Environment

52 |

Group #3 Target Environment

53 |

Group #4 Target Environment

54 |

Group #5 Target Environment

55 |

Group #6 Target Environment

56 | 57 |

Link to the code

58 |

Code on Github

59 | 60 |

Disclaimer

61 |

This site has no relationship with with Twitter, Inc. 62 |

63 |

PS: Where's the source code for the documentation (this site)?

64 | 65 |

Tutorial instructions 66 | source code.

67 |
68 |
69 |
70 | 71 | 72 | -------------------------------------------------------------------------------- /instructors/index.html: -------------------------------------------------------------------------------- 1 |

2 | There's a 3 | 4 | secret slides link 5 | 6 | just for instructors. 7 |

8 | -------------------------------------------------------------------------------- /instructors/slides/static/css/print/paper.css: -------------------------------------------------------------------------------- 1 | /* Default Print Stylesheet Template 2 | by Rob Glazebrook of CSSnewbie.com 3 | Last Updated: June 4, 2008 4 | 5 | Feel free (nay, compelled) to edit, append, and 6 | manipulate this file as you see fit. */ 7 | 8 | 9 | @media print { 10 | 11 | /* SECTION 1: Set default width, margin, float, and 12 | background. This prevents elements from extending 13 | beyond the edge of the printed page, and prevents 14 | unnecessary background images from printing */ 15 | html { 16 | background: #fff; 17 | width: auto; 18 | height: auto; 19 | overflow: visible; 20 | } 21 | body { 22 | background: #fff; 23 | font-size: 20pt; 24 | width: auto; 25 | height: auto; 26 | border: 0; 27 | margin: 0 5%; 28 | padding: 0; 29 | overflow: visible; 30 | float: none !important; 31 | } 32 | 33 | /* SECTION 2: Remove any elements not needed in print. 34 | This would include navigation, ads, sidebars, etc. */ 35 | .nestedarrow, 36 | .controls, 37 | .fork-reveal, 38 | .share-reveal, 39 | .state-background, 40 | .reveal .progress, 41 | .reveal .backgrounds { 42 | display: none !important; 43 | } 44 | 45 | /* SECTION 3: Set body font face, size, and color. 46 | Consider using a serif font for readability. */ 47 | body, p, td, li, div { 48 | font-size: 20pt!important; 49 | font-family: Georgia, "Times New Roman", Times, serif !important; 50 | color: #000; 51 | } 52 | 53 | /* SECTION 4: Set heading font face, sizes, and color. 54 | Differentiate your headings from your body text. 55 | Perhaps use a large sans-serif for distinction. */ 56 | h1,h2,h3,h4,h5,h6 { 57 | color: #000!important; 58 | height: auto; 59 | line-height: normal; 60 | font-family: Georgia, "Times New Roman", Times, serif !important; 61 | text-shadow: 0 0 0 #000 !important; 62 | text-align: left; 63 | letter-spacing: normal; 64 | } 65 | /* Need to reduce the size of the fonts for printing */ 66 | h1 { font-size: 28pt !important; } 67 | h2 { font-size: 24pt !important; } 68 | h3 { font-size: 22pt !important; } 69 | h4 { font-size: 22pt !important; font-variant: small-caps; } 70 | h5 { font-size: 21pt !important; } 71 | h6 { font-size: 20pt !important; font-style: italic; } 72 | 73 | /* SECTION 5: Make hyperlinks more usable. 74 | Ensure links are underlined, and consider appending 75 | the URL to the end of the link for usability. */ 76 | a:link, 77 | a:visited { 78 | color: #000 !important; 79 | font-weight: bold; 80 | text-decoration: underline; 81 | } 82 | /* 83 | .reveal a:link:after, 84 | .reveal a:visited:after { 85 | content: " (" attr(href) ") "; 86 | color: #222 !important; 87 | font-size: 90%; 88 | } 89 | */ 90 | 91 | 92 | /* SECTION 6: more reveal.js specific additions by @skypanther */ 93 | ul, ol, div, p { 94 | visibility: visible; 95 | position: static; 96 | width: auto; 97 | height: auto; 98 | display: block; 99 | overflow: visible; 100 | margin: 0; 101 | text-align: left !important; 102 | } 103 | .reveal pre, 104 | .reveal table { 105 | margin-left: 0; 106 | margin-right: 0; 107 | } 108 | .reveal pre code { 109 | padding: 20px; 110 | border: 1px solid #ddd; 111 | } 112 | .reveal blockquote { 113 | margin: 20px 0; 114 | } 115 | .reveal .slides { 116 | position: static !important; 117 | width: auto !important; 118 | height: auto !important; 119 | 120 | left: 0 !important; 121 | top: 0 !important; 122 | margin-left: 0 !important; 123 | margin-top: 0 !important; 124 | padding: 0 !important; 125 | zoom: 1 !important; 126 | 127 | overflow: visible !important; 128 | display: block !important; 129 | 130 | text-align: left !important; 131 | -webkit-perspective: none; 132 | -moz-perspective: none; 133 | -ms-perspective: none; 134 | perspective: none; 135 | 136 | -webkit-perspective-origin: 50% 50%; 137 | -moz-perspective-origin: 50% 50%; 138 | -ms-perspective-origin: 50% 50%; 139 | perspective-origin: 50% 50%; 140 | } 141 | .reveal .slides section { 142 | visibility: visible !important; 143 | position: static !important; 144 | width: 100% !important; 145 | height: auto !important; 146 | display: block !important; 147 | overflow: visible !important; 148 | 149 | left: 0 !important; 150 | top: 0 !important; 151 | margin-left: 0 !important; 152 | margin-top: 0 !important; 153 | padding: 60px 20px !important; 154 | z-index: auto !important; 155 | 156 | opacity: 1 !important; 157 | 158 | page-break-after: always !important; 159 | 160 | -webkit-transform-style: flat !important; 161 | -moz-transform-style: flat !important; 162 | -ms-transform-style: flat !important; 163 | transform-style: flat !important; 164 | 165 | -webkit-transform: none !important; 166 | -moz-transform: none !important; 167 | -ms-transform: none !important; 168 | transform: none !important; 169 | 170 | -webkit-transition: none !important; 171 | -moz-transition: none !important; 172 | -ms-transition: none !important; 173 | transition: none !important; 174 | } 175 | .reveal .slides section.stack { 176 | padding: 0 !important; 177 | } 178 | .reveal section:last-of-type { 179 | page-break-after: avoid !important; 180 | } 181 | .reveal section .fragment { 182 | opacity: 1 !important; 183 | visibility: visible !important; 184 | 185 | -webkit-transform: none !important; 186 | -moz-transform: none !important; 187 | -ms-transform: none !important; 188 | transform: none !important; 189 | } 190 | .reveal section img { 191 | display: block; 192 | margin: 15px 0px; 193 | background: rgba(255,255,255,1); 194 | border: 1px solid #666; 195 | box-shadow: none; 196 | } 197 | 198 | .reveal section small { 199 | font-size: 0.8em; 200 | } 201 | 202 | } -------------------------------------------------------------------------------- /instructors/slides/static/css/theme/black.css: -------------------------------------------------------------------------------- 1 | @import url(../../lib/font/source-sans-pro/source-sans-pro.css); 2 | /** 3 | * Black theme for reveal.js. This is the opposite of the 'white' theme. 4 | * 5 | * Copyright (C) 2015 Hakim El Hattab, http://hakim.se 6 | */ 7 | section.has-light-background, section.has-light-background h1, section.has-light-background h2, section.has-light-background h3, section.has-light-background h4, section.has-light-background h5, section.has-light-background h6 { 8 | color: #222; } 9 | 10 | /********************************************* 11 | * GLOBAL STYLES 12 | *********************************************/ 13 | body { 14 | background: #222; 15 | background-color: #222; } 16 | 17 | .reveal { 18 | font-family: 'Source Sans Pro', Helvetica, sans-serif; 19 | font-size: 38px; 20 | font-weight: normal; 21 | color: #fff; } 22 | 23 | ::selection { 24 | color: #fff; 25 | background: #bee4fd; 26 | text-shadow: none; } 27 | 28 | .reveal .slides > section, .reveal .slides > section > section { 29 | line-height: 1.3; 30 | font-weight: inherit; } 31 | 32 | /********************************************* 33 | * HEADERS 34 | *********************************************/ 35 | .reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6 { 36 | margin: 0 0 20px 0; 37 | color: #fff; 38 | font-family: 'Source Sans Pro', Helvetica, sans-serif; 39 | font-weight: 600; 40 | line-height: 1.2; 41 | letter-spacing: normal; 42 | text-transform: uppercase; 43 | text-shadow: none; 44 | word-wrap: break-word; } 45 | 46 | .reveal h1 { 47 | font-size: 2.5em; } 48 | 49 | .reveal h2 { 50 | font-size: 1.6em; } 51 | 52 | .reveal h3 { 53 | font-size: 1.3em; } 54 | 55 | .reveal h4 { 56 | font-size: 1em; } 57 | 58 | .reveal h1 { 59 | text-shadow: none; } 60 | 61 | /********************************************* 62 | * OTHER 63 | *********************************************/ 64 | .reveal p { 65 | margin: 20px 0; 66 | line-height: 1.3; } 67 | 68 | /* Ensure certain elements are never larger than the slide itself */ 69 | .reveal img, .reveal video, .reveal iframe { 70 | max-width: 95%; 71 | max-height: 95%; } 72 | 73 | .reveal strong, .reveal b { 74 | font-weight: bold; } 75 | 76 | .reveal em { 77 | font-style: italic; } 78 | 79 | .reveal ol, .reveal dl, .reveal ul { 80 | display: inline-block; 81 | text-align: left; 82 | margin: 0 0 0 1em; } 83 | 84 | .reveal ol { 85 | list-style-type: decimal; } 86 | 87 | .reveal ul { 88 | list-style-type: disc; } 89 | 90 | .reveal ul ul { 91 | list-style-type: square; } 92 | 93 | .reveal ul ul ul { 94 | list-style-type: circle; } 95 | 96 | .reveal ul ul, .reveal ul ol, .reveal ol ol, .reveal ol ul { 97 | display: block; 98 | margin-left: 40px; } 99 | 100 | .reveal dt { 101 | font-weight: bold; } 102 | 103 | .reveal dd { 104 | margin-left: 40px; } 105 | 106 | .reveal q, .reveal blockquote { 107 | quotes: none; } 108 | 109 | .reveal blockquote { 110 | display: block; 111 | position: relative; 112 | width: 70%; 113 | margin: 20px auto; 114 | padding: 5px; 115 | font-style: italic; 116 | background: rgba(255, 255, 255, 0.05); 117 | box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.2); } 118 | 119 | .reveal blockquote p:first-child, .reveal blockquote p:last-child { 120 | display: inline-block; } 121 | 122 | .reveal q { 123 | font-style: italic; } 124 | 125 | .reveal pre { 126 | display: block; 127 | position: relative; 128 | width: 90%; 129 | margin: 20px auto; 130 | text-align: left; 131 | font-size: 0.55em; 132 | font-family: monospace; 133 | line-height: 1.2em; 134 | word-wrap: break-word; 135 | box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.3); } 136 | 137 | .reveal code { 138 | font-family: monospace; } 139 | 140 | .reveal pre code { 141 | display: block; 142 | padding: 5px; 143 | overflow: auto; 144 | max-height: 400px; 145 | word-wrap: normal; 146 | background: #3F3F3F; 147 | color: #DCDCDC; } 148 | 149 | .reveal table { 150 | margin: auto; 151 | border-collapse: collapse; 152 | border-spacing: 0; } 153 | 154 | .reveal table th { 155 | font-weight: bold; } 156 | 157 | .reveal table th, .reveal table td { 158 | text-align: left; 159 | padding: 0.2em 0.5em 0.2em 0.5em; 160 | border-bottom: 1px solid; } 161 | 162 | .reveal table tr:last-child td { 163 | border-bottom: none; } 164 | 165 | .reveal sup { 166 | vertical-align: super; } 167 | 168 | .reveal sub { 169 | vertical-align: sub; } 170 | 171 | .reveal small { 172 | display: inline-block; 173 | font-size: 0.6em; 174 | line-height: 1.2em; 175 | vertical-align: top; } 176 | 177 | .reveal small * { 178 | vertical-align: top; } 179 | 180 | /********************************************* 181 | * LINKS 182 | *********************************************/ 183 | .reveal a { 184 | color: #42affa; 185 | text-decoration: none; 186 | -webkit-transition: color 0.15s ease; 187 | -moz-transition: color 0.15s ease; 188 | transition: color 0.15s ease; } 189 | 190 | .reveal a:hover { 191 | color: #8dcffc; 192 | text-shadow: none; 193 | border: none; } 194 | 195 | .reveal .roll span:after { 196 | color: #fff; 197 | background: #068ee9; } 198 | 199 | /********************************************* 200 | * IMAGES 201 | *********************************************/ 202 | .reveal section img { 203 | margin: 15px 0px; 204 | background: rgba(255, 255, 255, 0.12); 205 | border: 4px solid #fff; 206 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); } 207 | 208 | .reveal a img { 209 | -webkit-transition: all 0.15s linear; 210 | -moz-transition: all 0.15s linear; 211 | transition: all 0.15s linear; } 212 | 213 | .reveal a:hover img { 214 | background: rgba(255, 255, 255, 0.2); 215 | border-color: #42affa; 216 | box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); } 217 | 218 | /********************************************* 219 | * NAVIGATION CONTROLS 220 | *********************************************/ 221 | .reveal .controls div.navigate-left, .reveal .controls div.navigate-left.enabled { 222 | border-right-color: #42affa; } 223 | 224 | .reveal .controls div.navigate-right, .reveal .controls div.navigate-right.enabled { 225 | border-left-color: #42affa; } 226 | 227 | .reveal .controls div.navigate-up, .reveal .controls div.navigate-up.enabled { 228 | border-bottom-color: #42affa; } 229 | 230 | .reveal .controls div.navigate-down, .reveal .controls div.navigate-down.enabled { 231 | border-top-color: #42affa; } 232 | 233 | .reveal .controls div.navigate-left.enabled:hover { 234 | border-right-color: #8dcffc; } 235 | 236 | .reveal .controls div.navigate-right.enabled:hover { 237 | border-left-color: #8dcffc; } 238 | 239 | .reveal .controls div.navigate-up.enabled:hover { 240 | border-bottom-color: #8dcffc; } 241 | 242 | .reveal .controls div.navigate-down.enabled:hover { 243 | border-top-color: #8dcffc; } 244 | 245 | /********************************************* 246 | * PROGRESS BAR 247 | *********************************************/ 248 | .reveal .progress { 249 | background: rgba(0, 0, 0, 0.2); } 250 | 251 | .reveal .progress span { 252 | background: #42affa; 253 | -webkit-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 254 | -moz-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 255 | transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); } 256 | 257 | /********************************************* 258 | * SLIDE NUMBER 259 | *********************************************/ 260 | .reveal .slide-number { 261 | color: #42affa; } 262 | -------------------------------------------------------------------------------- /instructors/slides/static/css/theme/simple.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=News+Cycle:400,700); 2 | @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); 3 | /** 4 | * A simple theme for reveal.js presentations, similar 5 | * to the default theme. The accent color is darkblue. 6 | * 7 | * This theme is Copyright (C) 2012 Owen Versteeg, https://github.com/StereotypicalApps. It is MIT licensed. 8 | * reveal.js is Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se 9 | */ 10 | /********************************************* 11 | * GLOBAL STYLES 12 | *********************************************/ 13 | body { 14 | background: #fff; 15 | background-color: #fff; } 16 | 17 | .reveal { 18 | font-family: 'Lato', sans-serif; 19 | font-size: 36px; 20 | font-weight: normal; 21 | color: #000; } 22 | 23 | ::selection { 24 | color: #fff; 25 | background: rgba(0, 0, 0, 0.99); 26 | text-shadow: none; } 27 | 28 | .reveal .slides > section, .reveal .slides > section > section { 29 | line-height: 1.3; 30 | font-weight: inherit; } 31 | 32 | /********************************************* 33 | * HEADERS 34 | *********************************************/ 35 | .reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6 { 36 | margin: 0 0 20px 0; 37 | color: #000; 38 | font-family: 'News Cycle', Impact, sans-serif; 39 | font-weight: normal; 40 | line-height: 1.2; 41 | letter-spacing: normal; 42 | text-transform: none; 43 | text-shadow: none; 44 | word-wrap: break-word; } 45 | 46 | .reveal h1 { 47 | font-size: 3.77em; } 48 | 49 | .reveal h2 { 50 | font-size: 2em; } 51 | 52 | .reveal h3 { 53 | font-size: 1.55em; } 54 | 55 | .reveal h4 { 56 | font-size: 1em; } 57 | 58 | .reveal h1 { 59 | text-shadow: none; } 60 | 61 | /********************************************* 62 | * OTHER 63 | *********************************************/ 64 | .reveal p { 65 | margin: 20px 0; 66 | line-height: 1.3; } 67 | 68 | /* Ensure certain elements are never larger than the slide itself */ 69 | .reveal img, .reveal video, .reveal iframe { 70 | max-width: 95%; 71 | max-height: 95%; } 72 | 73 | .reveal strong, .reveal b { 74 | font-weight: bold; } 75 | 76 | .reveal em { 77 | font-style: italic; } 78 | 79 | .reveal ol, .reveal dl, .reveal ul { 80 | display: inline-block; 81 | text-align: left; 82 | margin: 0 0 0 1em; } 83 | 84 | .reveal ol { 85 | list-style-type: decimal; } 86 | 87 | .reveal ul { 88 | list-style-type: disc; } 89 | 90 | .reveal ul ul { 91 | list-style-type: square; } 92 | 93 | .reveal ul ul ul { 94 | list-style-type: circle; } 95 | 96 | .reveal ul ul, .reveal ul ol, .reveal ol ol, .reveal ol ul { 97 | display: block; 98 | margin-left: 40px; } 99 | 100 | .reveal dt { 101 | font-weight: bold; } 102 | 103 | .reveal dd { 104 | margin-left: 40px; } 105 | 106 | .reveal q, .reveal blockquote { 107 | quotes: none; } 108 | 109 | .reveal blockquote { 110 | display: block; 111 | position: relative; 112 | width: 70%; 113 | margin: 20px auto; 114 | padding: 5px; 115 | font-style: italic; 116 | background: rgba(255, 255, 255, 0.05); 117 | box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.2); } 118 | 119 | .reveal blockquote p:first-child, .reveal blockquote p:last-child { 120 | display: inline-block; } 121 | 122 | .reveal q { 123 | font-style: italic; } 124 | 125 | .reveal pre { 126 | display: block; 127 | position: relative; 128 | width: 90%; 129 | margin: 20px auto; 130 | text-align: left; 131 | font-size: 0.55em; 132 | font-family: monospace; 133 | line-height: 1.2em; 134 | word-wrap: break-word; 135 | box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.3); } 136 | 137 | .reveal code { 138 | font-family: monospace; } 139 | 140 | .reveal pre code { 141 | display: block; 142 | padding: 5px; 143 | overflow: auto; 144 | max-height: 400px; 145 | word-wrap: normal; 146 | background: #3F3F3F; 147 | color: #DCDCDC; } 148 | 149 | .reveal table { 150 | margin: auto; 151 | border-collapse: collapse; 152 | border-spacing: 0; } 153 | 154 | .reveal table th { 155 | font-weight: bold; } 156 | 157 | .reveal table th, .reveal table td { 158 | text-align: left; 159 | padding: 0.2em 0.5em 0.2em 0.5em; 160 | border-bottom: 1px solid; } 161 | 162 | .reveal table tr:last-child td { 163 | border-bottom: none; } 164 | 165 | .reveal sup { 166 | vertical-align: super; } 167 | 168 | .reveal sub { 169 | vertical-align: sub; } 170 | 171 | .reveal small { 172 | display: inline-block; 173 | font-size: 0.6em; 174 | line-height: 1.2em; 175 | vertical-align: top; } 176 | 177 | .reveal small * { 178 | vertical-align: top; } 179 | 180 | /********************************************* 181 | * LINKS 182 | *********************************************/ 183 | .reveal a { 184 | color: #00008B; 185 | text-decoration: none; 186 | -webkit-transition: color 0.15s ease; 187 | -moz-transition: color 0.15s ease; 188 | transition: color 0.15s ease; } 189 | 190 | .reveal a:hover { 191 | color: #0000f1; 192 | text-shadow: none; 193 | border: none; } 194 | 195 | .reveal .roll span:after { 196 | color: #fff; 197 | background: #00003f; } 198 | 199 | /********************************************* 200 | * IMAGES 201 | *********************************************/ 202 | .reveal section img { 203 | margin: 15px 0px; 204 | background: rgba(255, 255, 255, 0.12); 205 | border: 4px solid #000; 206 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); } 207 | 208 | .reveal a img { 209 | -webkit-transition: all 0.15s linear; 210 | -moz-transition: all 0.15s linear; 211 | transition: all 0.15s linear; } 212 | 213 | .reveal a:hover img { 214 | background: rgba(255, 255, 255, 0.2); 215 | border-color: #00008B; 216 | box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); } 217 | 218 | /********************************************* 219 | * NAVIGATION CONTROLS 220 | *********************************************/ 221 | .reveal .controls div.navigate-left, .reveal .controls div.navigate-left.enabled { 222 | border-right-color: #00008B; } 223 | 224 | .reveal .controls div.navigate-right, .reveal .controls div.navigate-right.enabled { 225 | border-left-color: #00008B; } 226 | 227 | .reveal .controls div.navigate-up, .reveal .controls div.navigate-up.enabled { 228 | border-bottom-color: #00008B; } 229 | 230 | .reveal .controls div.navigate-down, .reveal .controls div.navigate-down.enabled { 231 | border-top-color: #00008B; } 232 | 233 | .reveal .controls div.navigate-left.enabled:hover { 234 | border-right-color: #0000f1; } 235 | 236 | .reveal .controls div.navigate-right.enabled:hover { 237 | border-left-color: #0000f1; } 238 | 239 | .reveal .controls div.navigate-up.enabled:hover { 240 | border-bottom-color: #0000f1; } 241 | 242 | .reveal .controls div.navigate-down.enabled:hover { 243 | border-top-color: #0000f1; } 244 | 245 | /********************************************* 246 | * PROGRESS BAR 247 | *********************************************/ 248 | .reveal .progress { 249 | background: rgba(0, 0, 0, 0.2); } 250 | 251 | .reveal .progress span { 252 | background: #00008B; 253 | -webkit-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 254 | -moz-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 255 | transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); } 256 | 257 | /********************************************* 258 | * SLIDE NUMBER 259 | *********************************************/ 260 | .reveal .slide-number { 261 | color: #00008B; } 262 | -------------------------------------------------------------------------------- /instructors/slides/static/lib/css/zenburn.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Zenburn style from voldmar.ru (c) Vladimir Epifanov 4 | based on dark.css by Ivan Sagalaev 5 | 6 | */ 7 | 8 | .hljs { 9 | display: block; padding: 0.5em; 10 | background: #3F3F3F; 11 | color: #DCDCDC; 12 | } 13 | 14 | .hljs-keyword, 15 | .hljs-tag, 16 | .css .hljs-class, 17 | .css .hljs-id, 18 | .lisp .hljs-title, 19 | .nginx .hljs-title, 20 | .hljs-request, 21 | .hljs-status, 22 | .clojure .hljs-attribute { 23 | color: #E3CEAB; 24 | } 25 | 26 | .django .hljs-template_tag, 27 | .django .hljs-variable, 28 | .django .hljs-filter .hljs-argument { 29 | color: #DCDCDC; 30 | } 31 | 32 | .hljs-number, 33 | .hljs-date { 34 | color: #8CD0D3; 35 | } 36 | 37 | .dos .hljs-envvar, 38 | .dos .hljs-stream, 39 | .hljs-variable, 40 | .apache .hljs-sqbracket { 41 | color: #EFDCBC; 42 | } 43 | 44 | .dos .hljs-flow, 45 | .diff .hljs-change, 46 | .python .exception, 47 | .python .hljs-built_in, 48 | .hljs-literal, 49 | .tex .hljs-special { 50 | color: #EFEFAF; 51 | } 52 | 53 | .diff .hljs-chunk, 54 | .hljs-subst { 55 | color: #8F8F8F; 56 | } 57 | 58 | .dos .hljs-keyword, 59 | .python .hljs-decorator, 60 | .hljs-title, 61 | .haskell .hljs-type, 62 | .diff .hljs-header, 63 | .ruby .hljs-class .hljs-parent, 64 | .apache .hljs-tag, 65 | .nginx .hljs-built_in, 66 | .tex .hljs-command, 67 | .hljs-prompt { 68 | color: #efef8f; 69 | } 70 | 71 | .dos .hljs-winutils, 72 | .ruby .hljs-symbol, 73 | .ruby .hljs-symbol .hljs-string, 74 | .ruby .hljs-string { 75 | color: #DCA3A3; 76 | } 77 | 78 | .diff .hljs-deletion, 79 | .hljs-string, 80 | .hljs-tag .hljs-value, 81 | .hljs-preprocessor, 82 | .hljs-pragma, 83 | .hljs-built_in, 84 | .sql .hljs-aggregate, 85 | .hljs-javadoc, 86 | .smalltalk .hljs-class, 87 | .smalltalk .hljs-localvars, 88 | .smalltalk .hljs-array, 89 | .css .hljs-rules .hljs-value, 90 | .hljs-attr_selector, 91 | .hljs-pseudo, 92 | .apache .hljs-cbracket, 93 | .tex .hljs-formula, 94 | .coffeescript .hljs-attribute { 95 | color: #CC9393; 96 | } 97 | 98 | .hljs-shebang, 99 | .diff .hljs-addition, 100 | .hljs-comment, 101 | .java .hljs-annotation, 102 | .hljs-template_comment, 103 | .hljs-pi, 104 | .hljs-doctype { 105 | color: #7F9F7F; 106 | } 107 | 108 | .coffeescript .javascript, 109 | .javascript .xml, 110 | .tex .hljs-formula, 111 | .xml .javascript, 112 | .xml .vbscript, 113 | .xml .css, 114 | .xml .hljs-cdata { 115 | opacity: 0.5; 116 | } 117 | 118 | -------------------------------------------------------------------------------- /instructors/slides/static/lib/font/source-sans-pro/source-sans-pro-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/django-security-tutorials/hands-on-web-security-slides/471b4c53d7e1b64a0ebc5f7af1dc054a665c4bdc/instructors/slides/static/lib/font/source-sans-pro/source-sans-pro-italic.woff -------------------------------------------------------------------------------- /instructors/slides/static/lib/font/source-sans-pro/source-sans-pro-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/django-security-tutorials/hands-on-web-security-slides/471b4c53d7e1b64a0ebc5f7af1dc054a665c4bdc/instructors/slides/static/lib/font/source-sans-pro/source-sans-pro-regular.woff -------------------------------------------------------------------------------- /instructors/slides/static/lib/font/source-sans-pro/source-sans-pro-semibold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/django-security-tutorials/hands-on-web-security-slides/471b4c53d7e1b64a0ebc5f7af1dc054a665c4bdc/instructors/slides/static/lib/font/source-sans-pro/source-sans-pro-semibold.woff -------------------------------------------------------------------------------- /instructors/slides/static/lib/font/source-sans-pro/source-sans-pro.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Source Sans Pro'; 3 | src: url('source-sans-pro-regular.eot'); 4 | src: url('source-sans-pro-regular.eot?#iefix') format('embedded-opentype'), 5 | url('source-sans-pro-regular.woff') format('woff'), 6 | url('source-sans-pro-regular.ttf') format('truetype'); 7 | font-weight: normal; 8 | font-style: normal; 9 | } 10 | 11 | @font-face { 12 | font-family: 'Source Sans Pro'; 13 | src: url('source-sans-pro-italic.eot'); 14 | src: url('source-sans-pro-italic.eot?#iefix') format('embedded-opentype'), 15 | url('source-sans-pro-italic.woff') format('woff'), 16 | url('source-sans-pro-italic.ttf') format('truetype'); 17 | font-weight: normal; 18 | font-style: italic; 19 | } 20 | 21 | @font-face { 22 | font-family: 'Source Sans Pro'; 23 | src: url('source-sans-pro-semibold.eot'); 24 | src: url('source-sans-pro-semibold.eot?#iefix') format('embedded-opentype'), 25 | url('source-sans-pro-semibold.woff') format('woff'), 26 | url('source-sans-pro-semibold.ttf') format('truetype'); 27 | font-weight: 600; 28 | font-style: normal; 29 | } 30 | 31 | @font-face { 32 | font-family: 'Source Sans Pro'; 33 | src: url('source-sans-pro-semibolditalic.eot'); 34 | src: url('source-sans-pro-semibolditalic.eot?#iefix') format('embedded-opentype'), 35 | url('source-sans-pro-semibolditalic.woff') format('woff'), 36 | url('source-sans-pro-semibolditalic.ttf') format('truetype'); 37 | font-weight: 600; 38 | font-style: italic; 39 | } -------------------------------------------------------------------------------- /instructors/slides/static/lib/js/head.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | Head JS The only script in your 3 | Copyright Tero Piirainen (tipiirai) 4 | License MIT / http://bit.ly/mit-license 5 | Version 0.96 6 | 7 | http://headjs.com 8 | */(function(a){function z(){d||(d=!0,s(e,function(a){p(a)}))}function y(c,d){var e=a.createElement("script");e.type="text/"+(c.type||"javascript"),e.src=c.src||c,e.async=!1,e.onreadystatechange=e.onload=function(){var a=e.readyState;!d.done&&(!a||/loaded|complete/.test(a))&&(d.done=!0,d())},(a.body||b).appendChild(e)}function x(a,b){if(a.state==o)return b&&b();if(a.state==n)return k.ready(a.name,b);if(a.state==m)return a.onpreload.push(function(){x(a,b)});a.state=n,y(a.url,function(){a.state=o,b&&b(),s(g[a.name],function(a){p(a)}),u()&&d&&s(g.ALL,function(a){p(a)})})}function w(a,b){a.state===undefined&&(a.state=m,a.onpreload=[],y({src:a.url,type:"cache"},function(){v(a)}))}function v(a){a.state=l,s(a.onpreload,function(a){a.call()})}function u(a){a=a||h;var b;for(var c in a){if(a.hasOwnProperty(c)&&a[c].state!=o)return!1;b=!0}return b}function t(a){return Object.prototype.toString.call(a)=="[object Function]"}function s(a,b){if(!!a){typeof a=="object"&&(a=[].slice.call(a));for(var c=0;c 0 ) { 50 | text = text.replace( new RegExp('\\n?\\t{' + leadingTabs + '}','g'), '\n' ); 51 | } 52 | else if( leadingWs > 1 ) { 53 | text = text.replace( new RegExp('\\n? {' + leadingWs + '}'), '\n' ); 54 | } 55 | 56 | return text; 57 | 58 | } 59 | 60 | /** 61 | * Given a markdown slide section element, this will 62 | * return all arguments that aren't related to markdown 63 | * parsing. Used to forward any other user-defined arguments 64 | * to the output markdown slide. 65 | */ 66 | function getForwardedAttributes( section ) { 67 | 68 | var attributes = section.attributes; 69 | var result = []; 70 | 71 | for( var i = 0, len = attributes.length; i < len; i++ ) { 72 | var name = attributes[i].name, 73 | value = attributes[i].value; 74 | 75 | // disregard attributes that are used for markdown loading/parsing 76 | if( /data\-(markdown|separator|vertical|notes)/gi.test( name ) ) continue; 77 | 78 | if( value ) { 79 | result.push( name + '=' + value ); 80 | } 81 | else { 82 | result.push( name ); 83 | } 84 | } 85 | 86 | return result.join( ' ' ); 87 | 88 | } 89 | 90 | /** 91 | * Inspects the given options and fills out default 92 | * values for what's not defined. 93 | */ 94 | function getSlidifyOptions( options ) { 95 | 96 | options = options || {}; 97 | options.separator = options.separator || DEFAULT_SLIDE_SEPARATOR; 98 | options.notesSeparator = options.notesSeparator || DEFAULT_NOTES_SEPARATOR; 99 | options.attributes = options.attributes || ''; 100 | 101 | return options; 102 | 103 | } 104 | 105 | /** 106 | * Helper function for constructing a markdown slide. 107 | */ 108 | function createMarkdownSlide( content, options ) { 109 | 110 | options = getSlidifyOptions( options ); 111 | 112 | var notesMatch = content.split( new RegExp( options.notesSeparator, 'mgi' ) ); 113 | 114 | if( notesMatch.length === 2 ) { 115 | content = notesMatch[0] + ''; 116 | } 117 | 118 | return ''; 119 | 120 | } 121 | 122 | /** 123 | * Parses a data string into multiple slides based 124 | * on the passed in separator arguments. 125 | */ 126 | function slidify( markdown, options ) { 127 | 128 | options = getSlidifyOptions( options ); 129 | 130 | var separatorRegex = new RegExp( options.separator + ( options.verticalSeparator ? '|' + options.verticalSeparator : '' ), 'mg' ), 131 | horizontalSeparatorRegex = new RegExp( options.separator ); 132 | 133 | var matches, 134 | lastIndex = 0, 135 | isHorizontal, 136 | wasHorizontal = true, 137 | content, 138 | sectionStack = []; 139 | 140 | // iterate until all blocks between separators are stacked up 141 | while( matches = separatorRegex.exec( markdown ) ) { 142 | notes = null; 143 | 144 | // determine direction (horizontal by default) 145 | isHorizontal = horizontalSeparatorRegex.test( matches[0] ); 146 | 147 | if( !isHorizontal && wasHorizontal ) { 148 | // create vertical stack 149 | sectionStack.push( [] ); 150 | } 151 | 152 | // pluck slide content from markdown input 153 | content = markdown.substring( lastIndex, matches.index ); 154 | 155 | if( isHorizontal && wasHorizontal ) { 156 | // add to horizontal stack 157 | sectionStack.push( content ); 158 | } 159 | else { 160 | // add to vertical stack 161 | sectionStack[sectionStack.length-1].push( content ); 162 | } 163 | 164 | lastIndex = separatorRegex.lastIndex; 165 | wasHorizontal = isHorizontal; 166 | } 167 | 168 | // add the remaining slide 169 | ( wasHorizontal ? sectionStack : sectionStack[sectionStack.length-1] ).push( markdown.substring( lastIndex ) ); 170 | 171 | var markdownSections = ''; 172 | 173 | // flatten the hierarchical stack, and insert
tags 174 | for( var i = 0, len = sectionStack.length; i < len; i++ ) { 175 | // vertical 176 | if( sectionStack[i] instanceof Array ) { 177 | markdownSections += '
'; 178 | 179 | sectionStack[i].forEach( function( child ) { 180 | markdownSections += '
' + createMarkdownSlide( child, options ) + '
'; 181 | } ); 182 | 183 | markdownSections += '
'; 184 | } 185 | else { 186 | markdownSections += '
' + createMarkdownSlide( sectionStack[i], options ) + '
'; 187 | } 188 | } 189 | 190 | return markdownSections; 191 | 192 | } 193 | 194 | /** 195 | * Parses any current data-markdown slides, splits 196 | * multi-slide markdown into separate sections and 197 | * handles loading of external markdown. 198 | */ 199 | function processSlides() { 200 | 201 | var sections = document.querySelectorAll( '[data-markdown]'), 202 | section; 203 | 204 | for( var i = 0, len = sections.length; i < len; i++ ) { 205 | 206 | section = sections[i]; 207 | 208 | if( section.getAttribute( 'data-markdown' ).length ) { 209 | 210 | var xhr = new XMLHttpRequest(), 211 | url = section.getAttribute( 'data-markdown' ); 212 | 213 | datacharset = section.getAttribute( 'data-charset' ); 214 | 215 | // see https://developer.mozilla.org/en-US/docs/Web/API/element.getAttribute#Notes 216 | if( datacharset != null && datacharset != '' ) { 217 | xhr.overrideMimeType( 'text/html; charset=' + datacharset ); 218 | } 219 | 220 | xhr.onreadystatechange = function() { 221 | if( xhr.readyState === 4 ) { 222 | // file protocol yields status code 0 (useful for local debug, mobile applications etc.) 223 | if ( ( xhr.status >= 200 && xhr.status < 300 ) || xhr.status === 0 ) { 224 | 225 | section.outerHTML = slidify( xhr.responseText, { 226 | separator: section.getAttribute( 'data-separator' ), 227 | verticalSeparator: section.getAttribute( 'data-separator-vertical' ), 228 | notesSeparator: section.getAttribute( 'data-separator-notes' ), 229 | attributes: getForwardedAttributes( section ) 230 | }); 231 | 232 | } 233 | else { 234 | 235 | section.outerHTML = '
' + 236 | 'ERROR: The attempt to fetch ' + url + ' failed with HTTP status ' + xhr.status + '.' + 237 | 'Check your browser\'s JavaScript console for more details.' + 238 | '

Remember that you need to serve the presentation HTML from a HTTP server.

' + 239 | '
'; 240 | 241 | } 242 | } 243 | }; 244 | 245 | xhr.open( 'GET', url, false ); 246 | 247 | try { 248 | xhr.send(); 249 | } 250 | catch ( e ) { 251 | alert( 'Failed to get the Markdown file ' + url + '. Make sure that the presentation and the file are served by a HTTP server and the file can be found there. ' + e ); 252 | } 253 | 254 | } 255 | else if( section.getAttribute( 'data-separator' ) || section.getAttribute( 'data-separator-vertical' ) || section.getAttribute( 'data-separator-notes' ) ) { 256 | 257 | section.outerHTML = slidify( getMarkdownFromSlide( section ), { 258 | separator: section.getAttribute( 'data-separator' ), 259 | verticalSeparator: section.getAttribute( 'data-separator-vertical' ), 260 | notesSeparator: section.getAttribute( 'data-separator-notes' ), 261 | attributes: getForwardedAttributes( section ) 262 | }); 263 | 264 | } 265 | else { 266 | section.innerHTML = createMarkdownSlide( getMarkdownFromSlide( section ) ); 267 | } 268 | } 269 | 270 | } 271 | 272 | /** 273 | * Check if a node value has the attributes pattern. 274 | * If yes, extract it and add that value as one or several attributes 275 | * the the terget element. 276 | * 277 | * You need Cache Killer on Chrome to see the effect on any FOM transformation 278 | * directly on refresh (F5) 279 | * http://stackoverflow.com/questions/5690269/disabling-chrome-cache-for-website-development/7000899#answer-11786277 280 | */ 281 | function addAttributeInElement( node, elementTarget, separator ) { 282 | 283 | var mardownClassesInElementsRegex = new RegExp( separator, 'mg' ); 284 | var mardownClassRegex = new RegExp( "([^\"= ]+?)=\"([^\"=]+?)\"", 'mg' ); 285 | var nodeValue = node.nodeValue; 286 | if( matches = mardownClassesInElementsRegex.exec( nodeValue ) ) { 287 | 288 | var classes = matches[1]; 289 | nodeValue = nodeValue.substring( 0, matches.index ) + nodeValue.substring( mardownClassesInElementsRegex.lastIndex ); 290 | node.nodeValue = nodeValue; 291 | while( matchesClass = mardownClassRegex.exec( classes ) ) { 292 | elementTarget.setAttribute( matchesClass[1], matchesClass[2] ); 293 | } 294 | return true; 295 | } 296 | return false; 297 | } 298 | 299 | /** 300 | * Add attributes to the parent element of a text node, 301 | * or the element of an attribute node. 302 | */ 303 | function addAttributes( section, element, previousElement, separatorElementAttributes, separatorSectionAttributes ) { 304 | 305 | if ( element != null && element.childNodes != undefined && element.childNodes.length > 0 ) { 306 | previousParentElement = element; 307 | for( var i = 0; i < element.childNodes.length; i++ ) { 308 | childElement = element.childNodes[i]; 309 | if ( i > 0 ) { 310 | j = i - 1; 311 | while ( j >= 0 ) { 312 | aPreviousChildElement = element.childNodes[j]; 313 | if ( typeof aPreviousChildElement.setAttribute == 'function' && aPreviousChildElement.tagName != "BR" ) { 314 | previousParentElement = aPreviousChildElement; 315 | break; 316 | } 317 | j = j - 1; 318 | } 319 | } 320 | parentSection = section; 321 | if( childElement.nodeName == "section" ) { 322 | parentSection = childElement ; 323 | previousParentElement = childElement ; 324 | } 325 | if ( typeof childElement.setAttribute == 'function' || childElement.nodeType == Node.COMMENT_NODE ) { 326 | addAttributes( parentSection, childElement, previousParentElement, separatorElementAttributes, separatorSectionAttributes ); 327 | } 328 | } 329 | } 330 | 331 | if ( element.nodeType == Node.COMMENT_NODE ) { 332 | if ( addAttributeInElement( element, previousElement, separatorElementAttributes ) == false ) { 333 | addAttributeInElement( element, section, separatorSectionAttributes ); 334 | } 335 | } 336 | } 337 | 338 | /** 339 | * Converts any current data-markdown slides in the 340 | * DOM to HTML. 341 | */ 342 | function convertSlides() { 343 | 344 | var sections = document.querySelectorAll( '[data-markdown]'); 345 | 346 | for( var i = 0, len = sections.length; i < len; i++ ) { 347 | 348 | var section = sections[i]; 349 | 350 | // Only parse the same slide once 351 | if( !section.getAttribute( 'data-markdown-parsed' ) ) { 352 | 353 | section.setAttribute( 'data-markdown-parsed', true ) 354 | 355 | var notes = section.querySelector( 'aside.notes' ); 356 | var markdown = getMarkdownFromSlide( section ); 357 | 358 | section.innerHTML = marked( markdown ); 359 | addAttributes( section, section, null, section.getAttribute( 'data-element-attributes' ) || 360 | section.parentNode.getAttribute( 'data-element-attributes' ) || 361 | DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR, 362 | section.getAttribute( 'data-attributes' ) || 363 | section.parentNode.getAttribute( 'data-attributes' ) || 364 | DEFAULT_SLIDE_ATTRIBUTES_SEPARATOR); 365 | 366 | // If there were notes, we need to re-add them after 367 | // having overwritten the section's HTML 368 | if( notes ) { 369 | section.appendChild( notes ); 370 | } 371 | 372 | } 373 | 374 | } 375 | 376 | } 377 | 378 | // API 379 | return { 380 | 381 | initialize: function() { 382 | processSlides(); 383 | convertSlides(); 384 | }, 385 | 386 | // TODO: Do these belong in the API? 387 | processSlides: processSlides, 388 | convertSlides: convertSlides, 389 | slidify: slidify 390 | 391 | }; 392 | 393 | })); 394 | -------------------------------------------------------------------------------- /instructors/slides/static/plugin/markdown/marked.js: -------------------------------------------------------------------------------- 1 | /** 2 | * marked - a markdown parser 3 | * Copyright (c) 2011-2013, Christopher Jeffrey. (MIT Licensed) 4 | * https://github.com/chjj/marked 5 | */ 6 | 7 | (function(){var block={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:noop,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:noop,lheading:/^([^\n]+)\n *(=|-){3,} *\n*/,blockquote:/^( *>[^\n]+(\n[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,def:/^ *\[([^\]]+)\]: *]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:noop,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/, 8 | text:/^[^\n]+/};block.bullet=/(?:[*+-]|\d+\.)/;block.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr",/\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|@)\\b";block.html=replace(block.html)("comment",/\x3c!--[\s\S]*?--\x3e/)("closed", 9 | /<(tag)[\s\S]+?<\/\1>/)("closing",/])*?>/)(/tag/g,block._tag)();block.paragraph=replace(block.paragraph)("hr",block.hr)("heading",block.heading)("lheading",block.lheading)("blockquote",block.blockquote)("tag","<"+block._tag)("def",block.def)();block.normal=merge({},block);block.gfm=merge({},block.normal,{fences:/^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,paragraph:/^/});block.gfm.paragraph=replace(block.paragraph)("(?!","(?!"+block.gfm.fences.source.replace("\\1", 10 | "\\2")+"|")();block.tables=merge({},block.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/});function Lexer(options){this.tokens=[];this.tokens.links={};this.options=options||marked.defaults;this.rules=block.normal;if(this.options.gfm)if(this.options.tables)this.rules=block.tables;else this.rules=block.gfm}Lexer.rules=block;Lexer.lex=function(src,options){var lexer=new Lexer(options);return lexer.lex(src)}; 11 | Lexer.prototype.lex=function(src){src=src.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n");return this.token(src,true)};Lexer.prototype.token=function(src,top){var src=src.replace(/^ +$/gm,""),next,loose,cap,bull,b,item,space,i,l;while(src){if(cap=this.rules.newline.exec(src)){src=src.substring(cap[0].length);if(cap[0].length>1)this.tokens.push({type:"space"})}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);cap=cap[0].replace(/^ {4}/gm, 12 | "");this.tokens.push({type:"code",text:!this.options.pedantic?cap.replace(/\n+$/,""):cap});continue}if(cap=this.rules.fences.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"code",lang:cap[2],text:cap[3]});continue}if(cap=this.rules.heading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[1].length,text:cap[2]});continue}if(top&&(cap=this.rules.nptable.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g, 13 | "").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/\n$/,"").split("\n")};for(i=0;i ?/gm,"");this.token(cap,top);this.tokens.push({type:"blockquote_end"});continue}if(cap=this.rules.list.exec(src)){src=src.substring(cap[0].length); 15 | bull=cap[2];this.tokens.push({type:"list_start",ordered:bull.length>1});cap=cap[0].match(this.rules.item);next=false;l=cap.length;i=0;for(;i1&&b.length>1)){src=cap.slice(i+ 16 | 1).join("\n")+src;i=l-1}}loose=next||/\n\n(?!\s*$)/.test(item);if(i!==l-1){next=item[item.length-1]==="\n";if(!loose)loose=next}this.tokens.push({type:loose?"loose_item_start":"list_item_start"});this.token(item,false);this.tokens.push({type:"list_item_end"})}this.tokens.push({type:"list_end"});continue}if(cap=this.rules.html.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:cap[1]==="pre"||cap[1]==="script",text:cap[0]});continue}if(top&& 17 | (cap=this.rules.def.exec(src))){src=src.substring(cap[0].length);this.tokens.links[cap[1].toLowerCase()]={href:cap[2],title:cap[3]};continue}if(top&&(cap=this.rules.table.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/(?: *\| *)?\n$/,"").split("\n")};for(i=0;i])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:noop,tag:/^\x3c!--[\s\S]*?--\x3e|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/, 20 | code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:noop,text:/^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/;inline.link=replace(inline.link)("inside",inline._inside)("href",inline._href)();inline.reflink=replace(inline.reflink)("inside",inline._inside)();inline.normal=merge({},inline);inline.pedantic=merge({},inline.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/, 21 | em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/});inline.gfm=merge({},inline.normal,{escape:replace(inline.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:replace(inline.text)("]|","~]|")("|","|https?://|")()});inline.breaks=merge({},inline.gfm,{br:replace(inline.br)("{2,}","*")(),text:replace(inline.gfm.text)("{2,}","*")()});function InlineLexer(links,options){this.options=options||marked.defaults;this.links=links;this.rules=inline.normal; 22 | if(!this.links)throw new Error("Tokens array requires a `links` property.");if(this.options.gfm)if(this.options.breaks)this.rules=inline.breaks;else this.rules=inline.gfm;else if(this.options.pedantic)this.rules=inline.pedantic}InlineLexer.rules=inline;InlineLexer.output=function(src,links,options){var inline=new InlineLexer(links,options);return inline.output(src)};InlineLexer.prototype.output=function(src){var out="",link,text,href,cap;while(src){if(cap=this.rules.escape.exec(src)){src=src.substring(cap[0].length); 23 | out+=cap[1];continue}if(cap=this.rules.autolink.exec(src)){src=src.substring(cap[0].length);if(cap[2]==="@"){text=cap[1][6]===":"?this.mangle(cap[1].substring(7)):this.mangle(cap[1]);href=this.mangle("mailto:")+text}else{text=escape(cap[1]);href=text}out+=''+text+"";continue}if(cap=this.rules.url.exec(src)){src=src.substring(cap[0].length);text=escape(cap[1]);href=text;out+=''+text+"";continue}if(cap=this.rules.tag.exec(src)){src=src.substring(cap[0].length); 24 | out+=this.options.sanitize?escape(cap[0]):cap[0];continue}if(cap=this.rules.link.exec(src)){src=src.substring(cap[0].length);out+=this.outputLink(cap,{href:cap[2],title:cap[3]});continue}if((cap=this.rules.reflink.exec(src))||(cap=this.rules.nolink.exec(src))){src=src.substring(cap[0].length);link=(cap[2]||cap[1]).replace(/\s+/g," ");link=this.links[link.toLowerCase()];if(!link||!link.href){out+=cap[0][0];src=cap[0].substring(1)+src;continue}out+=this.outputLink(cap,link);continue}if(cap=this.rules.strong.exec(src)){src= 25 | src.substring(cap[0].length);out+=""+this.output(cap[2]||cap[1])+"";continue}if(cap=this.rules.em.exec(src)){src=src.substring(cap[0].length);out+=""+this.output(cap[2]||cap[1])+"";continue}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);out+=""+escape(cap[2],true)+"";continue}if(cap=this.rules.br.exec(src)){src=src.substring(cap[0].length);out+="
";continue}if(cap=this.rules.del.exec(src)){src=src.substring(cap[0].length);out+=""+ 26 | this.output(cap[1])+"";continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);out+=escape(cap[0]);continue}if(src)throw new Error("Infinite loop on byte: "+src.charCodeAt(0));}return out};InlineLexer.prototype.outputLink=function(cap,link){if(cap[0][0]!=="!")return'"+this.output(cap[1])+"";else return''+escape(cap[1])+'"};InlineLexer.prototype.smartypants=function(text){if(!this.options.smartypants)return text;return text.replace(/--/g,"\u2014").replace(/'([^']*)'/g,"\u2018$1\u2019").replace(/"([^"]*)"/g,"\u201c$1\u201d").replace(/\.{3}/g,"\u2026")};InlineLexer.prototype.mangle=function(text){var out="",l=text.length,i=0,ch;for(;i0.5)ch="x"+ch.toString(16);out+="&#"+ch+";"}return out};function Parser(options){this.tokens=[];this.token=null; 28 | this.options=options||marked.defaults}Parser.parse=function(src,options){var parser=new Parser(options);return parser.parse(src)};Parser.prototype.parse=function(src){this.inline=new InlineLexer(src.links,this.options);this.tokens=src.reverse();var out="";while(this.next())out+=this.tok();return out};Parser.prototype.next=function(){return this.token=this.tokens.pop()};Parser.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0};Parser.prototype.parseText=function(){var body=this.token.text; 29 | while(this.peek().type==="text")body+="\n"+this.next().text;return this.inline.output(body)};Parser.prototype.tok=function(){switch(this.token.type){case "space":return"";case "hr":return"
\n";case "heading":return""+this.inline.output(this.token.text)+"\n";case "code":if(this.options.highlight){var code=this.options.highlight(this.token.text,this.token.lang);if(code!=null&&code!==this.token.text){this.token.escaped=true;this.token.text=code}}if(!this.token.escaped)this.token.text= 30 | escape(this.token.text,true);return"
"+this.token.text+"
\n";case "table":var body="",heading,i,row,cell,j;body+="\n\n";for(i=0;i'+heading+"\n":""+heading+"\n"}body+="\n\n";body+="\n";for(i=0;i'+cell+"\n":""+cell+"\n"}body+="\n"}body+="\n";return"\n"+body+"
\n";case "blockquote_start":var body="";while(this.next().type!=="blockquote_end")body+=this.tok();return"
\n"+body+"
\n";case "list_start":var type=this.token.ordered?"ol":"ul",body="";while(this.next().type!=="list_end")body+= 32 | this.tok();return"<"+type+">\n"+body+"\n";case "list_item_start":var body="";while(this.next().type!=="list_item_end")body+=this.token.type==="text"?this.parseText():this.tok();return"
  • "+body+"
  • \n";case "loose_item_start":var body="";while(this.next().type!=="list_item_end")body+=this.tok();return"
  • "+body+"
  • \n";case "html":return!this.token.pre&&!this.options.pedantic?this.inline.output(this.token.text):this.token.text;case "paragraph":return"

    "+this.inline.output(this.token.text)+ 33 | "

    \n";case "text":return"

    "+this.parseText()+"

    \n"}};function escape(html,encode){return html.replace(!encode?/&(?!#?\w+;)/g:/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function replace(regex,opt){regex=regex.source;opt=opt||"";return function self(name,val){if(!name)return new RegExp(regex,opt);val=val.source||val;val=val.replace(/(^|[^\[])\^/g,"$1");regex=regex.replace(name,val);return self}}function noop(){}noop.exec=noop;function merge(obj){var i= 34 | 1,target,key;for(;iAn error occured:

    "+escape(e.message+"",true)+"
    ";throw e;}}marked.options=marked.setOptions=function(opt){merge(marked.defaults,opt);return marked};marked.defaults={gfm:true,tables:true,breaks:false,pedantic:false,sanitize:false,smartLists:false,silent:false,highlight:null,langPrefix:""};marked.Parser=Parser;marked.parser=Parser.parse;marked.Lexer=Lexer;marked.lexer=Lexer.lex;marked.InlineLexer=InlineLexer;marked.inlineLexer=InlineLexer.output; 37 | marked.parse=marked;if(typeof exports==="object")module.exports=marked;else if(typeof define==="function"&&define.amd)define(function(){return marked});else this.marked=marked}).call(function(){return this||(typeof window!=="undefined"?window:global)}()); 38 | -------------------------------------------------------------------------------- /instructors/slides/static/plugin/notes/notes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | reveal.js - Slide Notes 7 | 8 | 151 | 152 | 153 | 154 | 155 |
    156 |
    UPCOMING:
    157 |
    158 |
    159 |

    Time Click to Reset

    160 |
    161 | 0:00 AM 162 |
    163 |
    164 | 00:00:00 165 |
    166 |
    167 |
    168 | 169 | 173 |
    174 | 175 | 176 | 405 | 406 | 407 | -------------------------------------------------------------------------------- /instructors/slides/static/plugin/notes/notes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Handles opening of and synchronization with the reveal.js 3 | * notes window. 4 | * 5 | * Handshake process: 6 | * 1. This window posts 'connect' to notes window 7 | * - Includes URL of presentation to show 8 | * 2. Notes window responds with 'connected' when it is available 9 | * 3. This window proceeds to send the current presentation state 10 | * to the notes window 11 | */ 12 | var RevealNotes = (function() { 13 | 14 | function openNotes() { 15 | var jsFileLocation = document.querySelector('script[src$="notes.js"]').src; // this js file path 16 | jsFileLocation = jsFileLocation.replace(/notes\.js(\?.*)?$/, ''); // the js folder path 17 | var notesPopup = window.open( jsFileLocation + 'notes.html', 'reveal.js - Notes', 'width=1100,height=700' ); 18 | 19 | /** 20 | * Connect to the notes window through a postmessage handshake. 21 | * Using postmessage enables us to work in situations where the 22 | * origins differ, such as a presentation being opened from the 23 | * file system. 24 | */ 25 | function connect() { 26 | // Keep trying to connect until we get a 'connected' message back 27 | var connectInterval = setInterval( function() { 28 | notesPopup.postMessage( JSON.stringify( { 29 | namespace: 'reveal-notes', 30 | type: 'connect', 31 | url: window.location.protocol + '//' + window.location.host + window.location.pathname, 32 | state: Reveal.getState() 33 | } ), '*' ); 34 | }, 500 ); 35 | 36 | window.addEventListener( 'message', function( event ) { 37 | var data = JSON.parse( event.data ); 38 | if( data && data.namespace === 'reveal-notes' && data.type === 'connected' ) { 39 | clearInterval( connectInterval ); 40 | onConnected(); 41 | } 42 | } ); 43 | } 44 | 45 | /** 46 | * Posts the current slide data to the notes window 47 | */ 48 | function post() { 49 | 50 | var slideElement = Reveal.getCurrentSlide(), 51 | notesElement = slideElement.querySelector( 'aside.notes' ); 52 | 53 | var messageData = { 54 | namespace: 'reveal-notes', 55 | type: 'state', 56 | notes: '', 57 | markdown: false, 58 | state: Reveal.getState() 59 | }; 60 | 61 | // Look for notes defined in a slide attribute 62 | if( slideElement.hasAttribute( 'data-notes' ) ) { 63 | messageData.notes = slideElement.getAttribute( 'data-notes' ); 64 | } 65 | 66 | // Look for notes defined in an aside element 67 | if( notesElement ) { 68 | messageData.notes = notesElement.innerHTML; 69 | messageData.markdown = typeof notesElement.getAttribute( 'data-markdown' ) === 'string'; 70 | } 71 | 72 | notesPopup.postMessage( JSON.stringify( messageData ), '*' ); 73 | 74 | } 75 | 76 | /** 77 | * Called once we have established a connection to the notes 78 | * window. 79 | */ 80 | function onConnected() { 81 | 82 | // Monitor events that trigger a change in state 83 | Reveal.addEventListener( 'slidechanged', post ); 84 | Reveal.addEventListener( 'fragmentshown', post ); 85 | Reveal.addEventListener( 'fragmenthidden', post ); 86 | Reveal.addEventListener( 'overviewhidden', post ); 87 | Reveal.addEventListener( 'overviewshown', post ); 88 | Reveal.addEventListener( 'paused', post ); 89 | Reveal.addEventListener( 'resumed', post ); 90 | 91 | // Post the initial state 92 | post(); 93 | 94 | } 95 | 96 | connect(); 97 | } 98 | 99 | if( !/receiver/i.test( window.location.search ) ) { 100 | 101 | // If the there's a 'notes' query set, open directly 102 | if( window.location.search.match( /(\?|\&)notes/gi ) !== null ) { 103 | openNotes(); 104 | } 105 | 106 | // Open the notes when the 's' key is hit 107 | document.addEventListener( 'keydown', function( event ) { 108 | // Disregard the event if the target is editable or a 109 | // modifier is present 110 | if ( document.querySelector( ':focus' ) !== null || event.shiftKey || event.altKey || event.ctrlKey || event.metaKey ) return; 111 | 112 | if( event.keyCode === 83 ) { 113 | event.preventDefault(); 114 | openNotes(); 115 | } 116 | }, false ); 117 | 118 | } 119 | 120 | return { open: openNotes }; 121 | 122 | })(); 123 | -------------------------------------------------------------------------------- /instructors/slides/static/plugin/zoom-js/zoom.js: -------------------------------------------------------------------------------- 1 | // Custom reveal.js integration 2 | (function(){ 3 | var isEnabled = true; 4 | 5 | document.querySelector( '.reveal' ).addEventListener( 'mousedown', function( event ) { 6 | var modifier = ( Reveal.getConfig().zoomKey ? Reveal.getConfig().zoomKey : 'alt' ) + 'Key'; 7 | 8 | var zoomPadding = 20; 9 | var revealScale = Reveal.getScale(); 10 | 11 | if( event[ modifier ] && isEnabled ) { 12 | event.preventDefault(); 13 | 14 | var bounds = event.target.getBoundingClientRect(); 15 | 16 | zoom.to({ 17 | x: ( bounds.left * revealScale ) - zoomPadding, 18 | y: ( bounds.top * revealScale ) - zoomPadding, 19 | width: ( bounds.width * revealScale ) + ( zoomPadding * 2 ), 20 | height: ( bounds.height * revealScale ) + ( zoomPadding * 2 ), 21 | pan: false 22 | }); 23 | } 24 | } ); 25 | 26 | Reveal.addEventListener( 'overviewshown', function() { isEnabled = false; } ); 27 | Reveal.addEventListener( 'overviewhidden', function() { isEnabled = true; } ); 28 | })(); 29 | 30 | /*! 31 | * zoom.js 0.3 (modified for use with reveal.js) 32 | * http://lab.hakim.se/zoom-js 33 | * MIT licensed 34 | * 35 | * Copyright (C) 2011-2014 Hakim El Hattab, http://hakim.se 36 | */ 37 | var zoom = (function(){ 38 | 39 | // The current zoom level (scale) 40 | var level = 1; 41 | 42 | // The current mouse position, used for panning 43 | var mouseX = 0, 44 | mouseY = 0; 45 | 46 | // Timeout before pan is activated 47 | var panEngageTimeout = -1, 48 | panUpdateInterval = -1; 49 | 50 | // Check for transform support so that we can fallback otherwise 51 | var supportsTransforms = 'WebkitTransform' in document.body.style || 52 | 'MozTransform' in document.body.style || 53 | 'msTransform' in document.body.style || 54 | 'OTransform' in document.body.style || 55 | 'transform' in document.body.style; 56 | 57 | if( supportsTransforms ) { 58 | // The easing that will be applied when we zoom in/out 59 | document.body.style.transition = 'transform 0.8s ease'; 60 | document.body.style.OTransition = '-o-transform 0.8s ease'; 61 | document.body.style.msTransition = '-ms-transform 0.8s ease'; 62 | document.body.style.MozTransition = '-moz-transform 0.8s ease'; 63 | document.body.style.WebkitTransition = '-webkit-transform 0.8s ease'; 64 | } 65 | 66 | // Zoom out if the user hits escape 67 | document.addEventListener( 'keyup', function( event ) { 68 | if( level !== 1 && event.keyCode === 27 ) { 69 | zoom.out(); 70 | } 71 | } ); 72 | 73 | // Monitor mouse movement for panning 74 | document.addEventListener( 'mousemove', function( event ) { 75 | if( level !== 1 ) { 76 | mouseX = event.clientX; 77 | mouseY = event.clientY; 78 | } 79 | } ); 80 | 81 | /** 82 | * Applies the CSS required to zoom in, prefers the use of CSS3 83 | * transforms but falls back on zoom for IE. 84 | * 85 | * @param {Object} rect 86 | * @param {Number} scale 87 | */ 88 | function magnify( rect, scale ) { 89 | 90 | var scrollOffset = getScrollOffset(); 91 | 92 | // Ensure a width/height is set 93 | rect.width = rect.width || 1; 94 | rect.height = rect.height || 1; 95 | 96 | // Center the rect within the zoomed viewport 97 | rect.x -= ( window.innerWidth - ( rect.width * scale ) ) / 2; 98 | rect.y -= ( window.innerHeight - ( rect.height * scale ) ) / 2; 99 | 100 | if( supportsTransforms ) { 101 | // Reset 102 | if( scale === 1 ) { 103 | document.body.style.transform = ''; 104 | document.body.style.OTransform = ''; 105 | document.body.style.msTransform = ''; 106 | document.body.style.MozTransform = ''; 107 | document.body.style.WebkitTransform = ''; 108 | } 109 | // Scale 110 | else { 111 | var origin = scrollOffset.x +'px '+ scrollOffset.y +'px', 112 | transform = 'translate('+ -rect.x +'px,'+ -rect.y +'px) scale('+ scale +')'; 113 | 114 | document.body.style.transformOrigin = origin; 115 | document.body.style.OTransformOrigin = origin; 116 | document.body.style.msTransformOrigin = origin; 117 | document.body.style.MozTransformOrigin = origin; 118 | document.body.style.WebkitTransformOrigin = origin; 119 | 120 | document.body.style.transform = transform; 121 | document.body.style.OTransform = transform; 122 | document.body.style.msTransform = transform; 123 | document.body.style.MozTransform = transform; 124 | document.body.style.WebkitTransform = transform; 125 | } 126 | } 127 | else { 128 | // Reset 129 | if( scale === 1 ) { 130 | document.body.style.position = ''; 131 | document.body.style.left = ''; 132 | document.body.style.top = ''; 133 | document.body.style.width = ''; 134 | document.body.style.height = ''; 135 | document.body.style.zoom = ''; 136 | } 137 | // Scale 138 | else { 139 | document.body.style.position = 'relative'; 140 | document.body.style.left = ( - ( scrollOffset.x + rect.x ) / scale ) + 'px'; 141 | document.body.style.top = ( - ( scrollOffset.y + rect.y ) / scale ) + 'px'; 142 | document.body.style.width = ( scale * 100 ) + '%'; 143 | document.body.style.height = ( scale * 100 ) + '%'; 144 | document.body.style.zoom = scale; 145 | } 146 | } 147 | 148 | level = scale; 149 | 150 | if( document.documentElement.classList ) { 151 | if( level !== 1 ) { 152 | document.documentElement.classList.add( 'zoomed' ); 153 | } 154 | else { 155 | document.documentElement.classList.remove( 'zoomed' ); 156 | } 157 | } 158 | } 159 | 160 | /** 161 | * Pan the document when the mosue cursor approaches the edges 162 | * of the window. 163 | */ 164 | function pan() { 165 | var range = 0.12, 166 | rangeX = window.innerWidth * range, 167 | rangeY = window.innerHeight * range, 168 | scrollOffset = getScrollOffset(); 169 | 170 | // Up 171 | if( mouseY < rangeY ) { 172 | window.scroll( scrollOffset.x, scrollOffset.y - ( 1 - ( mouseY / rangeY ) ) * ( 14 / level ) ); 173 | } 174 | // Down 175 | else if( mouseY > window.innerHeight - rangeY ) { 176 | window.scroll( scrollOffset.x, scrollOffset.y + ( 1 - ( window.innerHeight - mouseY ) / rangeY ) * ( 14 / level ) ); 177 | } 178 | 179 | // Left 180 | if( mouseX < rangeX ) { 181 | window.scroll( scrollOffset.x - ( 1 - ( mouseX / rangeX ) ) * ( 14 / level ), scrollOffset.y ); 182 | } 183 | // Right 184 | else if( mouseX > window.innerWidth - rangeX ) { 185 | window.scroll( scrollOffset.x + ( 1 - ( window.innerWidth - mouseX ) / rangeX ) * ( 14 / level ), scrollOffset.y ); 186 | } 187 | } 188 | 189 | function getScrollOffset() { 190 | return { 191 | x: window.scrollX !== undefined ? window.scrollX : window.pageXOffset, 192 | y: window.scrollY !== undefined ? window.scrollY : window.pageYOffset 193 | } 194 | } 195 | 196 | return { 197 | /** 198 | * Zooms in on either a rectangle or HTML element. 199 | * 200 | * @param {Object} options 201 | * - element: HTML element to zoom in on 202 | * OR 203 | * - x/y: coordinates in non-transformed space to zoom in on 204 | * - width/height: the portion of the screen to zoom in on 205 | * - scale: can be used instead of width/height to explicitly set scale 206 | */ 207 | to: function( options ) { 208 | 209 | // Due to an implementation limitation we can't zoom in 210 | // to another element without zooming out first 211 | if( level !== 1 ) { 212 | zoom.out(); 213 | } 214 | else { 215 | options.x = options.x || 0; 216 | options.y = options.y || 0; 217 | 218 | // If an element is set, that takes precedence 219 | if( !!options.element ) { 220 | // Space around the zoomed in element to leave on screen 221 | var padding = 20; 222 | var bounds = options.element.getBoundingClientRect(); 223 | 224 | options.x = bounds.left - padding; 225 | options.y = bounds.top - padding; 226 | options.width = bounds.width + ( padding * 2 ); 227 | options.height = bounds.height + ( padding * 2 ); 228 | } 229 | 230 | // If width/height values are set, calculate scale from those values 231 | if( options.width !== undefined && options.height !== undefined ) { 232 | options.scale = Math.max( Math.min( window.innerWidth / options.width, window.innerHeight / options.height ), 1 ); 233 | } 234 | 235 | if( options.scale > 1 ) { 236 | options.x *= options.scale; 237 | options.y *= options.scale; 238 | 239 | magnify( options, options.scale ); 240 | 241 | if( options.pan !== false ) { 242 | 243 | // Wait with engaging panning as it may conflict with the 244 | // zoom transition 245 | panEngageTimeout = setTimeout( function() { 246 | panUpdateInterval = setInterval( pan, 1000 / 60 ); 247 | }, 800 ); 248 | 249 | } 250 | } 251 | } 252 | }, 253 | 254 | /** 255 | * Resets the document zoom state to its default. 256 | */ 257 | out: function() { 258 | clearTimeout( panEngageTimeout ); 259 | clearInterval( panUpdateInterval ); 260 | 261 | magnify( { x: 0, y: 0 }, 1 ); 262 | 263 | level = 1; 264 | }, 265 | 266 | // Alias 267 | magnify: function( options ) { this.to( options ) }, 268 | reset: function() { this.out() }, 269 | 270 | zoomLevel: function() { 271 | return level; 272 | } 273 | } 274 | 275 | })(); 276 | 277 | 278 | 279 | -------------------------------------------------------------------------------- /instructors/slides/static/slides.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | reveal.js - The HTML Presentation Framework 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 31 | 32 | 35 | 36 | 37 | 38 | 39 |
    40 |
    41 |
    42 | 43 | 44 | 45 | 46 | 47 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | argparse 2 | -------------------------------------------------------------------------------- /schedule/.gitignore: -------------------------------------------------------------------------------- 1 | # Emacs backup files 2 | *~ 3 | -------------------------------------------------------------------------------- /schedule/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
    11 |

    Schedule for tutorial

    12 |
    13 |
    14 |
      15 |
    • 30 min: Lecture: A tour of attacks
    • 16 |
    • 15 min: Small group exercise, Google Dorking
    • 17 |
    • 15 min: Small group discussion, What's at risk?
    • 18 |
    • 30 min: Lab time, part 1
    • 19 |
    • 20 min: Break
    • 20 |
    • 60 min: Lab time, part 2
    • 21 |
    • 30 min: Lecture: Best practices & wrap-up
    • 22 |
    23 |
    24 |
    25 |
    26 |

    Home

    27 |

    Lab material

    28 |
    29 |
    30 | 31 | 32 |
    33 | 34 |
    35 | 36 | 37 | -------------------------------------------------------------------------------- /static/bootstrap-4.1.3-dist/css/.DS_Store: -------------------------------------------------------------------------------- 1 | Bud1%  @� @� @� @ E%DSDB`� @� @� @ -------------------------------------------------------------------------------- /static/bootstrap-4.1.3-dist/css/bootstrap-reboot.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v4.1.3 (https://getbootstrap.com/) 3 | * Copyright 2011-2018 The Bootstrap Authors 4 | * Copyright 2011-2018 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */ 8 | *, 9 | *::before, 10 | *::after { 11 | box-sizing: border-box; 12 | } 13 | 14 | html { 15 | font-family: sans-serif; 16 | line-height: 1.15; 17 | -webkit-text-size-adjust: 100%; 18 | -ms-text-size-adjust: 100%; 19 | -ms-overflow-style: scrollbar; 20 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 21 | } 22 | 23 | @-ms-viewport { 24 | width: device-width; 25 | } 26 | 27 | article, aside, figcaption, figure, footer, header, hgroup, main, nav, section { 28 | display: block; 29 | } 30 | 31 | body { 32 | margin: 0; 33 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; 34 | font-size: 1rem; 35 | font-weight: 400; 36 | line-height: 1.5; 37 | color: #212529; 38 | text-align: left; 39 | background-color: #fff; 40 | } 41 | 42 | [tabindex="-1"]:focus { 43 | outline: 0 !important; 44 | } 45 | 46 | hr { 47 | box-sizing: content-box; 48 | height: 0; 49 | overflow: visible; 50 | } 51 | 52 | h1, h2, h3, h4, h5, h6 { 53 | margin-top: 0; 54 | margin-bottom: 0.5rem; 55 | } 56 | 57 | p { 58 | margin-top: 0; 59 | margin-bottom: 1rem; 60 | } 61 | 62 | abbr[title], 63 | abbr[data-original-title] { 64 | text-decoration: underline; 65 | -webkit-text-decoration: underline dotted; 66 | text-decoration: underline dotted; 67 | cursor: help; 68 | border-bottom: 0; 69 | } 70 | 71 | address { 72 | margin-bottom: 1rem; 73 | font-style: normal; 74 | line-height: inherit; 75 | } 76 | 77 | ol, 78 | ul, 79 | dl { 80 | margin-top: 0; 81 | margin-bottom: 1rem; 82 | } 83 | 84 | ol ol, 85 | ul ul, 86 | ol ul, 87 | ul ol { 88 | margin-bottom: 0; 89 | } 90 | 91 | dt { 92 | font-weight: 700; 93 | } 94 | 95 | dd { 96 | margin-bottom: .5rem; 97 | margin-left: 0; 98 | } 99 | 100 | blockquote { 101 | margin: 0 0 1rem; 102 | } 103 | 104 | dfn { 105 | font-style: italic; 106 | } 107 | 108 | b, 109 | strong { 110 | font-weight: bolder; 111 | } 112 | 113 | small { 114 | font-size: 80%; 115 | } 116 | 117 | sub, 118 | sup { 119 | position: relative; 120 | font-size: 75%; 121 | line-height: 0; 122 | vertical-align: baseline; 123 | } 124 | 125 | sub { 126 | bottom: -.25em; 127 | } 128 | 129 | sup { 130 | top: -.5em; 131 | } 132 | 133 | a { 134 | color: #007bff; 135 | text-decoration: none; 136 | background-color: transparent; 137 | -webkit-text-decoration-skip: objects; 138 | } 139 | 140 | a:hover { 141 | color: #0056b3; 142 | text-decoration: underline; 143 | } 144 | 145 | a:not([href]):not([tabindex]) { 146 | color: inherit; 147 | text-decoration: none; 148 | } 149 | 150 | a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus { 151 | color: inherit; 152 | text-decoration: none; 153 | } 154 | 155 | a:not([href]):not([tabindex]):focus { 156 | outline: 0; 157 | } 158 | 159 | pre, 160 | code, 161 | kbd, 162 | samp { 163 | font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 164 | font-size: 1em; 165 | } 166 | 167 | pre { 168 | margin-top: 0; 169 | margin-bottom: 1rem; 170 | overflow: auto; 171 | -ms-overflow-style: scrollbar; 172 | } 173 | 174 | figure { 175 | margin: 0 0 1rem; 176 | } 177 | 178 | img { 179 | vertical-align: middle; 180 | border-style: none; 181 | } 182 | 183 | svg { 184 | overflow: hidden; 185 | vertical-align: middle; 186 | } 187 | 188 | table { 189 | border-collapse: collapse; 190 | } 191 | 192 | caption { 193 | padding-top: 0.75rem; 194 | padding-bottom: 0.75rem; 195 | color: #6c757d; 196 | text-align: left; 197 | caption-side: bottom; 198 | } 199 | 200 | th { 201 | text-align: inherit; 202 | } 203 | 204 | label { 205 | display: inline-block; 206 | margin-bottom: 0.5rem; 207 | } 208 | 209 | button { 210 | border-radius: 0; 211 | } 212 | 213 | button:focus { 214 | outline: 1px dotted; 215 | outline: 5px auto -webkit-focus-ring-color; 216 | } 217 | 218 | input, 219 | button, 220 | select, 221 | optgroup, 222 | textarea { 223 | margin: 0; 224 | font-family: inherit; 225 | font-size: inherit; 226 | line-height: inherit; 227 | } 228 | 229 | button, 230 | input { 231 | overflow: visible; 232 | } 233 | 234 | button, 235 | select { 236 | text-transform: none; 237 | } 238 | 239 | button, 240 | html [type="button"], 241 | [type="reset"], 242 | [type="submit"] { 243 | -webkit-appearance: button; 244 | } 245 | 246 | button::-moz-focus-inner, 247 | [type="button"]::-moz-focus-inner, 248 | [type="reset"]::-moz-focus-inner, 249 | [type="submit"]::-moz-focus-inner { 250 | padding: 0; 251 | border-style: none; 252 | } 253 | 254 | input[type="radio"], 255 | input[type="checkbox"] { 256 | box-sizing: border-box; 257 | padding: 0; 258 | } 259 | 260 | input[type="date"], 261 | input[type="time"], 262 | input[type="datetime-local"], 263 | input[type="month"] { 264 | -webkit-appearance: listbox; 265 | } 266 | 267 | textarea { 268 | overflow: auto; 269 | resize: vertical; 270 | } 271 | 272 | fieldset { 273 | min-width: 0; 274 | padding: 0; 275 | margin: 0; 276 | border: 0; 277 | } 278 | 279 | legend { 280 | display: block; 281 | width: 100%; 282 | max-width: 100%; 283 | padding: 0; 284 | margin-bottom: .5rem; 285 | font-size: 1.5rem; 286 | line-height: inherit; 287 | color: inherit; 288 | white-space: normal; 289 | } 290 | 291 | progress { 292 | vertical-align: baseline; 293 | } 294 | 295 | [type="number"]::-webkit-inner-spin-button, 296 | [type="number"]::-webkit-outer-spin-button { 297 | height: auto; 298 | } 299 | 300 | [type="search"] { 301 | outline-offset: -2px; 302 | -webkit-appearance: none; 303 | } 304 | 305 | [type="search"]::-webkit-search-cancel-button, 306 | [type="search"]::-webkit-search-decoration { 307 | -webkit-appearance: none; 308 | } 309 | 310 | ::-webkit-file-upload-button { 311 | font: inherit; 312 | -webkit-appearance: button; 313 | } 314 | 315 | output { 316 | display: inline-block; 317 | } 318 | 319 | summary { 320 | display: list-item; 321 | cursor: pointer; 322 | } 323 | 324 | template { 325 | display: none; 326 | } 327 | 328 | [hidden] { 329 | display: none !important; 330 | } 331 | /*# sourceMappingURL=bootstrap-reboot.css.map */ -------------------------------------------------------------------------------- /static/bootstrap-4.1.3-dist/css/bootstrap-reboot.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v4.1.3 (https://getbootstrap.com/) 3 | * Copyright 2011-2018 The Bootstrap Authors 4 | * Copyright 2011-2018 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important} 8 | /*# sourceMappingURL=bootstrap-reboot.min.css.map */ -------------------------------------------------------------------------------- /static/images/IMG_9232.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/django-security-tutorials/hands-on-web-security-slides/471b4c53d7e1b64a0ebc5f7af1dc054a665c4bdc/static/images/IMG_9232.jpg -------------------------------------------------------------------------------- /static/pets.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #ffe9dc; 3 | } 4 | 5 | h1 { 6 | text-transform: lowercase; 7 | font-weight: 100; 8 | font-size: 48px; 9 | } -------------------------------------------------------------------------------- /student-handout/static/css/print/paper.css: -------------------------------------------------------------------------------- 1 | /* Default Print Stylesheet Template 2 | by Rob Glazebrook of CSSnewbie.com 3 | Last Updated: June 4, 2008 4 | 5 | Feel free (nay, compelled) to edit, append, and 6 | manipulate this file as you see fit. */ 7 | 8 | 9 | @media print { 10 | 11 | /* SECTION 1: Set default width, margin, float, and 12 | background. This prevents elements from extending 13 | beyond the edge of the printed page, and prevents 14 | unnecessary background images from printing */ 15 | html { 16 | background: #fff; 17 | width: auto; 18 | height: auto; 19 | overflow: visible; 20 | } 21 | body { 22 | background: #fff; 23 | font-size: 20pt; 24 | width: auto; 25 | height: auto; 26 | border: 0; 27 | margin: 0 5%; 28 | padding: 0; 29 | overflow: visible; 30 | float: none !important; 31 | } 32 | 33 | /* SECTION 2: Remove any elements not needed in print. 34 | This would include navigation, ads, sidebars, etc. */ 35 | .nestedarrow, 36 | .controls, 37 | .fork-reveal, 38 | .share-reveal, 39 | .state-background, 40 | .reveal .progress, 41 | .reveal .backgrounds { 42 | display: none !important; 43 | } 44 | 45 | /* SECTION 3: Set body font face, size, and color. 46 | Consider using a serif font for readability. */ 47 | body, p, td, li, div { 48 | font-size: 20pt!important; 49 | font-family: Georgia, "Times New Roman", Times, serif !important; 50 | color: #000; 51 | } 52 | 53 | /* SECTION 4: Set heading font face, sizes, and color. 54 | Differentiate your headings from your body text. 55 | Perhaps use a large sans-serif for distinction. */ 56 | h1,h2,h3,h4,h5,h6 { 57 | color: #000!important; 58 | height: auto; 59 | line-height: normal; 60 | font-family: Georgia, "Times New Roman", Times, serif !important; 61 | text-shadow: 0 0 0 #000 !important; 62 | text-align: left; 63 | letter-spacing: normal; 64 | } 65 | /* Need to reduce the size of the fonts for printing */ 66 | h1 { font-size: 28pt !important; } 67 | h2 { font-size: 24pt !important; } 68 | h3 { font-size: 22pt !important; } 69 | h4 { font-size: 22pt !important; font-variant: small-caps; } 70 | h5 { font-size: 21pt !important; } 71 | h6 { font-size: 20pt !important; font-style: italic; } 72 | 73 | /* SECTION 5: Make hyperlinks more usable. 74 | Ensure links are underlined, and consider appending 75 | the URL to the end of the link for usability. */ 76 | a:link, 77 | a:visited { 78 | color: #000 !important; 79 | font-weight: bold; 80 | text-decoration: underline; 81 | } 82 | /* 83 | .reveal a:link:after, 84 | .reveal a:visited:after { 85 | content: " (" attr(href) ") "; 86 | color: #222 !important; 87 | font-size: 90%; 88 | } 89 | */ 90 | 91 | 92 | /* SECTION 6: more reveal.js specific additions by @skypanther */ 93 | ul, ol, div, p { 94 | visibility: visible; 95 | position: static; 96 | width: auto; 97 | height: auto; 98 | display: block; 99 | overflow: visible; 100 | margin: 0; 101 | text-align: left !important; 102 | } 103 | .reveal pre, 104 | .reveal table { 105 | margin-left: 0; 106 | margin-right: 0; 107 | } 108 | .reveal pre code { 109 | padding: 20px; 110 | border: 1px solid #ddd; 111 | } 112 | .reveal blockquote { 113 | margin: 20px 0; 114 | } 115 | .reveal .slides { 116 | position: static !important; 117 | width: auto !important; 118 | height: auto !important; 119 | 120 | left: 0 !important; 121 | top: 0 !important; 122 | margin-left: 0 !important; 123 | margin-top: 0 !important; 124 | padding: 0 !important; 125 | zoom: 1 !important; 126 | 127 | overflow: visible !important; 128 | display: block !important; 129 | 130 | text-align: left !important; 131 | -webkit-perspective: none; 132 | -moz-perspective: none; 133 | -ms-perspective: none; 134 | perspective: none; 135 | 136 | -webkit-perspective-origin: 50% 50%; 137 | -moz-perspective-origin: 50% 50%; 138 | -ms-perspective-origin: 50% 50%; 139 | perspective-origin: 50% 50%; 140 | } 141 | .reveal .slides section { 142 | visibility: visible !important; 143 | position: static !important; 144 | width: 100% !important; 145 | height: auto !important; 146 | display: block !important; 147 | overflow: visible !important; 148 | 149 | left: 0 !important; 150 | top: 0 !important; 151 | margin-left: 0 !important; 152 | margin-top: 0 !important; 153 | padding: 60px 20px !important; 154 | z-index: auto !important; 155 | 156 | opacity: 1 !important; 157 | 158 | page-break-after: always !important; 159 | 160 | -webkit-transform-style: flat !important; 161 | -moz-transform-style: flat !important; 162 | -ms-transform-style: flat !important; 163 | transform-style: flat !important; 164 | 165 | -webkit-transform: none !important; 166 | -moz-transform: none !important; 167 | -ms-transform: none !important; 168 | transform: none !important; 169 | 170 | -webkit-transition: none !important; 171 | -moz-transition: none !important; 172 | -ms-transition: none !important; 173 | transition: none !important; 174 | } 175 | .reveal .slides section.stack { 176 | padding: 0 !important; 177 | } 178 | .reveal section:last-of-type { 179 | page-break-after: avoid !important; 180 | } 181 | .reveal section .fragment { 182 | opacity: 1 !important; 183 | visibility: visible !important; 184 | 185 | -webkit-transform: none !important; 186 | -moz-transform: none !important; 187 | -ms-transform: none !important; 188 | transform: none !important; 189 | } 190 | .reveal section img { 191 | display: block; 192 | margin: 15px 0px; 193 | background: rgba(255,255,255,1); 194 | border: 1px solid #666; 195 | box-shadow: none; 196 | } 197 | 198 | .reveal section small { 199 | font-size: 0.8em; 200 | } 201 | 202 | } -------------------------------------------------------------------------------- /student-handout/static/css/theme/black.css: -------------------------------------------------------------------------------- 1 | @import url(../../lib/font/source-sans-pro/source-sans-pro.css); 2 | /** 3 | * Black theme for reveal.js. This is the opposite of the 'white' theme. 4 | * 5 | * Copyright (C) 2015 Hakim El Hattab, http://hakim.se 6 | */ 7 | section.has-light-background, section.has-light-background h1, section.has-light-background h2, section.has-light-background h3, section.has-light-background h4, section.has-light-background h5, section.has-light-background h6 { 8 | color: #222; } 9 | 10 | /********************************************* 11 | * GLOBAL STYLES 12 | *********************************************/ 13 | body { 14 | background: #222; 15 | background-color: #222; } 16 | 17 | .reveal { 18 | font-family: 'Source Sans Pro', Helvetica, sans-serif; 19 | font-size: 38px; 20 | font-weight: normal; 21 | color: #fff; } 22 | 23 | ::selection { 24 | color: #fff; 25 | background: #bee4fd; 26 | text-shadow: none; } 27 | 28 | .reveal .slides > section, .reveal .slides > section > section { 29 | line-height: 1.3; 30 | font-weight: inherit; } 31 | 32 | /********************************************* 33 | * HEADERS 34 | *********************************************/ 35 | .reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6 { 36 | margin: 0 0 20px 0; 37 | color: #fff; 38 | font-family: 'Source Sans Pro', Helvetica, sans-serif; 39 | font-weight: 600; 40 | line-height: 1.2; 41 | letter-spacing: normal; 42 | text-transform: uppercase; 43 | text-shadow: none; 44 | word-wrap: break-word; } 45 | 46 | .reveal h1 { 47 | font-size: 2.5em; } 48 | 49 | .reveal h2 { 50 | font-size: 1.6em; } 51 | 52 | .reveal h3 { 53 | font-size: 1.3em; } 54 | 55 | .reveal h4 { 56 | font-size: 1em; } 57 | 58 | .reveal h1 { 59 | text-shadow: none; } 60 | 61 | /********************************************* 62 | * OTHER 63 | *********************************************/ 64 | .reveal p { 65 | margin: 20px 0; 66 | line-height: 1.3; } 67 | 68 | /* Ensure certain elements are never larger than the slide itself */ 69 | .reveal img, .reveal video, .reveal iframe { 70 | max-width: 95%; 71 | max-height: 95%; } 72 | 73 | .reveal strong, .reveal b { 74 | font-weight: bold; } 75 | 76 | .reveal em { 77 | font-style: italic; } 78 | 79 | .reveal ol, .reveal dl, .reveal ul { 80 | display: inline-block; 81 | text-align: left; 82 | margin: 0 0 0 1em; } 83 | 84 | .reveal ol { 85 | list-style-type: decimal; } 86 | 87 | .reveal ul { 88 | list-style-type: disc; } 89 | 90 | .reveal ul ul { 91 | list-style-type: square; } 92 | 93 | .reveal ul ul ul { 94 | list-style-type: circle; } 95 | 96 | .reveal ul ul, .reveal ul ol, .reveal ol ol, .reveal ol ul { 97 | display: block; 98 | margin-left: 40px; } 99 | 100 | .reveal dt { 101 | font-weight: bold; } 102 | 103 | .reveal dd { 104 | margin-left: 40px; } 105 | 106 | .reveal q, .reveal blockquote { 107 | quotes: none; } 108 | 109 | .reveal blockquote { 110 | display: block; 111 | position: relative; 112 | width: 70%; 113 | margin: 20px auto; 114 | padding: 5px; 115 | font-style: italic; 116 | background: rgba(255, 255, 255, 0.05); 117 | box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.2); } 118 | 119 | .reveal blockquote p:first-child, .reveal blockquote p:last-child { 120 | display: inline-block; } 121 | 122 | .reveal q { 123 | font-style: italic; } 124 | 125 | .reveal pre { 126 | display: block; 127 | position: relative; 128 | width: 90%; 129 | margin: 20px auto; 130 | text-align: left; 131 | font-size: 0.55em; 132 | font-family: monospace; 133 | line-height: 1.2em; 134 | word-wrap: break-word; 135 | box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.3); } 136 | 137 | .reveal code { 138 | font-family: monospace; } 139 | 140 | .reveal pre code { 141 | display: block; 142 | padding: 5px; 143 | overflow: auto; 144 | max-height: 400px; 145 | word-wrap: normal; 146 | background: #3F3F3F; 147 | color: #DCDCDC; } 148 | 149 | .reveal table { 150 | margin: auto; 151 | border-collapse: collapse; 152 | border-spacing: 0; } 153 | 154 | .reveal table th { 155 | font-weight: bold; } 156 | 157 | .reveal table th, .reveal table td { 158 | text-align: left; 159 | padding: 0.2em 0.5em 0.2em 0.5em; 160 | border-bottom: 1px solid; } 161 | 162 | .reveal table tr:last-child td { 163 | border-bottom: none; } 164 | 165 | .reveal sup { 166 | vertical-align: super; } 167 | 168 | .reveal sub { 169 | vertical-align: sub; } 170 | 171 | .reveal small { 172 | display: inline-block; 173 | font-size: 0.6em; 174 | line-height: 1.2em; 175 | vertical-align: top; } 176 | 177 | .reveal small * { 178 | vertical-align: top; } 179 | 180 | /********************************************* 181 | * LINKS 182 | *********************************************/ 183 | .reveal a { 184 | color: #42affa; 185 | text-decoration: none; 186 | -webkit-transition: color 0.15s ease; 187 | -moz-transition: color 0.15s ease; 188 | transition: color 0.15s ease; } 189 | 190 | .reveal a:hover { 191 | color: #8dcffc; 192 | text-shadow: none; 193 | border: none; } 194 | 195 | .reveal .roll span:after { 196 | color: #fff; 197 | background: #068ee9; } 198 | 199 | /********************************************* 200 | * IMAGES 201 | *********************************************/ 202 | .reveal section img { 203 | margin: 15px 0px; 204 | background: rgba(255, 255, 255, 0.12); 205 | border: 4px solid #fff; 206 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); } 207 | 208 | .reveal a img { 209 | -webkit-transition: all 0.15s linear; 210 | -moz-transition: all 0.15s linear; 211 | transition: all 0.15s linear; } 212 | 213 | .reveal a:hover img { 214 | background: rgba(255, 255, 255, 0.2); 215 | border-color: #42affa; 216 | box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); } 217 | 218 | /********************************************* 219 | * NAVIGATION CONTROLS 220 | *********************************************/ 221 | .reveal .controls div.navigate-left, .reveal .controls div.navigate-left.enabled { 222 | border-right-color: #42affa; } 223 | 224 | .reveal .controls div.navigate-right, .reveal .controls div.navigate-right.enabled { 225 | border-left-color: #42affa; } 226 | 227 | .reveal .controls div.navigate-up, .reveal .controls div.navigate-up.enabled { 228 | border-bottom-color: #42affa; } 229 | 230 | .reveal .controls div.navigate-down, .reveal .controls div.navigate-down.enabled { 231 | border-top-color: #42affa; } 232 | 233 | .reveal .controls div.navigate-left.enabled:hover { 234 | border-right-color: #8dcffc; } 235 | 236 | .reveal .controls div.navigate-right.enabled:hover { 237 | border-left-color: #8dcffc; } 238 | 239 | .reveal .controls div.navigate-up.enabled:hover { 240 | border-bottom-color: #8dcffc; } 241 | 242 | .reveal .controls div.navigate-down.enabled:hover { 243 | border-top-color: #8dcffc; } 244 | 245 | /********************************************* 246 | * PROGRESS BAR 247 | *********************************************/ 248 | .reveal .progress { 249 | background: rgba(0, 0, 0, 0.2); } 250 | 251 | .reveal .progress span { 252 | background: #42affa; 253 | -webkit-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 254 | -moz-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 255 | transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); } 256 | 257 | /********************************************* 258 | * SLIDE NUMBER 259 | *********************************************/ 260 | .reveal .slide-number { 261 | color: #42affa; } 262 | -------------------------------------------------------------------------------- /student-handout/static/css/theme/simple.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=News+Cycle:400,700); 2 | @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); 3 | /** 4 | * A simple theme for reveal.js presentations, similar 5 | * to the default theme. The accent color is darkblue. 6 | * 7 | * This theme is Copyright (C) 2012 Owen Versteeg, https://github.com/StereotypicalApps. It is MIT licensed. 8 | * reveal.js is Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se 9 | */ 10 | /********************************************* 11 | * GLOBAL STYLES 12 | *********************************************/ 13 | body { 14 | background: #fff; 15 | background-color: #fff; } 16 | 17 | .reveal { 18 | font-family: 'Lato', sans-serif; 19 | font-size: 36px; 20 | font-weight: normal; 21 | color: #000; } 22 | 23 | ::selection { 24 | color: #fff; 25 | background: rgba(0, 0, 0, 0.99); 26 | text-shadow: none; } 27 | 28 | .reveal .slides > section, .reveal .slides > section > section { 29 | line-height: 1.3; 30 | font-weight: inherit; } 31 | 32 | /********************************************* 33 | * HEADERS 34 | *********************************************/ 35 | .reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6 { 36 | margin: 0 0 20px 0; 37 | color: #000; 38 | font-family: 'News Cycle', Impact, sans-serif; 39 | font-weight: normal; 40 | line-height: 1.2; 41 | letter-spacing: normal; 42 | text-transform: none; 43 | text-shadow: none; 44 | word-wrap: break-word; } 45 | 46 | .reveal h1 { 47 | font-size: 3.77em; } 48 | 49 | .reveal h2 { 50 | font-size: 2em; } 51 | 52 | .reveal h3 { 53 | font-size: 1.55em; } 54 | 55 | .reveal h4 { 56 | font-size: 1em; } 57 | 58 | .reveal h1 { 59 | text-shadow: none; } 60 | 61 | /********************************************* 62 | * OTHER 63 | *********************************************/ 64 | .reveal p { 65 | margin: 20px 0; 66 | line-height: 1.3; } 67 | 68 | /* Ensure certain elements are never larger than the slide itself */ 69 | .reveal img, .reveal video, .reveal iframe { 70 | max-width: 95%; 71 | max-height: 95%; } 72 | 73 | .reveal strong, .reveal b { 74 | font-weight: bold; } 75 | 76 | .reveal em { 77 | font-style: italic; } 78 | 79 | .reveal ol, .reveal dl, .reveal ul { 80 | display: inline-block; 81 | text-align: left; 82 | margin: 0 0 0 1em; } 83 | 84 | .reveal ol { 85 | list-style-type: decimal; } 86 | 87 | .reveal ul { 88 | list-style-type: disc; } 89 | 90 | .reveal ul ul { 91 | list-style-type: square; } 92 | 93 | .reveal ul ul ul { 94 | list-style-type: circle; } 95 | 96 | .reveal ul ul, .reveal ul ol, .reveal ol ol, .reveal ol ul { 97 | display: block; 98 | margin-left: 40px; } 99 | 100 | .reveal dt { 101 | font-weight: bold; } 102 | 103 | .reveal dd { 104 | margin-left: 40px; } 105 | 106 | .reveal q, .reveal blockquote { 107 | quotes: none; } 108 | 109 | .reveal blockquote { 110 | display: block; 111 | position: relative; 112 | width: 70%; 113 | margin: 20px auto; 114 | padding: 5px; 115 | font-style: italic; 116 | background: rgba(255, 255, 255, 0.05); 117 | box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.2); } 118 | 119 | .reveal blockquote p:first-child, .reveal blockquote p:last-child { 120 | display: inline-block; } 121 | 122 | .reveal q { 123 | font-style: italic; } 124 | 125 | .reveal pre { 126 | display: block; 127 | position: relative; 128 | width: 90%; 129 | margin: 20px auto; 130 | text-align: left; 131 | font-size: 0.55em; 132 | font-family: monospace; 133 | line-height: 1.2em; 134 | word-wrap: break-word; 135 | box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.3); } 136 | 137 | .reveal code { 138 | font-family: monospace; } 139 | 140 | .reveal pre code { 141 | display: block; 142 | padding: 5px; 143 | overflow: auto; 144 | max-height: 400px; 145 | word-wrap: normal; 146 | background: #3F3F3F; 147 | color: #DCDCDC; } 148 | 149 | .reveal table { 150 | margin: auto; 151 | border-collapse: collapse; 152 | border-spacing: 0; } 153 | 154 | .reveal table th { 155 | font-weight: bold; } 156 | 157 | .reveal table th, .reveal table td { 158 | text-align: left; 159 | padding: 0.2em 0.5em 0.2em 0.5em; 160 | border-bottom: 1px solid; } 161 | 162 | .reveal table tr:last-child td { 163 | border-bottom: none; } 164 | 165 | .reveal sup { 166 | vertical-align: super; } 167 | 168 | .reveal sub { 169 | vertical-align: sub; } 170 | 171 | .reveal small { 172 | display: inline-block; 173 | font-size: 0.6em; 174 | line-height: 1.2em; 175 | vertical-align: top; } 176 | 177 | .reveal small * { 178 | vertical-align: top; } 179 | 180 | /********************************************* 181 | * LINKS 182 | *********************************************/ 183 | .reveal a { 184 | color: #00008B; 185 | text-decoration: none; 186 | -webkit-transition: color 0.15s ease; 187 | -moz-transition: color 0.15s ease; 188 | transition: color 0.15s ease; } 189 | 190 | .reveal a:hover { 191 | color: #0000f1; 192 | text-shadow: none; 193 | border: none; } 194 | 195 | .reveal .roll span:after { 196 | color: #fff; 197 | background: #00003f; } 198 | 199 | /********************************************* 200 | * IMAGES 201 | *********************************************/ 202 | .reveal section img { 203 | margin: 15px 0px; 204 | background: rgba(255, 255, 255, 0.12); 205 | border: 4px solid #000; 206 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); } 207 | 208 | .reveal a img { 209 | -webkit-transition: all 0.15s linear; 210 | -moz-transition: all 0.15s linear; 211 | transition: all 0.15s linear; } 212 | 213 | .reveal a:hover img { 214 | background: rgba(255, 255, 255, 0.2); 215 | border-color: #00008B; 216 | box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); } 217 | 218 | /********************************************* 219 | * NAVIGATION CONTROLS 220 | *********************************************/ 221 | .reveal .controls div.navigate-left, .reveal .controls div.navigate-left.enabled { 222 | border-right-color: #00008B; } 223 | 224 | .reveal .controls div.navigate-right, .reveal .controls div.navigate-right.enabled { 225 | border-left-color: #00008B; } 226 | 227 | .reveal .controls div.navigate-up, .reveal .controls div.navigate-up.enabled { 228 | border-bottom-color: #00008B; } 229 | 230 | .reveal .controls div.navigate-down, .reveal .controls div.navigate-down.enabled { 231 | border-top-color: #00008B; } 232 | 233 | .reveal .controls div.navigate-left.enabled:hover { 234 | border-right-color: #0000f1; } 235 | 236 | .reveal .controls div.navigate-right.enabled:hover { 237 | border-left-color: #0000f1; } 238 | 239 | .reveal .controls div.navigate-up.enabled:hover { 240 | border-bottom-color: #0000f1; } 241 | 242 | .reveal .controls div.navigate-down.enabled:hover { 243 | border-top-color: #0000f1; } 244 | 245 | /********************************************* 246 | * PROGRESS BAR 247 | *********************************************/ 248 | .reveal .progress { 249 | background: rgba(0, 0, 0, 0.2); } 250 | 251 | .reveal .progress span { 252 | background: #00008B; 253 | -webkit-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 254 | -moz-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 255 | transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); } 256 | 257 | /********************************************* 258 | * SLIDE NUMBER 259 | *********************************************/ 260 | .reveal .slide-number { 261 | color: #00008B; } 262 | -------------------------------------------------------------------------------- /student-handout/static/lib/css/zenburn.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Zenburn style from voldmar.ru (c) Vladimir Epifanov 4 | based on dark.css by Ivan Sagalaev 5 | 6 | */ 7 | 8 | .hljs { 9 | display: block; padding: 0.5em; 10 | background: #3F3F3F; 11 | color: #DCDCDC; 12 | } 13 | 14 | .hljs-keyword, 15 | .hljs-tag, 16 | .css .hljs-class, 17 | .css .hljs-id, 18 | .lisp .hljs-title, 19 | .nginx .hljs-title, 20 | .hljs-request, 21 | .hljs-status, 22 | .clojure .hljs-attribute { 23 | color: #E3CEAB; 24 | } 25 | 26 | .django .hljs-template_tag, 27 | .django .hljs-variable, 28 | .django .hljs-filter .hljs-argument { 29 | color: #DCDCDC; 30 | } 31 | 32 | .hljs-number, 33 | .hljs-date { 34 | color: #8CD0D3; 35 | } 36 | 37 | .dos .hljs-envvar, 38 | .dos .hljs-stream, 39 | .hljs-variable, 40 | .apache .hljs-sqbracket { 41 | color: #EFDCBC; 42 | } 43 | 44 | .dos .hljs-flow, 45 | .diff .hljs-change, 46 | .python .exception, 47 | .python .hljs-built_in, 48 | .hljs-literal, 49 | .tex .hljs-special { 50 | color: #EFEFAF; 51 | } 52 | 53 | .diff .hljs-chunk, 54 | .hljs-subst { 55 | color: #8F8F8F; 56 | } 57 | 58 | .dos .hljs-keyword, 59 | .python .hljs-decorator, 60 | .hljs-title, 61 | .haskell .hljs-type, 62 | .diff .hljs-header, 63 | .ruby .hljs-class .hljs-parent, 64 | .apache .hljs-tag, 65 | .nginx .hljs-built_in, 66 | .tex .hljs-command, 67 | .hljs-prompt { 68 | color: #efef8f; 69 | } 70 | 71 | .dos .hljs-winutils, 72 | .ruby .hljs-symbol, 73 | .ruby .hljs-symbol .hljs-string, 74 | .ruby .hljs-string { 75 | color: #DCA3A3; 76 | } 77 | 78 | .diff .hljs-deletion, 79 | .hljs-string, 80 | .hljs-tag .hljs-value, 81 | .hljs-preprocessor, 82 | .hljs-pragma, 83 | .hljs-built_in, 84 | .sql .hljs-aggregate, 85 | .hljs-javadoc, 86 | .smalltalk .hljs-class, 87 | .smalltalk .hljs-localvars, 88 | .smalltalk .hljs-array, 89 | .css .hljs-rules .hljs-value, 90 | .hljs-attr_selector, 91 | .hljs-pseudo, 92 | .apache .hljs-cbracket, 93 | .tex .hljs-formula, 94 | .coffeescript .hljs-attribute { 95 | color: #CC9393; 96 | } 97 | 98 | .hljs-shebang, 99 | .diff .hljs-addition, 100 | .hljs-comment, 101 | .java .hljs-annotation, 102 | .hljs-template_comment, 103 | .hljs-pi, 104 | .hljs-doctype { 105 | color: #7F9F7F; 106 | } 107 | 108 | .coffeescript .javascript, 109 | .javascript .xml, 110 | .tex .hljs-formula, 111 | .xml .javascript, 112 | .xml .vbscript, 113 | .xml .css, 114 | .xml .hljs-cdata { 115 | opacity: 0.5; 116 | } 117 | 118 | -------------------------------------------------------------------------------- /student-handout/static/lib/font/source-sans-pro/source-sans-pro-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/django-security-tutorials/hands-on-web-security-slides/471b4c53d7e1b64a0ebc5f7af1dc054a665c4bdc/student-handout/static/lib/font/source-sans-pro/source-sans-pro-italic.woff -------------------------------------------------------------------------------- /student-handout/static/lib/font/source-sans-pro/source-sans-pro-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/django-security-tutorials/hands-on-web-security-slides/471b4c53d7e1b64a0ebc5f7af1dc054a665c4bdc/student-handout/static/lib/font/source-sans-pro/source-sans-pro-regular.woff -------------------------------------------------------------------------------- /student-handout/static/lib/font/source-sans-pro/source-sans-pro-semibold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/django-security-tutorials/hands-on-web-security-slides/471b4c53d7e1b64a0ebc5f7af1dc054a665c4bdc/student-handout/static/lib/font/source-sans-pro/source-sans-pro-semibold.woff -------------------------------------------------------------------------------- /student-handout/static/lib/font/source-sans-pro/source-sans-pro.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Source Sans Pro'; 3 | src: url('source-sans-pro-regular.eot'); 4 | src: url('source-sans-pro-regular.eot?#iefix') format('embedded-opentype'), 5 | url('source-sans-pro-regular.woff') format('woff'), 6 | url('source-sans-pro-regular.ttf') format('truetype'); 7 | font-weight: normal; 8 | font-style: normal; 9 | } 10 | 11 | @font-face { 12 | font-family: 'Source Sans Pro'; 13 | src: url('source-sans-pro-italic.eot'); 14 | src: url('source-sans-pro-italic.eot?#iefix') format('embedded-opentype'), 15 | url('source-sans-pro-italic.woff') format('woff'), 16 | url('source-sans-pro-italic.ttf') format('truetype'); 17 | font-weight: normal; 18 | font-style: italic; 19 | } 20 | 21 | @font-face { 22 | font-family: 'Source Sans Pro'; 23 | src: url('source-sans-pro-semibold.eot'); 24 | src: url('source-sans-pro-semibold.eot?#iefix') format('embedded-opentype'), 25 | url('source-sans-pro-semibold.woff') format('woff'), 26 | url('source-sans-pro-semibold.ttf') format('truetype'); 27 | font-weight: 600; 28 | font-style: normal; 29 | } 30 | 31 | @font-face { 32 | font-family: 'Source Sans Pro'; 33 | src: url('source-sans-pro-semibolditalic.eot'); 34 | src: url('source-sans-pro-semibolditalic.eot?#iefix') format('embedded-opentype'), 35 | url('source-sans-pro-semibolditalic.woff') format('woff'), 36 | url('source-sans-pro-semibolditalic.ttf') format('truetype'); 37 | font-weight: 600; 38 | font-style: italic; 39 | } -------------------------------------------------------------------------------- /student-handout/static/lib/js/head.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | Head JS The only script in your 3 | Copyright Tero Piirainen (tipiirai) 4 | License MIT / http://bit.ly/mit-license 5 | Version 0.96 6 | 7 | http://headjs.com 8 | */(function(a){function z(){d||(d=!0,s(e,function(a){p(a)}))}function y(c,d){var e=a.createElement("script");e.type="text/"+(c.type||"javascript"),e.src=c.src||c,e.async=!1,e.onreadystatechange=e.onload=function(){var a=e.readyState;!d.done&&(!a||/loaded|complete/.test(a))&&(d.done=!0,d())},(a.body||b).appendChild(e)}function x(a,b){if(a.state==o)return b&&b();if(a.state==n)return k.ready(a.name,b);if(a.state==m)return a.onpreload.push(function(){x(a,b)});a.state=n,y(a.url,function(){a.state=o,b&&b(),s(g[a.name],function(a){p(a)}),u()&&d&&s(g.ALL,function(a){p(a)})})}function w(a,b){a.state===undefined&&(a.state=m,a.onpreload=[],y({src:a.url,type:"cache"},function(){v(a)}))}function v(a){a.state=l,s(a.onpreload,function(a){a.call()})}function u(a){a=a||h;var b;for(var c in a){if(a.hasOwnProperty(c)&&a[c].state!=o)return!1;b=!0}return b}function t(a){return Object.prototype.toString.call(a)=="[object Function]"}function s(a,b){if(!!a){typeof a=="object"&&(a=[].slice.call(a));for(var c=0;c 0 ) { 50 | text = text.replace( new RegExp('\\n?\\t{' + leadingTabs + '}','g'), '\n' ); 51 | } 52 | else if( leadingWs > 1 ) { 53 | text = text.replace( new RegExp('\\n? {' + leadingWs + '}'), '\n' ); 54 | } 55 | 56 | return text; 57 | 58 | } 59 | 60 | /** 61 | * Given a markdown slide section element, this will 62 | * return all arguments that aren't related to markdown 63 | * parsing. Used to forward any other user-defined arguments 64 | * to the output markdown slide. 65 | */ 66 | function getForwardedAttributes( section ) { 67 | 68 | var attributes = section.attributes; 69 | var result = []; 70 | 71 | for( var i = 0, len = attributes.length; i < len; i++ ) { 72 | var name = attributes[i].name, 73 | value = attributes[i].value; 74 | 75 | // disregard attributes that are used for markdown loading/parsing 76 | if( /data\-(markdown|separator|vertical|notes)/gi.test( name ) ) continue; 77 | 78 | if( value ) { 79 | result.push( name + '=' + value ); 80 | } 81 | else { 82 | result.push( name ); 83 | } 84 | } 85 | 86 | return result.join( ' ' ); 87 | 88 | } 89 | 90 | /** 91 | * Inspects the given options and fills out default 92 | * values for what's not defined. 93 | */ 94 | function getSlidifyOptions( options ) { 95 | 96 | options = options || {}; 97 | options.separator = options.separator || DEFAULT_SLIDE_SEPARATOR; 98 | options.notesSeparator = options.notesSeparator || DEFAULT_NOTES_SEPARATOR; 99 | options.attributes = options.attributes || ''; 100 | 101 | return options; 102 | 103 | } 104 | 105 | /** 106 | * Helper function for constructing a markdown slide. 107 | */ 108 | function createMarkdownSlide( content, options ) { 109 | 110 | options = getSlidifyOptions( options ); 111 | 112 | var notesMatch = content.split( new RegExp( options.notesSeparator, 'mgi' ) ); 113 | 114 | if( notesMatch.length === 2 ) { 115 | content = notesMatch[0] + ''; 116 | } 117 | 118 | return ''; 119 | 120 | } 121 | 122 | /** 123 | * Parses a data string into multiple slides based 124 | * on the passed in separator arguments. 125 | */ 126 | function slidify( markdown, options ) { 127 | 128 | options = getSlidifyOptions( options ); 129 | 130 | var separatorRegex = new RegExp( options.separator + ( options.verticalSeparator ? '|' + options.verticalSeparator : '' ), 'mg' ), 131 | horizontalSeparatorRegex = new RegExp( options.separator ); 132 | 133 | var matches, 134 | lastIndex = 0, 135 | isHorizontal, 136 | wasHorizontal = true, 137 | content, 138 | sectionStack = []; 139 | 140 | // iterate until all blocks between separators are stacked up 141 | while( matches = separatorRegex.exec( markdown ) ) { 142 | notes = null; 143 | 144 | // determine direction (horizontal by default) 145 | isHorizontal = horizontalSeparatorRegex.test( matches[0] ); 146 | 147 | if( !isHorizontal && wasHorizontal ) { 148 | // create vertical stack 149 | sectionStack.push( [] ); 150 | } 151 | 152 | // pluck slide content from markdown input 153 | content = markdown.substring( lastIndex, matches.index ); 154 | 155 | if( isHorizontal && wasHorizontal ) { 156 | // add to horizontal stack 157 | sectionStack.push( content ); 158 | } 159 | else { 160 | // add to vertical stack 161 | sectionStack[sectionStack.length-1].push( content ); 162 | } 163 | 164 | lastIndex = separatorRegex.lastIndex; 165 | wasHorizontal = isHorizontal; 166 | } 167 | 168 | // add the remaining slide 169 | ( wasHorizontal ? sectionStack : sectionStack[sectionStack.length-1] ).push( markdown.substring( lastIndex ) ); 170 | 171 | var markdownSections = ''; 172 | 173 | // flatten the hierarchical stack, and insert
    tags 174 | for( var i = 0, len = sectionStack.length; i < len; i++ ) { 175 | // vertical 176 | if( sectionStack[i] instanceof Array ) { 177 | markdownSections += '
    '; 178 | 179 | sectionStack[i].forEach( function( child ) { 180 | markdownSections += '
    ' + createMarkdownSlide( child, options ) + '
    '; 181 | } ); 182 | 183 | markdownSections += '
    '; 184 | } 185 | else { 186 | markdownSections += '
    ' + createMarkdownSlide( sectionStack[i], options ) + '
    '; 187 | } 188 | } 189 | 190 | return markdownSections; 191 | 192 | } 193 | 194 | /** 195 | * Parses any current data-markdown slides, splits 196 | * multi-slide markdown into separate sections and 197 | * handles loading of external markdown. 198 | */ 199 | function processSlides() { 200 | 201 | var sections = document.querySelectorAll( '[data-markdown]'), 202 | section; 203 | 204 | for( var i = 0, len = sections.length; i < len; i++ ) { 205 | 206 | section = sections[i]; 207 | 208 | if( section.getAttribute( 'data-markdown' ).length ) { 209 | 210 | var xhr = new XMLHttpRequest(), 211 | url = section.getAttribute( 'data-markdown' ); 212 | 213 | datacharset = section.getAttribute( 'data-charset' ); 214 | 215 | // see https://developer.mozilla.org/en-US/docs/Web/API/element.getAttribute#Notes 216 | if( datacharset != null && datacharset != '' ) { 217 | xhr.overrideMimeType( 'text/html; charset=' + datacharset ); 218 | } 219 | 220 | xhr.onreadystatechange = function() { 221 | if( xhr.readyState === 4 ) { 222 | // file protocol yields status code 0 (useful for local debug, mobile applications etc.) 223 | if ( ( xhr.status >= 200 && xhr.status < 300 ) || xhr.status === 0 ) { 224 | 225 | section.outerHTML = slidify( xhr.responseText, { 226 | separator: section.getAttribute( 'data-separator' ), 227 | verticalSeparator: section.getAttribute( 'data-separator-vertical' ), 228 | notesSeparator: section.getAttribute( 'data-separator-notes' ), 229 | attributes: getForwardedAttributes( section ) 230 | }); 231 | 232 | } 233 | else { 234 | 235 | section.outerHTML = '
    ' + 236 | 'ERROR: The attempt to fetch ' + url + ' failed with HTTP status ' + xhr.status + '.' + 237 | 'Check your browser\'s JavaScript console for more details.' + 238 | '

    Remember that you need to serve the presentation HTML from a HTTP server.

    ' + 239 | '
    '; 240 | 241 | } 242 | } 243 | }; 244 | 245 | xhr.open( 'GET', url, false ); 246 | 247 | try { 248 | xhr.send(); 249 | } 250 | catch ( e ) { 251 | alert( 'Failed to get the Markdown file ' + url + '. Make sure that the presentation and the file are served by a HTTP server and the file can be found there. ' + e ); 252 | } 253 | 254 | } 255 | else if( section.getAttribute( 'data-separator' ) || section.getAttribute( 'data-separator-vertical' ) || section.getAttribute( 'data-separator-notes' ) ) { 256 | 257 | section.outerHTML = slidify( getMarkdownFromSlide( section ), { 258 | separator: section.getAttribute( 'data-separator' ), 259 | verticalSeparator: section.getAttribute( 'data-separator-vertical' ), 260 | notesSeparator: section.getAttribute( 'data-separator-notes' ), 261 | attributes: getForwardedAttributes( section ) 262 | }); 263 | 264 | } 265 | else { 266 | section.innerHTML = createMarkdownSlide( getMarkdownFromSlide( section ) ); 267 | } 268 | } 269 | 270 | } 271 | 272 | /** 273 | * Check if a node value has the attributes pattern. 274 | * If yes, extract it and add that value as one or several attributes 275 | * the the terget element. 276 | * 277 | * You need Cache Killer on Chrome to see the effect on any FOM transformation 278 | * directly on refresh (F5) 279 | * http://stackoverflow.com/questions/5690269/disabling-chrome-cache-for-website-development/7000899#answer-11786277 280 | */ 281 | function addAttributeInElement( node, elementTarget, separator ) { 282 | 283 | var mardownClassesInElementsRegex = new RegExp( separator, 'mg' ); 284 | var mardownClassRegex = new RegExp( "([^\"= ]+?)=\"([^\"=]+?)\"", 'mg' ); 285 | var nodeValue = node.nodeValue; 286 | if( matches = mardownClassesInElementsRegex.exec( nodeValue ) ) { 287 | 288 | var classes = matches[1]; 289 | nodeValue = nodeValue.substring( 0, matches.index ) + nodeValue.substring( mardownClassesInElementsRegex.lastIndex ); 290 | node.nodeValue = nodeValue; 291 | while( matchesClass = mardownClassRegex.exec( classes ) ) { 292 | elementTarget.setAttribute( matchesClass[1], matchesClass[2] ); 293 | } 294 | return true; 295 | } 296 | return false; 297 | } 298 | 299 | /** 300 | * Add attributes to the parent element of a text node, 301 | * or the element of an attribute node. 302 | */ 303 | function addAttributes( section, element, previousElement, separatorElementAttributes, separatorSectionAttributes ) { 304 | 305 | if ( element != null && element.childNodes != undefined && element.childNodes.length > 0 ) { 306 | previousParentElement = element; 307 | for( var i = 0; i < element.childNodes.length; i++ ) { 308 | childElement = element.childNodes[i]; 309 | if ( i > 0 ) { 310 | j = i - 1; 311 | while ( j >= 0 ) { 312 | aPreviousChildElement = element.childNodes[j]; 313 | if ( typeof aPreviousChildElement.setAttribute == 'function' && aPreviousChildElement.tagName != "BR" ) { 314 | previousParentElement = aPreviousChildElement; 315 | break; 316 | } 317 | j = j - 1; 318 | } 319 | } 320 | parentSection = section; 321 | if( childElement.nodeName == "section" ) { 322 | parentSection = childElement ; 323 | previousParentElement = childElement ; 324 | } 325 | if ( typeof childElement.setAttribute == 'function' || childElement.nodeType == Node.COMMENT_NODE ) { 326 | addAttributes( parentSection, childElement, previousParentElement, separatorElementAttributes, separatorSectionAttributes ); 327 | } 328 | } 329 | } 330 | 331 | if ( element.nodeType == Node.COMMENT_NODE ) { 332 | if ( addAttributeInElement( element, previousElement, separatorElementAttributes ) == false ) { 333 | addAttributeInElement( element, section, separatorSectionAttributes ); 334 | } 335 | } 336 | } 337 | 338 | /** 339 | * Converts any current data-markdown slides in the 340 | * DOM to HTML. 341 | */ 342 | function convertSlides() { 343 | 344 | var sections = document.querySelectorAll( '[data-markdown]'); 345 | 346 | for( var i = 0, len = sections.length; i < len; i++ ) { 347 | 348 | var section = sections[i]; 349 | 350 | // Only parse the same slide once 351 | if( !section.getAttribute( 'data-markdown-parsed' ) ) { 352 | 353 | section.setAttribute( 'data-markdown-parsed', true ) 354 | 355 | var notes = section.querySelector( 'aside.notes' ); 356 | var markdown = getMarkdownFromSlide( section ); 357 | 358 | section.innerHTML = marked( markdown ); 359 | addAttributes( section, section, null, section.getAttribute( 'data-element-attributes' ) || 360 | section.parentNode.getAttribute( 'data-element-attributes' ) || 361 | DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR, 362 | section.getAttribute( 'data-attributes' ) || 363 | section.parentNode.getAttribute( 'data-attributes' ) || 364 | DEFAULT_SLIDE_ATTRIBUTES_SEPARATOR); 365 | 366 | // If there were notes, we need to re-add them after 367 | // having overwritten the section's HTML 368 | if( notes ) { 369 | section.appendChild( notes ); 370 | } 371 | 372 | } 373 | 374 | } 375 | 376 | } 377 | 378 | // API 379 | return { 380 | 381 | initialize: function() { 382 | processSlides(); 383 | convertSlides(); 384 | }, 385 | 386 | // TODO: Do these belong in the API? 387 | processSlides: processSlides, 388 | convertSlides: convertSlides, 389 | slidify: slidify 390 | 391 | }; 392 | 393 | })); 394 | -------------------------------------------------------------------------------- /student-handout/static/plugin/markdown/marked.js: -------------------------------------------------------------------------------- 1 | /** 2 | * marked - a markdown parser 3 | * Copyright (c) 2011-2013, Christopher Jeffrey. (MIT Licensed) 4 | * https://github.com/chjj/marked 5 | */ 6 | 7 | (function(){var block={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:noop,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:noop,lheading:/^([^\n]+)\n *(=|-){3,} *\n*/,blockquote:/^( *>[^\n]+(\n[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,def:/^ *\[([^\]]+)\]: *]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:noop,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/, 8 | text:/^[^\n]+/};block.bullet=/(?:[*+-]|\d+\.)/;block.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr",/\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|@)\\b";block.html=replace(block.html)("comment",/\x3c!--[\s\S]*?--\x3e/)("closed", 9 | /<(tag)[\s\S]+?<\/\1>/)("closing",/])*?>/)(/tag/g,block._tag)();block.paragraph=replace(block.paragraph)("hr",block.hr)("heading",block.heading)("lheading",block.lheading)("blockquote",block.blockquote)("tag","<"+block._tag)("def",block.def)();block.normal=merge({},block);block.gfm=merge({},block.normal,{fences:/^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,paragraph:/^/});block.gfm.paragraph=replace(block.paragraph)("(?!","(?!"+block.gfm.fences.source.replace("\\1", 10 | "\\2")+"|")();block.tables=merge({},block.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/});function Lexer(options){this.tokens=[];this.tokens.links={};this.options=options||marked.defaults;this.rules=block.normal;if(this.options.gfm)if(this.options.tables)this.rules=block.tables;else this.rules=block.gfm}Lexer.rules=block;Lexer.lex=function(src,options){var lexer=new Lexer(options);return lexer.lex(src)}; 11 | Lexer.prototype.lex=function(src){src=src.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n");return this.token(src,true)};Lexer.prototype.token=function(src,top){var src=src.replace(/^ +$/gm,""),next,loose,cap,bull,b,item,space,i,l;while(src){if(cap=this.rules.newline.exec(src)){src=src.substring(cap[0].length);if(cap[0].length>1)this.tokens.push({type:"space"})}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);cap=cap[0].replace(/^ {4}/gm, 12 | "");this.tokens.push({type:"code",text:!this.options.pedantic?cap.replace(/\n+$/,""):cap});continue}if(cap=this.rules.fences.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"code",lang:cap[2],text:cap[3]});continue}if(cap=this.rules.heading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[1].length,text:cap[2]});continue}if(top&&(cap=this.rules.nptable.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g, 13 | "").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/\n$/,"").split("\n")};for(i=0;i ?/gm,"");this.token(cap,top);this.tokens.push({type:"blockquote_end"});continue}if(cap=this.rules.list.exec(src)){src=src.substring(cap[0].length); 15 | bull=cap[2];this.tokens.push({type:"list_start",ordered:bull.length>1});cap=cap[0].match(this.rules.item);next=false;l=cap.length;i=0;for(;i1&&b.length>1)){src=cap.slice(i+ 16 | 1).join("\n")+src;i=l-1}}loose=next||/\n\n(?!\s*$)/.test(item);if(i!==l-1){next=item[item.length-1]==="\n";if(!loose)loose=next}this.tokens.push({type:loose?"loose_item_start":"list_item_start"});this.token(item,false);this.tokens.push({type:"list_item_end"})}this.tokens.push({type:"list_end"});continue}if(cap=this.rules.html.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:cap[1]==="pre"||cap[1]==="script",text:cap[0]});continue}if(top&& 17 | (cap=this.rules.def.exec(src))){src=src.substring(cap[0].length);this.tokens.links[cap[1].toLowerCase()]={href:cap[2],title:cap[3]};continue}if(top&&(cap=this.rules.table.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/(?: *\| *)?\n$/,"").split("\n")};for(i=0;i])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:noop,tag:/^\x3c!--[\s\S]*?--\x3e|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/, 20 | code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:noop,text:/^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/;inline.link=replace(inline.link)("inside",inline._inside)("href",inline._href)();inline.reflink=replace(inline.reflink)("inside",inline._inside)();inline.normal=merge({},inline);inline.pedantic=merge({},inline.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/, 21 | em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/});inline.gfm=merge({},inline.normal,{escape:replace(inline.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:replace(inline.text)("]|","~]|")("|","|https?://|")()});inline.breaks=merge({},inline.gfm,{br:replace(inline.br)("{2,}","*")(),text:replace(inline.gfm.text)("{2,}","*")()});function InlineLexer(links,options){this.options=options||marked.defaults;this.links=links;this.rules=inline.normal; 22 | if(!this.links)throw new Error("Tokens array requires a `links` property.");if(this.options.gfm)if(this.options.breaks)this.rules=inline.breaks;else this.rules=inline.gfm;else if(this.options.pedantic)this.rules=inline.pedantic}InlineLexer.rules=inline;InlineLexer.output=function(src,links,options){var inline=new InlineLexer(links,options);return inline.output(src)};InlineLexer.prototype.output=function(src){var out="",link,text,href,cap;while(src){if(cap=this.rules.escape.exec(src)){src=src.substring(cap[0].length); 23 | out+=cap[1];continue}if(cap=this.rules.autolink.exec(src)){src=src.substring(cap[0].length);if(cap[2]==="@"){text=cap[1][6]===":"?this.mangle(cap[1].substring(7)):this.mangle(cap[1]);href=this.mangle("mailto:")+text}else{text=escape(cap[1]);href=text}out+=''+text+"";continue}if(cap=this.rules.url.exec(src)){src=src.substring(cap[0].length);text=escape(cap[1]);href=text;out+=''+text+"";continue}if(cap=this.rules.tag.exec(src)){src=src.substring(cap[0].length); 24 | out+=this.options.sanitize?escape(cap[0]):cap[0];continue}if(cap=this.rules.link.exec(src)){src=src.substring(cap[0].length);out+=this.outputLink(cap,{href:cap[2],title:cap[3]});continue}if((cap=this.rules.reflink.exec(src))||(cap=this.rules.nolink.exec(src))){src=src.substring(cap[0].length);link=(cap[2]||cap[1]).replace(/\s+/g," ");link=this.links[link.toLowerCase()];if(!link||!link.href){out+=cap[0][0];src=cap[0].substring(1)+src;continue}out+=this.outputLink(cap,link);continue}if(cap=this.rules.strong.exec(src)){src= 25 | src.substring(cap[0].length);out+=""+this.output(cap[2]||cap[1])+"";continue}if(cap=this.rules.em.exec(src)){src=src.substring(cap[0].length);out+=""+this.output(cap[2]||cap[1])+"";continue}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);out+=""+escape(cap[2],true)+"";continue}if(cap=this.rules.br.exec(src)){src=src.substring(cap[0].length);out+="
    ";continue}if(cap=this.rules.del.exec(src)){src=src.substring(cap[0].length);out+=""+ 26 | this.output(cap[1])+"";continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);out+=escape(cap[0]);continue}if(src)throw new Error("Infinite loop on byte: "+src.charCodeAt(0));}return out};InlineLexer.prototype.outputLink=function(cap,link){if(cap[0][0]!=="!")return'"+this.output(cap[1])+"";else return''+escape(cap[1])+'"};InlineLexer.prototype.smartypants=function(text){if(!this.options.smartypants)return text;return text.replace(/--/g,"\u2014").replace(/'([^']*)'/g,"\u2018$1\u2019").replace(/"([^"]*)"/g,"\u201c$1\u201d").replace(/\.{3}/g,"\u2026")};InlineLexer.prototype.mangle=function(text){var out="",l=text.length,i=0,ch;for(;i0.5)ch="x"+ch.toString(16);out+="&#"+ch+";"}return out};function Parser(options){this.tokens=[];this.token=null; 28 | this.options=options||marked.defaults}Parser.parse=function(src,options){var parser=new Parser(options);return parser.parse(src)};Parser.prototype.parse=function(src){this.inline=new InlineLexer(src.links,this.options);this.tokens=src.reverse();var out="";while(this.next())out+=this.tok();return out};Parser.prototype.next=function(){return this.token=this.tokens.pop()};Parser.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0};Parser.prototype.parseText=function(){var body=this.token.text; 29 | while(this.peek().type==="text")body+="\n"+this.next().text;return this.inline.output(body)};Parser.prototype.tok=function(){switch(this.token.type){case "space":return"";case "hr":return"
    \n";case "heading":return""+this.inline.output(this.token.text)+"\n";case "code":if(this.options.highlight){var code=this.options.highlight(this.token.text,this.token.lang);if(code!=null&&code!==this.token.text){this.token.escaped=true;this.token.text=code}}if(!this.token.escaped)this.token.text= 30 | escape(this.token.text,true);return"
    "+this.token.text+"
    \n";case "table":var body="",heading,i,row,cell,j;body+="\n\n";for(i=0;i'+heading+"\n":""+heading+"\n"}body+="\n\n";body+="\n";for(i=0;i'+cell+"\n":""+cell+"\n"}body+="\n"}body+="\n";return"\n"+body+"
    \n";case "blockquote_start":var body="";while(this.next().type!=="blockquote_end")body+=this.tok();return"
    \n"+body+"
    \n";case "list_start":var type=this.token.ordered?"ol":"ul",body="";while(this.next().type!=="list_end")body+= 32 | this.tok();return"<"+type+">\n"+body+"\n";case "list_item_start":var body="";while(this.next().type!=="list_item_end")body+=this.token.type==="text"?this.parseText():this.tok();return"
  • "+body+"
  • \n";case "loose_item_start":var body="";while(this.next().type!=="list_item_end")body+=this.tok();return"
  • "+body+"
  • \n";case "html":return!this.token.pre&&!this.options.pedantic?this.inline.output(this.token.text):this.token.text;case "paragraph":return"

    "+this.inline.output(this.token.text)+ 33 | "

    \n";case "text":return"

    "+this.parseText()+"

    \n"}};function escape(html,encode){return html.replace(!encode?/&(?!#?\w+;)/g:/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function replace(regex,opt){regex=regex.source;opt=opt||"";return function self(name,val){if(!name)return new RegExp(regex,opt);val=val.source||val;val=val.replace(/(^|[^\[])\^/g,"$1");regex=regex.replace(name,val);return self}}function noop(){}noop.exec=noop;function merge(obj){var i= 34 | 1,target,key;for(;iAn error occured:

    "+escape(e.message+"",true)+"
    ";throw e;}}marked.options=marked.setOptions=function(opt){merge(marked.defaults,opt);return marked};marked.defaults={gfm:true,tables:true,breaks:false,pedantic:false,sanitize:false,smartLists:false,silent:false,highlight:null,langPrefix:""};marked.Parser=Parser;marked.parser=Parser.parse;marked.Lexer=Lexer;marked.lexer=Lexer.lex;marked.InlineLexer=InlineLexer;marked.inlineLexer=InlineLexer.output; 37 | marked.parse=marked;if(typeof exports==="object")module.exports=marked;else if(typeof define==="function"&&define.amd)define(function(){return marked});else this.marked=marked}).call(function(){return this||(typeof window!=="undefined"?window:global)}()); 38 | -------------------------------------------------------------------------------- /student-handout/static/plugin/notes/notes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | reveal.js - Slide Notes 7 | 8 | 151 | 152 | 153 | 154 | 155 |
    156 |
    UPCOMING:
    157 |
    158 |
    159 |

    Time Click to Reset

    160 |
    161 | 0:00 AM 162 |
    163 |
    164 | 00:00:00 165 |
    166 |
    167 |
    168 | 169 | 173 |
    174 | 175 | 176 | 405 | 406 | 407 | -------------------------------------------------------------------------------- /student-handout/static/plugin/notes/notes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Handles opening of and synchronization with the reveal.js 3 | * notes window. 4 | * 5 | * Handshake process: 6 | * 1. This window posts 'connect' to notes window 7 | * - Includes URL of presentation to show 8 | * 2. Notes window responds with 'connected' when it is available 9 | * 3. This window proceeds to send the current presentation state 10 | * to the notes window 11 | */ 12 | var RevealNotes = (function() { 13 | 14 | function openNotes() { 15 | var jsFileLocation = document.querySelector('script[src$="notes.js"]').src; // this js file path 16 | jsFileLocation = jsFileLocation.replace(/notes\.js(\?.*)?$/, ''); // the js folder path 17 | var notesPopup = window.open( jsFileLocation + 'notes.html', 'reveal.js - Notes', 'width=1100,height=700' ); 18 | 19 | /** 20 | * Connect to the notes window through a postmessage handshake. 21 | * Using postmessage enables us to work in situations where the 22 | * origins differ, such as a presentation being opened from the 23 | * file system. 24 | */ 25 | function connect() { 26 | // Keep trying to connect until we get a 'connected' message back 27 | var connectInterval = setInterval( function() { 28 | notesPopup.postMessage( JSON.stringify( { 29 | namespace: 'reveal-notes', 30 | type: 'connect', 31 | url: window.location.protocol + '//' + window.location.host + window.location.pathname, 32 | state: Reveal.getState() 33 | } ), '*' ); 34 | }, 500 ); 35 | 36 | window.addEventListener( 'message', function( event ) { 37 | var data = JSON.parse( event.data ); 38 | if( data && data.namespace === 'reveal-notes' && data.type === 'connected' ) { 39 | clearInterval( connectInterval ); 40 | onConnected(); 41 | } 42 | } ); 43 | } 44 | 45 | /** 46 | * Posts the current slide data to the notes window 47 | */ 48 | function post() { 49 | 50 | var slideElement = Reveal.getCurrentSlide(), 51 | notesElement = slideElement.querySelector( 'aside.notes' ); 52 | 53 | var messageData = { 54 | namespace: 'reveal-notes', 55 | type: 'state', 56 | notes: '', 57 | markdown: false, 58 | state: Reveal.getState() 59 | }; 60 | 61 | // Look for notes defined in a slide attribute 62 | if( slideElement.hasAttribute( 'data-notes' ) ) { 63 | messageData.notes = slideElement.getAttribute( 'data-notes' ); 64 | } 65 | 66 | // Look for notes defined in an aside element 67 | if( notesElement ) { 68 | messageData.notes = notesElement.innerHTML; 69 | messageData.markdown = typeof notesElement.getAttribute( 'data-markdown' ) === 'string'; 70 | } 71 | 72 | notesPopup.postMessage( JSON.stringify( messageData ), '*' ); 73 | 74 | } 75 | 76 | /** 77 | * Called once we have established a connection to the notes 78 | * window. 79 | */ 80 | function onConnected() { 81 | 82 | // Monitor events that trigger a change in state 83 | Reveal.addEventListener( 'slidechanged', post ); 84 | Reveal.addEventListener( 'fragmentshown', post ); 85 | Reveal.addEventListener( 'fragmenthidden', post ); 86 | Reveal.addEventListener( 'overviewhidden', post ); 87 | Reveal.addEventListener( 'overviewshown', post ); 88 | Reveal.addEventListener( 'paused', post ); 89 | Reveal.addEventListener( 'resumed', post ); 90 | 91 | // Post the initial state 92 | post(); 93 | 94 | } 95 | 96 | connect(); 97 | } 98 | 99 | if( !/receiver/i.test( window.location.search ) ) { 100 | 101 | // If the there's a 'notes' query set, open directly 102 | if( window.location.search.match( /(\?|\&)notes/gi ) !== null ) { 103 | openNotes(); 104 | } 105 | 106 | // Open the notes when the 's' key is hit 107 | document.addEventListener( 'keydown', function( event ) { 108 | // Disregard the event if the target is editable or a 109 | // modifier is present 110 | if ( document.querySelector( ':focus' ) !== null || event.shiftKey || event.altKey || event.ctrlKey || event.metaKey ) return; 111 | 112 | if( event.keyCode === 83 ) { 113 | event.preventDefault(); 114 | openNotes(); 115 | } 116 | }, false ); 117 | 118 | } 119 | 120 | return { open: openNotes }; 121 | 122 | })(); 123 | -------------------------------------------------------------------------------- /student-handout/static/plugin/zoom-js/zoom.js: -------------------------------------------------------------------------------- 1 | // Custom reveal.js integration 2 | (function(){ 3 | var isEnabled = true; 4 | 5 | document.querySelector( '.reveal' ).addEventListener( 'mousedown', function( event ) { 6 | var modifier = ( Reveal.getConfig().zoomKey ? Reveal.getConfig().zoomKey : 'alt' ) + 'Key'; 7 | 8 | var zoomPadding = 20; 9 | var revealScale = Reveal.getScale(); 10 | 11 | if( event[ modifier ] && isEnabled ) { 12 | event.preventDefault(); 13 | 14 | var bounds = event.target.getBoundingClientRect(); 15 | 16 | zoom.to({ 17 | x: ( bounds.left * revealScale ) - zoomPadding, 18 | y: ( bounds.top * revealScale ) - zoomPadding, 19 | width: ( bounds.width * revealScale ) + ( zoomPadding * 2 ), 20 | height: ( bounds.height * revealScale ) + ( zoomPadding * 2 ), 21 | pan: false 22 | }); 23 | } 24 | } ); 25 | 26 | Reveal.addEventListener( 'overviewshown', function() { isEnabled = false; } ); 27 | Reveal.addEventListener( 'overviewhidden', function() { isEnabled = true; } ); 28 | })(); 29 | 30 | /*! 31 | * zoom.js 0.3 (modified for use with reveal.js) 32 | * http://lab.hakim.se/zoom-js 33 | * MIT licensed 34 | * 35 | * Copyright (C) 2011-2014 Hakim El Hattab, http://hakim.se 36 | */ 37 | var zoom = (function(){ 38 | 39 | // The current zoom level (scale) 40 | var level = 1; 41 | 42 | // The current mouse position, used for panning 43 | var mouseX = 0, 44 | mouseY = 0; 45 | 46 | // Timeout before pan is activated 47 | var panEngageTimeout = -1, 48 | panUpdateInterval = -1; 49 | 50 | // Check for transform support so that we can fallback otherwise 51 | var supportsTransforms = 'WebkitTransform' in document.body.style || 52 | 'MozTransform' in document.body.style || 53 | 'msTransform' in document.body.style || 54 | 'OTransform' in document.body.style || 55 | 'transform' in document.body.style; 56 | 57 | if( supportsTransforms ) { 58 | // The easing that will be applied when we zoom in/out 59 | document.body.style.transition = 'transform 0.8s ease'; 60 | document.body.style.OTransition = '-o-transform 0.8s ease'; 61 | document.body.style.msTransition = '-ms-transform 0.8s ease'; 62 | document.body.style.MozTransition = '-moz-transform 0.8s ease'; 63 | document.body.style.WebkitTransition = '-webkit-transform 0.8s ease'; 64 | } 65 | 66 | // Zoom out if the user hits escape 67 | document.addEventListener( 'keyup', function( event ) { 68 | if( level !== 1 && event.keyCode === 27 ) { 69 | zoom.out(); 70 | } 71 | } ); 72 | 73 | // Monitor mouse movement for panning 74 | document.addEventListener( 'mousemove', function( event ) { 75 | if( level !== 1 ) { 76 | mouseX = event.clientX; 77 | mouseY = event.clientY; 78 | } 79 | } ); 80 | 81 | /** 82 | * Applies the CSS required to zoom in, prefers the use of CSS3 83 | * transforms but falls back on zoom for IE. 84 | * 85 | * @param {Object} rect 86 | * @param {Number} scale 87 | */ 88 | function magnify( rect, scale ) { 89 | 90 | var scrollOffset = getScrollOffset(); 91 | 92 | // Ensure a width/height is set 93 | rect.width = rect.width || 1; 94 | rect.height = rect.height || 1; 95 | 96 | // Center the rect within the zoomed viewport 97 | rect.x -= ( window.innerWidth - ( rect.width * scale ) ) / 2; 98 | rect.y -= ( window.innerHeight - ( rect.height * scale ) ) / 2; 99 | 100 | if( supportsTransforms ) { 101 | // Reset 102 | if( scale === 1 ) { 103 | document.body.style.transform = ''; 104 | document.body.style.OTransform = ''; 105 | document.body.style.msTransform = ''; 106 | document.body.style.MozTransform = ''; 107 | document.body.style.WebkitTransform = ''; 108 | } 109 | // Scale 110 | else { 111 | var origin = scrollOffset.x +'px '+ scrollOffset.y +'px', 112 | transform = 'translate('+ -rect.x +'px,'+ -rect.y +'px) scale('+ scale +')'; 113 | 114 | document.body.style.transformOrigin = origin; 115 | document.body.style.OTransformOrigin = origin; 116 | document.body.style.msTransformOrigin = origin; 117 | document.body.style.MozTransformOrigin = origin; 118 | document.body.style.WebkitTransformOrigin = origin; 119 | 120 | document.body.style.transform = transform; 121 | document.body.style.OTransform = transform; 122 | document.body.style.msTransform = transform; 123 | document.body.style.MozTransform = transform; 124 | document.body.style.WebkitTransform = transform; 125 | } 126 | } 127 | else { 128 | // Reset 129 | if( scale === 1 ) { 130 | document.body.style.position = ''; 131 | document.body.style.left = ''; 132 | document.body.style.top = ''; 133 | document.body.style.width = ''; 134 | document.body.style.height = ''; 135 | document.body.style.zoom = ''; 136 | } 137 | // Scale 138 | else { 139 | document.body.style.position = 'relative'; 140 | document.body.style.left = ( - ( scrollOffset.x + rect.x ) / scale ) + 'px'; 141 | document.body.style.top = ( - ( scrollOffset.y + rect.y ) / scale ) + 'px'; 142 | document.body.style.width = ( scale * 100 ) + '%'; 143 | document.body.style.height = ( scale * 100 ) + '%'; 144 | document.body.style.zoom = scale; 145 | } 146 | } 147 | 148 | level = scale; 149 | 150 | if( document.documentElement.classList ) { 151 | if( level !== 1 ) { 152 | document.documentElement.classList.add( 'zoomed' ); 153 | } 154 | else { 155 | document.documentElement.classList.remove( 'zoomed' ); 156 | } 157 | } 158 | } 159 | 160 | /** 161 | * Pan the document when the mosue cursor approaches the edges 162 | * of the window. 163 | */ 164 | function pan() { 165 | var range = 0.12, 166 | rangeX = window.innerWidth * range, 167 | rangeY = window.innerHeight * range, 168 | scrollOffset = getScrollOffset(); 169 | 170 | // Up 171 | if( mouseY < rangeY ) { 172 | window.scroll( scrollOffset.x, scrollOffset.y - ( 1 - ( mouseY / rangeY ) ) * ( 14 / level ) ); 173 | } 174 | // Down 175 | else if( mouseY > window.innerHeight - rangeY ) { 176 | window.scroll( scrollOffset.x, scrollOffset.y + ( 1 - ( window.innerHeight - mouseY ) / rangeY ) * ( 14 / level ) ); 177 | } 178 | 179 | // Left 180 | if( mouseX < rangeX ) { 181 | window.scroll( scrollOffset.x - ( 1 - ( mouseX / rangeX ) ) * ( 14 / level ), scrollOffset.y ); 182 | } 183 | // Right 184 | else if( mouseX > window.innerWidth - rangeX ) { 185 | window.scroll( scrollOffset.x + ( 1 - ( window.innerWidth - mouseX ) / rangeX ) * ( 14 / level ), scrollOffset.y ); 186 | } 187 | } 188 | 189 | function getScrollOffset() { 190 | return { 191 | x: window.scrollX !== undefined ? window.scrollX : window.pageXOffset, 192 | y: window.scrollY !== undefined ? window.scrollY : window.pageYOffset 193 | } 194 | } 195 | 196 | return { 197 | /** 198 | * Zooms in on either a rectangle or HTML element. 199 | * 200 | * @param {Object} options 201 | * - element: HTML element to zoom in on 202 | * OR 203 | * - x/y: coordinates in non-transformed space to zoom in on 204 | * - width/height: the portion of the screen to zoom in on 205 | * - scale: can be used instead of width/height to explicitly set scale 206 | */ 207 | to: function( options ) { 208 | 209 | // Due to an implementation limitation we can't zoom in 210 | // to another element without zooming out first 211 | if( level !== 1 ) { 212 | zoom.out(); 213 | } 214 | else { 215 | options.x = options.x || 0; 216 | options.y = options.y || 0; 217 | 218 | // If an element is set, that takes precedence 219 | if( !!options.element ) { 220 | // Space around the zoomed in element to leave on screen 221 | var padding = 20; 222 | var bounds = options.element.getBoundingClientRect(); 223 | 224 | options.x = bounds.left - padding; 225 | options.y = bounds.top - padding; 226 | options.width = bounds.width + ( padding * 2 ); 227 | options.height = bounds.height + ( padding * 2 ); 228 | } 229 | 230 | // If width/height values are set, calculate scale from those values 231 | if( options.width !== undefined && options.height !== undefined ) { 232 | options.scale = Math.max( Math.min( window.innerWidth / options.width, window.innerHeight / options.height ), 1 ); 233 | } 234 | 235 | if( options.scale > 1 ) { 236 | options.x *= options.scale; 237 | options.y *= options.scale; 238 | 239 | magnify( options, options.scale ); 240 | 241 | if( options.pan !== false ) { 242 | 243 | // Wait with engaging panning as it may conflict with the 244 | // zoom transition 245 | panEngageTimeout = setTimeout( function() { 246 | panUpdateInterval = setInterval( pan, 1000 / 60 ); 247 | }, 800 ); 248 | 249 | } 250 | } 251 | } 252 | }, 253 | 254 | /** 255 | * Resets the document zoom state to its default. 256 | */ 257 | out: function() { 258 | clearTimeout( panEngageTimeout ); 259 | clearInterval( panUpdateInterval ); 260 | 261 | magnify( { x: 0, y: 0 }, 1 ); 262 | 263 | level = 1; 264 | }, 265 | 266 | // Alias 267 | magnify: function( options ) { this.to( options ) }, 268 | reset: function() { this.out() }, 269 | 270 | zoomLevel: function() { 271 | return level; 272 | } 273 | } 274 | 275 | })(); 276 | 277 | 278 | 279 | -------------------------------------------------------------------------------- /student-handout/static/slides.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | reveal.js - The HTML Presentation Framework 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 31 | 32 | 35 | 36 | 37 | 38 | 39 |
    40 |
    41 |
    42 | 43 | 44 | 45 | 46 | 47 | 108 | 109 | 110 | 111 | --------------------------------------------------------------------------------