├── .gitignore ├── slides ├── 43_gui │ ├── gui.sass │ ├── prepros.jpg │ └── gui.slim ├── 17_badpre │ ├── badpre.sass │ └── badpre.slim ├── 18_sass │ ├── sass.slim │ ├── bad.jpg │ └── sass.sass ├── 19_rework │ ├── rework.slim │ └── rework.jpg ├── 36_flexstrong │ ├── flexstrong.sass │ └── flexstrong.slim ├── 02_chapter1 │ ├── pain.jpg │ ├── chapter1.sass │ └── chapter1.slim ├── 06_robots │ ├── robots.jpg │ └── robots.slim ├── 30_values │ ├── values.sass │ └── values.slim ├── 35_flexbox │ ├── flexbox.sass │ └── flexbox.slim ├── 11_chapter2 │ ├── cover.jpg │ └── chapter2.slim ├── 14_feature3 │ ├── caniuse.png │ └── feature3.slim ├── 15_feature4 │ ├── compass.jpg │ └── feature4.slim ├── 25_chapter3 │ ├── chapter3.sass │ ├── inside.jpg │ └── chapter3.slim ├── 40_chapter4 │ ├── chapter4.sass │ ├── cover.jpg │ └── chapter4.slim ├── 32_keyframes │ ├── keyframes.sass │ └── keyframes.slim ├── 33_selectors │ ├── selectors.sass │ └── selectors.slim ├── 41_auto │ └── auto.slim ├── 04_border-radius │ ├── github.png │ └── border-radius.slim ├── 45_forget │ └── forget.slim ├── 44_enable │ └── enable.slim ├── 39_nothacks │ └── nothacks.slim ├── 37_hacks │ ├── hacks.sass │ └── hacks.slim ├── 47_end │ ├── end.sass │ └── end.slim ├── 01_title │ ├── title.slim │ ├── title.sass │ └── logo.svg ├── 09_implicit │ └── implicit.slim ├── 08_stylus │ └── stylus.slim ├── 46_clean │ └── clean.slim ├── 05_questions │ └── questions.slim ├── 07_releases │ └── releases.slim ├── 12_feature1 │ └── feature1.slim ├── 10_prefixfree │ └── prefixfree.slim ├── 31_func │ └── func.slim ├── 16_goodpre │ └── goodpre.slim ├── 13_feature2 │ └── feature2.slim ├── 03_mixins │ └── mixins.slim ├── 28_browsers │ └── browsers.slim ├── 29_props │ └── props.slim ├── 38_cleaning │ └── cleaning.slim ├── 23_prepost │ ├── prepost.sass │ └── prepost.slim ├── 26_inside │ ├── inside.slim │ └── inside.sass ├── 27_autoupdate │ └── autoupdate.slim ├── 24_posts │ └── posts.slim ├── 20_postprocess │ ├── postprocess.slim │ └── postprocess.sass ├── 42_grunt │ └── grunt.slim ├── 21_post1 │ └── post1.slim ├── 34_gradients │ └── gradients.slim └── 22_post2 │ └── post2.slim ├── vendor ├── OpenSans.woff ├── Anka.Coder.woff ├── bright │ ├── mesh.png │ ├── defaults.scss │ ├── reset.scss │ └── screen.scss ├── OpenSans.Bold.woff ├── OpenSans.Light.woff └── shower.js ├── Gemfile ├── README.md ├── common ├── fonts.sass ├── _statistics.html ├── style.sass └── layout.slim ├── Gemfile.lock ├── Rakefile └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle/ 2 | public/ 3 | -------------------------------------------------------------------------------- /slides/43_gui/gui.sass: -------------------------------------------------------------------------------- 1 | .gui-slide 2 | img 3 | width: 540px 4 | -------------------------------------------------------------------------------- /slides/17_badpre/badpre.sass: -------------------------------------------------------------------------------- 1 | .badpre-slide 2 | pre 3 | font-size: 5px 4 | -------------------------------------------------------------------------------- /slides/18_sass/sass.slim: -------------------------------------------------------------------------------- 1 | - title 'Программируем на Сасс' 2 | - cover 'bad.jpg' 3 | -------------------------------------------------------------------------------- /slides/19_rework/rework.slim: -------------------------------------------------------------------------------- 1 | - title 'Постпроцессоры' 2 | - cover 'rework.jpg' 3 | -------------------------------------------------------------------------------- /vendor/OpenSans.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ai/wsd2013/master/vendor/OpenSans.woff -------------------------------------------------------------------------------- /slides/18_sass/bad.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ai/wsd2013/master/slides/18_sass/bad.jpg -------------------------------------------------------------------------------- /vendor/Anka.Coder.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ai/wsd2013/master/vendor/Anka.Coder.woff -------------------------------------------------------------------------------- /vendor/bright/mesh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ai/wsd2013/master/vendor/bright/mesh.png -------------------------------------------------------------------------------- /slides/18_sass/sass.sass: -------------------------------------------------------------------------------- 1 | .sass-slide 2 | h2 3 | position: relative 4 | top: 250px 5 | -------------------------------------------------------------------------------- /slides/36_flexstrong/flexstrong.sass: -------------------------------------------------------------------------------- 1 | .flexstrong-slide 2 | .split 3 | padding-top: 20px 4 | -------------------------------------------------------------------------------- /slides/43_gui/prepros.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ai/wsd2013/master/slides/43_gui/prepros.jpg -------------------------------------------------------------------------------- /vendor/OpenSans.Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ai/wsd2013/master/vendor/OpenSans.Bold.woff -------------------------------------------------------------------------------- /slides/02_chapter1/pain.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ai/wsd2013/master/slides/02_chapter1/pain.jpg -------------------------------------------------------------------------------- /slides/06_robots/robots.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ai/wsd2013/master/slides/06_robots/robots.jpg -------------------------------------------------------------------------------- /slides/19_rework/rework.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ai/wsd2013/master/slides/19_rework/rework.jpg -------------------------------------------------------------------------------- /slides/30_values/values.sass: -------------------------------------------------------------------------------- 1 | .values-slide 2 | .compile-from, .compile-to 3 | font-size: 85% 4 | -------------------------------------------------------------------------------- /slides/35_flexbox/flexbox.sass: -------------------------------------------------------------------------------- 1 | .flexbox-slide 2 | .compile-to, .compile-from 3 | margin: 0 4 | -------------------------------------------------------------------------------- /vendor/OpenSans.Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ai/wsd2013/master/vendor/OpenSans.Light.woff -------------------------------------------------------------------------------- /slides/02_chapter1/chapter1.sass: -------------------------------------------------------------------------------- 1 | .chapter1-slide 2 | h2 3 | position: relative 4 | top: 14px 5 | -------------------------------------------------------------------------------- /slides/11_chapter2/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ai/wsd2013/master/slides/11_chapter2/cover.jpg -------------------------------------------------------------------------------- /slides/14_feature3/caniuse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ai/wsd2013/master/slides/14_feature3/caniuse.png -------------------------------------------------------------------------------- /slides/15_feature4/compass.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ai/wsd2013/master/slides/15_feature4/compass.jpg -------------------------------------------------------------------------------- /slides/25_chapter3/chapter3.sass: -------------------------------------------------------------------------------- 1 | .chapter3-slide 2 | h2 3 | position: relative 4 | top: 300px 5 | -------------------------------------------------------------------------------- /slides/25_chapter3/inside.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ai/wsd2013/master/slides/25_chapter3/inside.jpg -------------------------------------------------------------------------------- /slides/40_chapter4/chapter4.sass: -------------------------------------------------------------------------------- 1 | .chapter4-slide 2 | h2 3 | position: relative 4 | top: 260px 5 | -------------------------------------------------------------------------------- /slides/40_chapter4/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ai/wsd2013/master/slides/40_chapter4/cover.jpg -------------------------------------------------------------------------------- /slides/06_robots/robots.slim: -------------------------------------------------------------------------------- 1 | - title 'Машины должны страдать' 2 | - cover 'robots.jpg' 3 | - type 'shout' 4 | -------------------------------------------------------------------------------- /slides/32_keyframes/keyframes.sass: -------------------------------------------------------------------------------- 1 | .keyframes-slide 2 | .compile-from, .compile-to 3 | font-size: 80% 4 | -------------------------------------------------------------------------------- /slides/33_selectors/selectors.sass: -------------------------------------------------------------------------------- 1 | .selectors-slide 2 | .compile-from, .compile-to 3 | font-size: 80% 4 | -------------------------------------------------------------------------------- /slides/41_auto/auto.slim: -------------------------------------------------------------------------------- 1 | - title 'Шаг 1Автоматизуйте фронтенд' 2 | - type 'shout important' 3 | -------------------------------------------------------------------------------- /slides/04_border-radius/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ai/wsd2013/master/slides/04_border-radius/github.png -------------------------------------------------------------------------------- /slides/45_forget/forget.slim: -------------------------------------------------------------------------------- 1 | - title 'Шаг 3. Забудьте о префиксах' 2 | - type 'shout important' 3 | -------------------------------------------------------------------------------- /slides/44_enable/enable.slim: -------------------------------------------------------------------------------- 1 | - title 'Шаг 2. Включите Автопрефиксер' 2 | - type 'shout important' 3 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rake' 4 | gem 'sinatra' 5 | gem 'therubyracer' 6 | gem 'evil-front-all' 7 | -------------------------------------------------------------------------------- /slides/02_chapter1/chapter1.slim: -------------------------------------------------------------------------------- 1 | - title 'Глава 1 Боль' 2 | - cover 'pain.jpg' 3 | - type 'chapter-slide' 4 | -------------------------------------------------------------------------------- /slides/11_chapter2/chapter2.slim: -------------------------------------------------------------------------------- 1 | - title 'Глава 2 Анализ' 2 | - cover 'cover.jpg' 3 | - type 'chapter-slide' 4 | -------------------------------------------------------------------------------- /slides/39_nothacks/nothacks.slim: -------------------------------------------------------------------------------- 1 | - title 'Но не чистит хаки' 2 | 3 | pre 4 | code -moz-transform: translateZ(0) 5 | -------------------------------------------------------------------------------- /slides/37_hacks/hacks.sass: -------------------------------------------------------------------------------- 1 | .hacks-slide 2 | ul 3 | width: 33% 4 | float: left 5 | & > li:before 6 | display: none 7 | -------------------------------------------------------------------------------- /slides/40_chapter4/chapter4.slim: -------------------------------------------------------------------------------- 1 | - title 'Глава 4 Самые важные слова' 2 | - cover 'cover.jpg' 3 | - type 'chapter-slide' 4 | -------------------------------------------------------------------------------- /slides/47_end/end.sass: -------------------------------------------------------------------------------- 1 | .end-slide 2 | .link 3 | font-size: 120% 4 | padding-top: 10px 5 | .first 6 | padding-top: 200px 7 | -------------------------------------------------------------------------------- /slides/25_chapter3/chapter3.slim: -------------------------------------------------------------------------------- 1 | - title 'Глава 3 Внутри Автопрефиксера' 2 | - cover 'inside.jpg' 3 | - type 'chapter-slide' 4 | -------------------------------------------------------------------------------- /slides/01_title/title.slim: -------------------------------------------------------------------------------- 1 | - title 'Автопрефиксер мир без CSS-префиксов' 2 | 3 | = image_tag 'logo.svg' 4 | .author Андрей Ситник, Злые марсиане 5 | -------------------------------------------------------------------------------- /slides/09_implicit/implicit.slim: -------------------------------------------------------------------------------- 1 | - title 'Стайлус и nib' 2 | 3 | ul 4 | li Плюс: Неявные примеси 5 | li Минус: Много ненужных префиксов 6 | -------------------------------------------------------------------------------- /slides/08_stylus/stylus.slim: -------------------------------------------------------------------------------- 1 | - title 'Стайлус и nib' 2 | 3 | pre 4 | code border-radius 3px 5 | 6 | pre 7 | code -webkit-border-radius: 3px 8 | code border-radius: 3px 9 | -------------------------------------------------------------------------------- /slides/46_clean/clean.slim: -------------------------------------------------------------------------------- 1 | - title 'Чистый CSS' 2 | 3 | pre 4 | code :fullscreen body { 5 | code transition: transform 1s; 6 | code transform: rotate(90deg) 7 | code } 8 | -------------------------------------------------------------------------------- /slides/05_questions/questions.slim: -------------------------------------------------------------------------------- 1 | - title 'Компас не прячет от нас префиксы' 2 | 3 | ol 4 | li Это свойство из CSS 3? 5 | li Это свойство ещё требует префиксов? 6 | li Пишем примесь или обычное свойство. 7 | -------------------------------------------------------------------------------- /slides/07_releases/releases.slim: -------------------------------------------------------------------------------- 1 | - title 'Релизы Компаса' 2 | 3 | p С последнего стабильного релиза (0.12) прошло: 4 | ul 5 | li 21 месяц назад 6 | li 15 версий Хрома и Файрфокса 7 | li 2 релиза Эксплорера 8 | -------------------------------------------------------------------------------- /slides/43_gui/gui.slim: -------------------------------------------------------------------------------- 1 | - title 'Самый простой вариант' 2 | 3 | p 4 | strong Prepros 5 | = ' ' 6 | a href="http://alphapixels.com/prepros/" target="_blank" alphapixels.com/prepros 7 | 8 | = image_tag('prepros.jpg') 9 | -------------------------------------------------------------------------------- /slides/14_feature3/feature3.slim: -------------------------------------------------------------------------------- 1 | - title 'Принципы Автопрефиксера' 2 | 3 | ol 4 | li Без интерфейса 5 | li Работа с чистым CSS 6 | li 7 | strong Самые актуальные префиксы 8 | 9 | = image_tag('caniuse.png') 10 | -------------------------------------------------------------------------------- /slides/12_feature1/feature1.slim: -------------------------------------------------------------------------------- 1 | - title 'Принципы Автопрефиксера' 2 | 3 | ol 4 | li 5 | strong Без интерфейса 6 | 7 | pre 8 | code :fullscreen a { 9 | code transition: transform 1s 10 | code } 11 | -------------------------------------------------------------------------------- /slides/10_prefixfree/prefixfree.slim: -------------------------------------------------------------------------------- 1 | - title '-prefix-free' 2 | 3 | ul 4 | li Вы пишите обычный CSS 5 | li JS-скрипт вставляет только нужные префиксы уже в браузере 6 | 7 | p Идеальный интерфейс, но проблемы с производительностью 8 | -------------------------------------------------------------------------------- /slides/04_border-radius/border-radius.slim: -------------------------------------------------------------------------------- 1 | - title 'border-radius' 2 | 3 | ul 4 | li Не нужен уже больше четырех лет 5 | li На ГитХабе 218 000 файлов с ненужной примесью 6 | 7 | = image_tag('github.png') 8 | -------------------------------------------------------------------------------- /slides/31_func/func.slim: -------------------------------------------------------------------------------- 1 | - title 'Функции' 2 | 3 | pre.compile-from 4 | code width: calc(10% + 10em) 5 | 6 | pre.compile-to 7 | code width: -webkit-calc(10% + 10em) 8 | code width: calc(10% + 10em) 9 | -------------------------------------------------------------------------------- /slides/15_feature4/feature4.slim: -------------------------------------------------------------------------------- 1 | - title 'Принципы Автопрефиксера' 2 | 3 | ol 4 | li Без интерфейса 5 | li Работа с чистым CSS 6 | li Самые актуальные префиксы 7 | li 8 | strong Автообновление 9 | 10 | = image_tag('compass.jpg') 11 | -------------------------------------------------------------------------------- /slides/16_goodpre/goodpre.slim: -------------------------------------------------------------------------------- 1 | - title 'Хорошие препроцессоры' 2 | 3 | pre 4 | code .quote 5 | code position: relative 6 | code top: 100px 7 | code +size(100px, 50px) 8 | code .arrow 9 | code +triangle 10 | -------------------------------------------------------------------------------- /slides/30_values/values.slim: -------------------------------------------------------------------------------- 1 | - title 'Значения' 2 | 3 | pre.compile-from 4 | code transition: transform 1s 5 | 6 | pre.compile-to 7 | code -webkit-transition: -webkit-transform 1s 8 | code transition: transform 1s 9 | -------------------------------------------------------------------------------- /slides/47_end/end.slim: -------------------------------------------------------------------------------- 1 | - title 'Вопросы' 2 | 3 | .link.first 4 | a href="https://github.com/ai/autoprefixer" target="_blank" 5 | | github.com/ai/autoprefixer 6 | 7 | .link 8 | a href="https://twitter.com/autoprefixer" target="_blank" 9 | | @autoprefixer 10 | -------------------------------------------------------------------------------- /slides/13_feature2/feature2.slim: -------------------------------------------------------------------------------- 1 | - title 'Принципы Автопрефиксера' 2 | 3 | ol 4 | li Без интерфейса 5 | li 6 | strong Универсальность 7 | ul 8 | li Сасс 9 | li Стайлус 10 | li Новые препроцессоры 11 | li Чистый CSS в старом коде или библиотеках 12 | -------------------------------------------------------------------------------- /slides/03_mixins/mixins.slim: -------------------------------------------------------------------------------- 1 | - title 'Привет из прошлого' 2 | 3 | pre 4 | code @include border-radius(5px) 5 | 6 | pre 7 | code -webkit-border-radius: 5px 8 | code -moz-border-radius: 5px 9 | code -khtml-border-radius: 5px 10 | code border-radius: 5px 11 | -------------------------------------------------------------------------------- /slides/28_browsers/browsers.slim: -------------------------------------------------------------------------------- 1 | - title 'Браузеры по умолчанию' 2 | 3 | ul 4 | li Больше 1 % в глобальной статистике 5 | li Последние 2 версии 6 | li Файрфокс 24 — ESR-релиз 7 | li Опера 12.1 — пока ветка 12 поддерживается 8 | -------------------------------------------------------------------------------- /slides/29_props/props.slim: -------------------------------------------------------------------------------- 1 | - title 'Свойства' 2 | 3 | pre.compile-from 4 | code box-sizing: border-box 5 | 6 | pre.compile-to 7 | code -webkit-box-sizing: border-box 8 | code -moz-box-sizing: border-box 9 | code box-sizing: border-box 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Презентация «Автопрефиксер: мир без CSS-префиксов». 2 | 3 | Для выступления на [Web Standards Days](http://webstandardsdays.ru/) в Минске и 4 | Киеве, [DUMP](http://dump-it.ru/) в Екатеринбурге 5 | и [РИТ 2014](http://ritconf.ru/) в Москве. 6 | 7 | Посмотреть: [ai.github.io/wsd2013](http://ai.github.io/wsd2013/). 8 | -------------------------------------------------------------------------------- /slides/38_cleaning/cleaning.slim: -------------------------------------------------------------------------------- 1 | - title 'Чистка' 2 | 3 | pre.compile-from 4 | code -webkit-border-radius: 10px 5 | code -moz-border-radius: 10px 6 | code border-radius: 10px 7 | 8 | pre.compile-to 9 | code 10 | | border-radius: 10px 11 | = '       ' 12 | -------------------------------------------------------------------------------- /slides/23_prepost/prepost.sass: -------------------------------------------------------------------------------- 1 | @import "evil-front" 2 | 3 | .prepost-slide 4 | .graph 5 | left: 40px 6 | .preprocessor 7 | position: absolute 8 | top: 0.95em 9 | left: -5em 10 | +clearfix 11 | color: #52a2df 12 | .arrow 13 | top: -0.55em 14 | .sass 15 | float: left 16 | font-weight: bold 17 | -------------------------------------------------------------------------------- /slides/26_inside/inside.slim: -------------------------------------------------------------------------------- 1 | - title '' 2 | 3 | .graph 4 | .browsers Поддерживаемые
браузеры 5 | .bc-arrow ↓ 6 | .caniuse Данные с Can I Use 7 | 8 | .add нужные префиксы → 9 | .remove ненужные префиксы → 10 | 11 | .css CSS 12 | .ca-arrow ↓ 13 | .autoprefixer Автопрефиксер 14 | .ac-arrow ↓ 15 | .prefixed CSS с префиксами 16 | -------------------------------------------------------------------------------- /slides/35_flexbox/flexbox.slim: -------------------------------------------------------------------------------- 1 | - title 'Флексбокс' 2 | 3 | pre.compile-from 4 | code display: flex 5 | 6 | pre.compile-to 7 | code display: -webkit-box; 8 | code display: -webkit-flex; 9 | code display: -moz-box; 10 | code display: -ms-flexbox; 11 | code display: flex 12 | -------------------------------------------------------------------------------- /slides/01_title/title.sass: -------------------------------------------------------------------------------- 1 | .title-slide 2 | h2 3 | strong 4 | display: block 5 | font-weight: normal 6 | font-size: 154% 7 | line-height: 1.5 8 | svg 9 | position: absolute 10 | top: 12px 11 | right: 120px 12 | width: 170px 13 | .author 14 | font-family: "Open Sans Light" 15 | position: relative 16 | top: 180px 17 | -------------------------------------------------------------------------------- /slides/27_autoupdate/autoupdate.slim: -------------------------------------------------------------------------------- 1 | - title 'Быстрое обновление' 2 | 3 | p Скрипты проверки обновления Can I Use: 4 | 5 | pre 6 | code @feature 'css3-boxsizing', (browsers) => 7 | code prefix 'box-sizing', browsers: browsers 8 | 9 | ol 10 | li Запускаю скрипт ./bin/autoprefixer --update 11 | li Если есть обновления — n cake publish 12 | -------------------------------------------------------------------------------- /slides/24_posts/posts.slim: -------------------------------------------------------------------------------- 1 | - title 'Примеры постпроцессоров' 2 | 3 | ul 4 | li Автопрефиксер 5 | li grunt-pixrem — полифил для rem-единиц 6 | li CSSWring — сжатие CSS с поддержкой source map 7 | li CSS MQPacker — объединяет общие CSS Media Queries 8 | li RTLCSS — зеркалит стили для язков справа-на-лево 9 | -------------------------------------------------------------------------------- /slides/20_postprocess/postprocess.slim: -------------------------------------------------------------------------------- 1 | - title 'Постпроцессоры' 2 | 3 | .graph 4 | .css CSS 5 | .arrow → 6 | .position 7 | .rework-title PostCSS 8 | .rework.parser Парсер 9 | .rework.stringifier Сохранение 10 | .down 11 | | ↓ 12 | .arrow-text JS-дерево 13 | .up 14 | | ↑ 15 | .arrow-text Новое JS-дерево 16 | .code Ваш JS-код обработки 17 | .arrow → 18 | .css Новый CSS 19 | -------------------------------------------------------------------------------- /slides/42_grunt/grunt.slim: -------------------------------------------------------------------------------- 1 | - title 'Мощные и гибкие' 2 | 3 | p 4 | strong Grunt 5 | br 6 | a href="http://gruntjs.com/" target="_blank" gruntjs.com 7 | 8 | p 9 | strong Broccoli 10 | br 11 | a href="https://github.com/joliss/broccoli" target="_blank" github.com/joliss/broccoli 12 | 13 | p 14 | strong Mincer 15 | br 16 | a href="https://github.com/nodeca/mincer" target="_blank" github.com/nodeca/mincer 17 | -------------------------------------------------------------------------------- /slides/21_post1/post1.slim: -------------------------------------------------------------------------------- 1 | - title 'Создаём постпроцессор' 2 | 3 | pre 4 | code 5 | | processor = postcss (css) -> 6 | code css.eachRule (rule) -> 7 | code if rule.selector.match(/::(before|after)/') 8 | code if rule.every (i) -> i.prop != 'content' 9 | code rule.prepend(prop: 'content'', value: '""') 10 | -------------------------------------------------------------------------------- /common/fonts.sass: -------------------------------------------------------------------------------- 1 | @font-face 2 | font-family: "Open Sans" 3 | src: inline("OpenSans.woff") format("woff") 4 | 5 | @font-face 6 | font-family: "Open Sans" 7 | font-weight: bold 8 | src: inline("OpenSans.Bold.woff") format("woff") 9 | 10 | @font-face 11 | font-family: "Open Sans Light" 12 | src: inline("OpenSans.Light.woff") format("woff") 13 | 14 | @font-face 15 | font-family: "Anka Coder" 16 | src: inline("Anka.Coder.woff") format("woff") 17 | -------------------------------------------------------------------------------- /slides/34_gradients/gradients.slim: -------------------------------------------------------------------------------- 1 | - title 'Градиенты' 2 | 3 | pre 4 | code background: linear-gradient( to left, white, black ); 5 | 6 | p= '           ↓' 7 | 8 | pre 9 | code background: -webkit-gradient( linear, top right, top left, 10 | code from(white), to(black)); 11 | code background: -webkit-linear-gradient( right, white, black ); 12 | code background: linear-gradient( to left, white, black ); 13 | -------------------------------------------------------------------------------- /common/_statistics.html: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /slides/01_title/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /slides/22_post2/post2.slim: -------------------------------------------------------------------------------- 1 | - title 'Применяем постпроцессор' 2 | 3 | pre 4 | code 5 | | output = processor.process(input).css 6 | 7 | pre.compile-from 8 | code 9 | mark a:before 10 | code width: 10px 11 | code height: 10px 12 | code background: blue 13 | 14 | pre.compile-to 15 | code 16 | mark a:before 17 | code content: "" 18 | code width: 10px 19 | code height: 10px 20 | code background: blue 21 | -------------------------------------------------------------------------------- /slides/36_flexstrong/flexstrong.slim: -------------------------------------------------------------------------------- 1 | - title 'Сложный флексбокс' 2 | 3 | pre.compile-from 4 | code flex-direction: row 5 | 6 | pre.compile-to 7 | code -webkit-box-orient: horizontal; 8 | code -webkit-box-direction: normal; 9 | code.split -webkit-flex-direction: row; 10 | code.split -moz-box-orient: horizontal; 11 | code -moz-box-direction: normal; 12 | code.split -ms-flex-direction: row; 13 | code.split flex-direction: row 14 | -------------------------------------------------------------------------------- /slides/23_prepost/prepost.slim: -------------------------------------------------------------------------------- 1 | - title 'Постпроцессоры ♥ Сасс и Стайлус' 2 | 3 | .graph 4 | .preprocessor 5 | .sass Сасс 6 | .arrow → 7 | .css.origin 8 | | CSS 9 | .map Карта кода 10 | .arrow → 11 | .position 12 | .rework-title PostCSS 13 | .rework.parser Парсер 14 | .rework.stringifier Сохранение 15 | .down 16 | | ↓ 17 | .arrow-text JS-дерево 18 | .up 19 | | ↑ 20 | .arrow-text Новое JS-дерево 21 | .code Ваш JS-код обработки 22 | .arrow → 23 | .css 24 | | Новый CSS 25 | .map Новая карта 26 | -------------------------------------------------------------------------------- /slides/33_selectors/selectors.slim: -------------------------------------------------------------------------------- 1 | - title 'Селекторы' 2 | 3 | pre.compile-from 4 | code :fullscreen a { 5 | code transition: transform 1s } 6 | 7 | pre.compile-to 8 | code :-webkit-full-screen a { 9 | code -webkit-transition: -webkit-transform 1s; 10 | code transition: transform 1s; } 11 | code= ' ' 12 | code :-moz-full-screen a { 13 | code transition: transform 1s; } 14 | code= ' ' 15 | code :fullscreen a { 16 | code -webkit-transition: -webkit-transform 1s; 17 | code transition: transform 1s; } 18 | -------------------------------------------------------------------------------- /slides/32_keyframes/keyframes.slim: -------------------------------------------------------------------------------- 1 | - title 'Кадры' 2 | 3 | pre.compile-from 4 | code @keyframes anim { 5 | code to { 6 | code transform: rotate(360deg); } } 7 | 8 | pre.compile-to 9 | code @-webkit-keyframes anim { 10 | code to { 11 | code -webkit-transform: rotate(360deg); 12 | code transform: rotate(360deg); } } 13 | code= ' ' 14 | code @keyframes anim { 15 | code to { 16 | code -webkit-transform: rotate(360deg); 17 | code -ms-transform: rotate(360deg); 18 | code transform: rotate(360deg); } } 19 | -------------------------------------------------------------------------------- /slides/37_hacks/hacks.slim: -------------------------------------------------------------------------------- 1 | - title 'Хаки' 2 | 3 | ul 4 | li 5 | code align-content 6 | li 7 | code align-items 8 | li 9 | code align-self 10 | li 11 | code border-image 12 | li 13 | code border-radius 14 | li 15 | code break-inside 16 | li 17 | code display-flex 18 | li 19 | code fill-available 20 | ul 21 | li 22 | code filter 23 | li 24 | code flex-basis 25 | li 26 | code flex 27 | li 28 | code flex-direction 29 | li 30 | code flex-flow 31 | li 32 | code flex-grow 33 | li 34 | code flex-shrink 35 | li 36 | code flex-spec 37 | ul 38 | li 39 | code flex-wrap 40 | li 41 | code fullscreen 42 | li 43 | code gradient 44 | li 45 | code justify-content 46 | li 47 | code order 48 | li 49 | code placeholder 50 | li 51 | code transform 52 | li 53 | code transition 54 | -------------------------------------------------------------------------------- /vendor/bright/defaults.scss: -------------------------------------------------------------------------------- 1 | // Bright theme for Shower HTML presentation engine: github.com/shower/shower 2 | // Copyright © 2010–2013 Vadim Makeev, pepelsbey.net 3 | // Licensed under MIT license: github.com/shower/shower/wiki/MIT-License 4 | 5 | // Layout 6 | $width:1024px; // Slide width, permanent in most cases 7 | $height:640px; // Slide height, 640px for 16:10, 768px for 4:3 8 | $top:100px; // Top padding above slide content 9 | $left:128px; // Left slide content padding 10 | $right:96px; // Right slide content padding 11 | $break:1180px; // Window width for small thumbnails to appear 12 | $ratio:'16x10'; // Available options: '16x10' or '4x3' 13 | 14 | // Colors 15 | $color:#52A2DF; 16 | 17 | // #52A2DF 1px 18 | $dot:'data:image/gif;base64,R0lGODdhAQABAPAAAFKi3wAAACH/C1hNUCBEYXRhWE1QAz94cAAsAAAAAAEAAQBAAgJEAQA7'; 19 | 20 | // Mixins 21 | @mixin retina { 22 | @media (-webkit-min-device-pixel-ratio:2), (min-resolution:192dpi) { 23 | @content; 24 | } 25 | } -------------------------------------------------------------------------------- /slides/26_inside/inside.sass: -------------------------------------------------------------------------------- 1 | .inside-slide 2 | .graph 3 | position: relative 4 | font-size: 116% 5 | left: -40px 6 | .browsers, .caniuse, .css, .autoprefixer, .prefixed 7 | position: absolute 8 | line-height: 1.4 9 | .browsers 10 | top: -0.6em 11 | left: 1.5em 12 | font-size: 80% 13 | text-align: center 14 | .caniuse, .autoprefixer 15 | padding: 0.6em 0.8em 16 | border: 4px solid 17 | color: #52a2df 18 | font-weight: bold 19 | .caniuse 20 | top: 5em 21 | left: -1.5em 22 | .css 23 | top: 0 24 | left: 25.7em 25 | .autoprefixer 26 | top: 5em 27 | left: 21.5em 28 | .prefixed 29 | top: 12em 30 | left: 22.4em 31 | 32 | .bc-arrow, .ca-arrow, .ac-arrow 33 | font-size: 160% 34 | position: absolute 35 | .bc-arrow 36 | top: 0.8em 37 | left: 2.6em 38 | .ca-arrow 39 | top: 0.8em 40 | left: 16.4em 41 | .ac-arrow 42 | top: 5.2em 43 | left: 16.4em 44 | 45 | .add, .remove 46 | position: absolute 47 | font-size: 80% 48 | .add 49 | top: 6.1em 50 | left: 14.6em 51 | .remove 52 | top: 7.6em 53 | left: 14.1em 54 | -------------------------------------------------------------------------------- /common/style.sass: -------------------------------------------------------------------------------- 1 | @import "bright/screen" 2 | @import "evil-front" 3 | 4 | .caption 5 | color: black 6 | 7 | .caption a, .slide a 8 | display: inline-block 9 | line-height: 1.2 10 | border-bottom: 0.05em solid rgba(#52a2df, 0.4) 11 | &:hover 12 | border-bottom: 0.05em solid #52a2df 13 | 14 | .slide::after 15 | display: none 16 | 17 | .slide > div 18 | padding-top: 80px 19 | height: 560px 20 | 21 | .cover h2 22 | font-family: "Open Sans" 23 | color: white 24 | +stroke-text(black) 25 | 26 | .chapter-slide 27 | h2 28 | position: relative 29 | font-size: 40px 30 | strong 31 | display: block 32 | font-weight: normal 33 | font-size: 80px 34 | line-height: 1 35 | position: relative 36 | top: 10px 37 | left: -4px 38 | 39 | .slide.important 40 | h2 41 | font-size: 60px 42 | strong 43 | display: block 44 | font-size: 100px 45 | padding-top: 20px 46 | line-height: 1.1 47 | 48 | .slide 49 | .compile-from, .compile-to 50 | font-size: 100% 51 | .compile-from 52 | float: left 53 | margin-left: -40px 54 | .compile-to 55 | float: right 56 | margin-right: -40px 57 | -------------------------------------------------------------------------------- /vendor/bright/reset.scss: -------------------------------------------------------------------------------- 1 | // http://meyerweb.com/eric/tools/css/reset/ 2 | // v2.0 | 20110126 3 | // License: none (public domain) 4 | 5 | html, body, div, span, applet, object, iframe, 6 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 7 | a, abbr, acronym, address, big, cite, code, 8 | del, dfn, em, img, ins, kbd, q, s, samp, 9 | small, strike, strong, sub, sup, tt, var, 10 | b, u, i, center, 11 | dl, dt, dd, ol, ul, li, 12 | fieldset, form, label, legend, 13 | table, caption, tbody, tfoot, thead, tr, th, td, 14 | article, aside, canvas, details, embed, 15 | figure, figcaption, footer, header, hgroup, 16 | menu, nav, output, ruby, section, summary, 17 | time, mark, audio, video { 18 | margin:0; 19 | padding:0; 20 | border:0; 21 | font-size:100%; 22 | font:inherit; 23 | vertical-align:baseline; 24 | } 25 | article, aside, details, figcaption, figure, 26 | footer, header, hgroup, menu, nav, section { 27 | display:block; 28 | } 29 | body { 30 | line-height:1; 31 | } 32 | ol, ul { 33 | list-style:none; 34 | } 35 | blockquote, q { 36 | quotes:none; 37 | } 38 | blockquote:before, blockquote:after, 39 | q:before, q:after { 40 | content:''; 41 | content:none; 42 | } 43 | table { 44 | border-collapse:collapse; 45 | border-spacing:0; 46 | } 47 | -------------------------------------------------------------------------------- /common/layout.slim: -------------------------------------------------------------------------------- 1 | doctype 5 2 | html lang="ru" 3 | head 4 | meta charset="UTF-8" 5 | link rel="icon" href="http://sitnik.ru/favicon.ico" 6 | title Автопрефиксер: мир без CSS-префиксов 7 | meta name="viewport" content="width=1274, user-scalable=no" 8 | - if production? 9 | = include_jquery(env: :production) 10 | - if development? 11 | link rel="stylesheet" href="/style.css" 12 | - slides_styles do |file| 13 | link rel="stylesheet" href="/#{ file }" 14 | - else 15 | style 16 | = assets['style.css'] 17 | - slides_styles do |file| 18 | = assets[file] 19 | - unless development? 20 | = include_statistics 21 | body.list 22 | 23 | header.caption 24 | h1 Автопрефиксер: мир без CSS-префиксов 25 | p 26 | | Андрей Ситник, 27 | Злые марсиане 28 | 29 | - slides.each_with_index do |slide, i| 30 | section.slide id=(i + 1) class="#{slide.name}-slide#{slide.types}" 31 | div 32 | - if slide.title 33 | h2= slide.title 34 | = slide.html 35 | 36 | .progress 37 | div 38 | 39 | - if development? 40 | link rel="stylesheet" href="/fonts.css" 41 | - else 42 | style= assets['fonts.css'] 43 | 44 | - if development? 45 | script src="/jquery.js" 46 | script src="/shower.js" 47 | - else 48 | script 49 | - if standalone? 50 | = assets['jquery.js'] 51 | = assets['shower.js'] 52 | -------------------------------------------------------------------------------- /slides/20_postprocess/postprocess.sass: -------------------------------------------------------------------------------- 1 | .postprocess-slide, .prepost-slide 2 | .graph 3 | margin-top: 120px 4 | text-align: center 5 | font-size: 110% 6 | position: relative 7 | .position 8 | position: relative 9 | display: inline-block 10 | .css, .rework, .arrow 11 | display: inline-block 12 | .css 13 | padding: 9px 0 14 | position: relative 15 | .map 16 | position: absolute 17 | top: 100% 18 | left: 0 19 | font-size: 66% 20 | margin-top: -0.4em 21 | white-space: nowrap 22 | .arrow 23 | padding: 0 20px 24 | font-size: 165% 25 | position: relative 26 | .rework-title 27 | position: absolute 28 | bottom: 100% 29 | left: 0 30 | right: 0 31 | text-align: center 32 | color: #52a2df 33 | font-weight: bold 34 | .rework 35 | color: #52a2df 36 | border: 4px solid 37 | width: 7em 38 | text-align: center 39 | font-weight: bold 40 | padding: 0.1em 0 41 | .down, .up 42 | font-size: 165% 43 | position: absolute 44 | top: 100% 45 | width: (1em / 1.65) 46 | text-align: center 47 | .arrow-text 48 | position: absolute 49 | top: 38% 50 | font-size: 40% 51 | white-space: nowrap 52 | .down 53 | left: (3em / 1.65) 54 | .arrow-text 55 | right: 125% 56 | .up 57 | right: (3em / 1.65) 58 | .arrow-text 59 | left: 125% 60 | .code 61 | position: absolute 62 | top: 100% 63 | left: 0 64 | right: 0 65 | margin-top: 4em 66 | text-align: center 67 | border: 2px solid 68 | box-sizing: border-box 69 | .parser 70 | margin-right: 10px 71 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | activesupport (4.1.0) 5 | i18n (~> 0.6, >= 0.6.9) 6 | json (~> 1.7, >= 1.7.7) 7 | minitest (~> 5.1) 8 | thread_safe (~> 0.1) 9 | tzinfo (~> 1.1) 10 | autoprefixer-rails (1.1.20140410) 11 | execjs 12 | coffee-script (2.2.0) 13 | coffee-script-source 14 | execjs 15 | coffee-script-source (1.7.0) 16 | csso-rails (0.3.4) 17 | execjs (>= 1) 18 | dimensions (1.3.0) 19 | evil-blocks-rails (0.5.1) 20 | sprockets (>= 2) 21 | evil-front (0.3.4) 22 | i18n 23 | nokogiri (>= 1) 24 | rails-sass-images (>= 0.3) 25 | rubypants-unicode 26 | sass (>= 3.2.9) 27 | slim (>= 1.3.9) 28 | sprockets (>= 1) 29 | standalone_typograf (>= 3.0.1) 30 | unicode_utils (>= 1.4) 31 | evil-front-all (0.3.0) 32 | autoprefixer-rails (>= 0.5) 33 | coffee-script (>= 2.2.0) 34 | csso-rails (>= 0.3) 35 | evil-blocks-rails (>= 0.2) 36 | evil-front (~> 0.3.0) 37 | jquery-cdn (>= 1) 38 | sprockets (>= 1) 39 | uglifier (>= 2.1.1) 40 | execjs (2.0.2) 41 | hike (1.2.3) 42 | i18n (0.6.9) 43 | jquery-cdn (2.1.0) 44 | sprockets (>= 2) 45 | json (1.8.1) 46 | libv8 (3.16.14.3) 47 | mime-types (2.2) 48 | mini_portile (0.5.3) 49 | minitest (5.3.3) 50 | multi_json (1.9.2) 51 | nokogiri (1.6.1) 52 | mini_portile (~> 0.5.0) 53 | rack (1.5.2) 54 | rack-protection (1.5.3) 55 | rack 56 | rails-sass-images (0.5) 57 | dimensions (> 0) 58 | mime-types (> 0) 59 | sass (> 0) 60 | rake (10.3.1) 61 | ref (1.0.5) 62 | rubypants-unicode (0.2.3) 63 | sass (3.3.5) 64 | sinatra (1.4.5) 65 | rack (~> 1.4) 66 | rack-protection (~> 1.4) 67 | tilt (~> 1.3, >= 1.3.4) 68 | slim (2.0.2) 69 | temple (~> 0.6.6) 70 | tilt (>= 1.3.3, < 2.1) 71 | sprockets (2.12.1) 72 | hike (~> 1.2) 73 | multi_json (~> 1.0) 74 | rack (~> 1.0) 75 | tilt (~> 1.1, != 1.3.0) 76 | standalone_typograf (3.0.2) 77 | activesupport 78 | temple (0.6.7) 79 | therubyracer (0.12.1) 80 | libv8 (~> 3.16.14.0) 81 | ref 82 | thread_safe (0.3.3) 83 | tilt (1.4.1) 84 | tzinfo (1.1.0) 85 | thread_safe (~> 0.1) 86 | uglifier (2.5.0) 87 | execjs (>= 0.3.0) 88 | json (>= 1.8.0) 89 | unicode_utils (1.4.0) 90 | 91 | PLATFORMS 92 | ruby 93 | 94 | DEPENDENCIES 95 | evil-front-all 96 | rake 97 | sinatra 98 | therubyracer 99 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'pathname' 2 | require 'base64' 3 | 4 | ROOT = Pathname(__FILE__).dirname 5 | PUBLIC = ROOT.join('public') 6 | SLIDES = ROOT.join('slides') 7 | COMMON = ROOT.join('common') 8 | VENDOR = ROOT.join('vendor') 9 | 10 | require 'evil-front-all' 11 | JqueryCdn.local_url = proc { '/jquery.js' } 12 | 13 | class Pathname 14 | def glob(pattern, &block) 15 | Pathname.glob(self.join(pattern), &block) 16 | end 17 | 18 | def copy_to(to_dir, pattern = '**/*', &block) 19 | self.glob(pattern) do |from| 20 | next if from.directory? 21 | next if block_given? and yield 22 | to = to_dir.join(from.relative_path_from(self)) 23 | to.dirname.mkpath 24 | FileUtils.cp(from, to) 25 | end 26 | end 27 | end 28 | 29 | Slide = Struct.new(:name, :title, :types, :html, :file) do 30 | def style 31 | file.dirname.basename.join("#{name}.css") 32 | end 33 | 34 | def name 35 | file.basename.sub_ext('') 36 | end 37 | end 38 | 39 | class Builder 40 | include EvilFront::Helpers 41 | 42 | attr_accessor :slides 43 | 44 | def initialize(build_type = :development) 45 | @build_type = build_type 46 | end 47 | 48 | def name(value); @name = value; end 49 | def title(value); @title = value; end 50 | 51 | def type(*values) 52 | @types += ' ' + values.join(' ') 53 | end 54 | 55 | def render(file, &block) 56 | @current = file 57 | options = { format: :html5, disable_escape: true, pretty: false } 58 | Slim::Template.new(file.to_s, options).render(self, &block) 59 | end 60 | 61 | def assets 62 | @sprockets ||= begin 63 | Sprockets::Environment.new(ROOT) do |env| 64 | env.append_path(SLIDES) 65 | env.append_path(COMMON) 66 | env.append_path(VENDOR) 67 | 68 | EvilFront.install_all(env) 69 | 70 | unless development? 71 | env.js_compressor = Uglifier.new(copyright: false) 72 | env.css_compressor = :csso 73 | end 74 | end 75 | end 76 | end 77 | 78 | def slide(file) 79 | @name = @title = @cover = nil 80 | @types = '' 81 | html = render(file) 82 | html = image_tag(@cover, class: 'cover') + html if @cover 83 | @slides << Slide.new(@name, @title, @types, html, file) 84 | end 85 | 86 | def slides_styles(&block) 87 | slides.map(&:style).reject {|i| assets[i].nil? }.each do |style| 88 | yield style 89 | end 90 | end 91 | 92 | def image_tag(name, attrs = { }) 93 | attrs[:alt] ||= '' 94 | uri = @current.dirname.join(name) 95 | type = file_type(uri) 96 | if type == 'image/gif' 97 | attrs[:class] = (attrs[:class] ? attrs[:class] + ' ' : '') + 'gif' 98 | end 99 | 100 | return uri.read if name =~ /\.svg$/ 101 | 102 | if standalone? 103 | uri = encode_image(uri, type) 104 | else 105 | uri = uri.to_s.gsub(SLIDES.to_s, '') 106 | uri = './slides' + uri if production? 107 | end 108 | attrs = attrs.map { |k, v| "#{k}=\"#{v}\"" }.join(' ') 109 | "" 110 | end 111 | 112 | def encode_image(file, type) 113 | "data:#{type};base64," + Base64.encode64(file.open { |io| io.read }) 114 | end 115 | 116 | def file_type(file) 117 | `file -ib #{file}`.split(';').first 118 | end 119 | 120 | def cover(name) 121 | @types += ' cover h' 122 | @cover = name 123 | end 124 | 125 | def include_statistics 126 | COMMON.join('_statistics.html').read 127 | end 128 | 129 | def standalone? 130 | @build_type == :standalone 131 | end 132 | 133 | def production? 134 | @build_type == :production 135 | end 136 | 137 | def development? 138 | @build_type == :development 139 | end 140 | 141 | def result_file 142 | if standalone? 143 | 'wsd2013.html' 144 | else 145 | 'index.html' 146 | end 147 | end 148 | 149 | def layout_file 150 | COMMON.join('layout.slim') 151 | end 152 | 153 | def clean! 154 | PUBLIC.mkpath 155 | PUBLIC.glob('*') { |i| i.rmtree } 156 | self 157 | end 158 | 159 | def build! 160 | clean! 161 | 162 | @slides = [] 163 | SLIDES.glob('**/*.slim').sort.each { |i| slide(i) } 164 | 165 | PUBLIC.join(result_file).open('w') { |io| io << render(layout_file) } 166 | if production? 167 | ROOT.copy_to(PUBLIC, '**/*.{png,gif,jpg}') do |image| 168 | image.to_s.start_with? PUBLIC.to_s 169 | end 170 | end 171 | 172 | self 173 | end 174 | end 175 | 176 | desc 'Build site files' 177 | task :build do 178 | Builder.new(:production).build! 179 | end 180 | 181 | desc 'Build presentation all-in-one file' 182 | task :standalone do 183 | Builder.new(:standalone).build! 184 | end 185 | 186 | desc 'Run server for development' 187 | task :server do 188 | require 'sinatra/base' 189 | 190 | class WebSlides < Sinatra::Base 191 | set :lock, true 192 | 193 | get '/' do 194 | builder.build! 195 | send_file PUBLIC.join('index.html') 196 | end 197 | 198 | { 199 | css: 'text/css', js: 'text/javascript', 200 | png: 'image/png', jpg: 'image/jpeg' 201 | }.each_pair do |ext, mime| 202 | get "/*.#{ ext }" do |path| 203 | path = path + ".#{ ext }" 204 | content_type mime 205 | builder.assets[path].to_s 206 | end 207 | end 208 | 209 | def builder 210 | @builder ||= Builder.new 211 | end 212 | end 213 | 214 | WebSlides.run! 215 | end 216 | 217 | desc 'Prepare commit to GitHub Pages' 218 | task :deploy => :build do 219 | sh ['git checkout gh-pages', 220 | 'git rm index.html', 221 | 'git rm -r slides/', 222 | 'git rm -r vendor/', 223 | 'cp -r public/* ./', 224 | 'git add index.html', 225 | 'git add slides/', 226 | 'git add vendor/'].join(' && ') 227 | end 228 | 229 | desc 'Add new slide' 230 | task :add do 231 | print "Slide name: " 232 | name = STDIN.gets.strip 233 | 234 | last = SLIDES.children.length + 1 235 | print "Position [#{ last }]: " 236 | pos = STDIN.gets.strip.to_i 237 | pos = last if pos <= 0 or pos > last 238 | 239 | if pos < last 240 | SLIDES.children.sort[pos-1..-1].each do |from| 241 | num, code = from.basename.to_s.split('_', 2) 242 | num = (num.to_i + 1).to_s 243 | num = '0' + num if num.length == 1 244 | to = from.dirname.join("#{ num }_#{ code }") 245 | from.rename(to) 246 | end 247 | end 248 | 249 | num = pos.to_s 250 | num = '0' + num if num.length == 1 251 | slim = SLIDES.join("#{ num }_#{ name }/#{ name }.slim") 252 | 253 | slim.dirname.mkpath 254 | slim.open("w") { |io| io << "- title ''\n" } 255 | 256 | sh "xdg-open #{ slim }" 257 | end 258 | 259 | desc 'Delete slide' 260 | task :del do 261 | print "Slide position: " 262 | pos = STDIN.gets.strip.to_i 263 | 264 | dir = SLIDES.children.sort[pos - 1] 265 | dir.rmtree 266 | 267 | SLIDES.children.sort[pos-1..-1].each do |from| 268 | num, code = from.basename.to_s.split('_', 2) 269 | num = (num.to_i - 1).to_s 270 | num = '0' + num if num.length == 1 271 | to = from.dirname.join("#{ num }_#{ code }") 272 | from.rename(to) 273 | end 274 | end 275 | -------------------------------------------------------------------------------- /slides/17_badpre/badpre.slim: -------------------------------------------------------------------------------- 1 | - title 'Плохие препроцессоры' 2 | 3 | pre 4 | code @import "shared"; 5 | code $default-transition-property: all !default; 6 | code $default-transition-duration: 1s !default; 7 | code $default-transition-function: false !default; 8 | code $default-transition-delay: false !default; 9 | code $transitionable-prefixed-values: transform, transform-origin !default; 10 | code @mixin transition-property($property-1: $default-transition-property, $property-2 : false, $property-3 : false, $property-4 : false, $property-5 : false, $property-6 : false, $property-7 : false, $property-8 : false, $property-9 : false, $property-10: false 11 | code ) { 12 | code @if type-of($property-1) == string { $property-1: unquote($property-1); } 13 | code $properties: compact($property-1, $property-2, $property-3, $property-4, $property-5, $property-6, $property-7, $property-8, $property-9, $property-10); 14 | code @if $experimental-support-for-webkit { -webkit-transition-property : prefixed-for-transition(-webkit, $properties); } 15 | code @if $experimental-support-for-mozilla { -moz-transition-property : prefixed-for-transition(-moz, $properties); } 16 | code @if $experimental-support-for-opera { -o-transition-property : prefixed-for-transition(-o, $properties); } 17 | code transition-property : $properties; 18 | code } 19 | code @mixin transition-duration($duration-1: $default-transition-duration, $duration-2 : false, $duration-3 : false, $duration-4 : false, $duration-5 : false, $duration-6 : false, $duration-7 : false, $duration-8 : false, $duration-9 : false, $duration-10: false 20 | code ) { 21 | code @if type-of($duration-1) == string { $duration-1: unquote($duration-1); } 22 | code $durations: compact($duration-1, $duration-2, $duration-3, $duration-4, $duration-5, $duration-6, $duration-7, $duration-8, $duration-9, $duration-10); 23 | code @include experimental(transition-duration, $durations, 24 | code -moz, -webkit, -o, not -ms, not -khtml, official 25 | code ); 26 | code } 27 | code @mixin transition-timing-function($function-1: $default-transition-function, $function-2 : false, $function-3 : false, $function-4 : false, $function-5 : false, $function-6 : false, $function-7 : false, $function-8 : false, $function-9 : false, $function-10: false 28 | code ) { 29 | code $function-1: unquote($function-1); 30 | code $functions: compact($function-1, $function-2, $function-3, $function-4, $function-5, $function-6, $function-7, $function-8, $function-9, $function-10); 31 | code @include experimental(transition-timing-function, $functions, 32 | code -moz, -webkit, -o, not -ms, not -khtml, official 33 | code ); 34 | code } 35 | code @mixin transition-delay($delay-1: $default-transition-delay, $delay-2 : false, $delay-3 : false, $delay-4 : false, $delay-5 : false, $delay-6 : false, $delay-7 : false, $delay-8 : false, $delay-9 : false, $delay-10: false 36 | code ) { 37 | code @if type-of($delay-1) == string { $delay-1: unquote($delay-1); } 38 | code $delays: compact($delay-1, $delay-2, $delay-3, $delay-4, $delay-5, $delay-6, $delay-7, $delay-8, $delay-9, $delay-10); 39 | code @include experimental(transition-delay, $delays, 40 | code -moz, -webkit, -o, not -ms, not -khtml, official 41 | code ); 42 | code } 43 | code @mixin single-transition( 44 | code $property: $default-transition-property, 45 | code $duration: $default-transition-duration, 46 | code $function: $default-transition-function, 47 | code $delay: $default-transition-delay 48 | code ) { 49 | code @include transition(compact($property $duration $function $delay)); 50 | code } 51 | code @mixin transition( 52 | code $transition-1 : default, $transition-2 : false, $transition-3 : false, $transition-4 : false, $transition-5 : false, $transition-6 : false, $transition-7 : false, $transition-8 : false, $transition-9 : false, $transition-10: false 53 | code ) { 54 | code @if $transition-1 == default { 55 | code $transition-1 : compact($default-transition-property $default-transition-duration $default-transition-function $default-transition-delay); 56 | code } 57 | code $transitions: false; 58 | code @if type-of($transition-1) == list and type-of(nth($transition-1,1)) == list { 59 | code $transitions: join($transition-1, compact($transition-2, $transition-3, $transition-4, $transition-5, $transition-6, $transition-7, $transition-8, $transition-9, $transition-10), comma); 60 | code } @else { 61 | code $transitions : compact($transition-1, $transition-2, $transition-3, $transition-4, $transition-5, $transition-6, $transition-7, $transition-8, $transition-9, $transition-10); 62 | code } 63 | code $delays: comma-list(); 64 | code $has-delays: false; 65 | code $webkit-value: comma-list(); 66 | code $moz-value: comma-list(); 67 | code $o-value: comma-list(); 68 | code @each $transition in $transitions { 69 | code $property: nth($transition, 1); 70 | code $duration: false; 71 | code $timing-function: false; 72 | code $delay: false; 73 | code @if length($transition) > 1 { $duration: nth($transition, 2); } 74 | code @if length($transition) > 2 { $timing-function: nth($transition, 3); } 75 | code @if length($transition) > 3 { $delay: nth($transition, 4); $has-delays: true; } 76 | code @if is-time($timing-function) and not $delay { $delay: $timing-function; $timing-function: false; $has-delays: true; } 77 | code $delays: append($delays, if($delay, $delay, 0s)); 78 | code $webkit-value: append($webkit-value, compact(prefixed-for-transition(-webkit, $property) $duration $timing-function)); 79 | code $moz-value: append( $moz-value, compact(prefixed-for-transition( -moz, $property) $duration $timing-function $delay)); 80 | code $o-value: append( $o-value, compact(prefixed-for-transition( -o, $property) $duration $timing-function $delay)); 81 | code } 82 | code @if $experimental-support-for-webkit { -webkit-transition : $webkit-value; 83 | code @if $has-delays { -webkit-transition-delay : $delays; } } 84 | code @if $experimental-support-for-mozilla { -moz-transition : $moz-value; } 85 | code @if $experimental-support-for-opera { -o-transition : $o-value; } 86 | code transition : $transitions; 87 | code } 88 | code @function comma-list($list: ()) { 89 | code @return join((), $list, comma); 90 | code } 91 | code @function prefixed-for-transition($prefix, $property) { 92 | code @if type-of($property) == list { 93 | code $new-list: comma-list(); 94 | code @each $v in $property { 95 | code $new-list: append($new-list, prefixed-for-transition($prefix, $v)); 96 | code } 97 | code @return $new-list; 98 | code } @else { 99 | code @if index($transitionable-prefixed-values, $property) { 100 | code @return #{$prefix}-#{$property}; 101 | code } @else { 102 | code @return $property; 103 | code } 104 | code } 105 | code } 106 | code @function is-time($value) { 107 | code @if type-of($value) == number { 108 | code @return not not index(s ms, unit($value)); 109 | code } @else { 110 | code @return false; 111 | code } 112 | code } 113 | -------------------------------------------------------------------------------- /vendor/bright/screen.scss: -------------------------------------------------------------------------------- 1 | // Bright theme for Shower HTML presentation engine: github.com/shower/shower 2 | // Copyright © 2010–2013 Vadim Makeev, pepelsbey.net 3 | // Licensed under MIT license: github.com/shower/shower/wiki/MIT-License 4 | 5 | @import 'defaults'; 6 | @import 'reset'; 7 | 8 | body { 9 | counter-reset:slide; 10 | font:24px/2 'Open Sans', sans-serif; 11 | } 12 | a { 13 | text-decoration:none; 14 | } 15 | 16 | // Caption 17 | // ------------------------------- 18 | .caption { 19 | display:none; 20 | margin:0 0 60px; 21 | padding:0 50px 0 0; 22 | color:#555; 23 | h1 { 24 | font:50px 'Open Sans Light', sans-serif; 25 | } 26 | a { 27 | color:$color; 28 | &:hover { 29 | border-bottom:0.1em solid; 30 | } 31 | } 32 | } 33 | 34 | // Badge 35 | // ------------------------------- 36 | .badge { 37 | position:absolute; 38 | top:0; 39 | right:0; 40 | display:none; 41 | overflow:hidden; 42 | visibility:hidden; 43 | width:11em; 44 | height:11em; 45 | line-height:2.5; 46 | font-size:15px; 47 | } 48 | .badge a { 49 | position:absolute; 50 | bottom:50%; 51 | right:-50%; 52 | left:-50%; 53 | visibility:visible; 54 | background:$color; 55 | color:#FFF; 56 | text-align:center; 57 | transform-origin:50% 100%; 58 | transform:rotate(45deg) translateY(-1em); 59 | } 60 | 61 | // Slide 62 | // ------------------------------- 63 | .slide { 64 | position:relative; 65 | width:$width; 66 | height:$height; 67 | background:#FFF; 68 | color:#000; 69 | -webkit-print-color-adjust:exact; 70 | -webkit-text-size-adjust:none; 71 | -moz-text-size-adjust:none; 72 | -ms-text-size-adjust:none; 73 | // Number 74 | &:after { 75 | position:absolute; 76 | right:0; 77 | bottom:45px; 78 | left:0; 79 | color:#AAA; 80 | counter-increment:slide; 81 | content:counter(slide); 82 | text-align:center; 83 | line-height:1; 84 | } 85 | // Inner 86 | > div { 87 | position:absolute; 88 | top:0; 89 | left:0; 90 | overflow:hidden; 91 | padding:$top $right 0 $left; 92 | width:$width - $left - $right; 93 | height:$height - $top; 94 | } 95 | } 96 | 97 | // Elements 98 | // ------------------------------- 99 | .slide { 100 | // Header 101 | h2 { 102 | margin:0 0 58px; 103 | font:48px/1 'Open Sans Light', sans-serif; 104 | } 105 | // Text 106 | p { 107 | margin:0 0 48px; 108 | } 109 | a { 110 | border-bottom:0.1em solid; 111 | color:$color; 112 | } 113 | b, strong { 114 | font-weight:bold; 115 | } 116 | i, em { 117 | font-style:italic; 118 | } 119 | kbd, code, samp { 120 | padding:2px 7px; 121 | background:rgba(#000, 0.1); 122 | tab-size:4; 123 | line-height:1; 124 | font-family:'Anka Coder', monospace; 125 | } 126 | // Quote 127 | blockquote { 128 | font-style:italic; 129 | &:before { 130 | position:absolute; 131 | margin:-50px 0 0 -100px; 132 | color:#DDD; 133 | content:'\201C'; 134 | line-height:1; 135 | font-size:200px; 136 | } 137 | & + figcaption { 138 | margin:-48px 0 48px; 139 | font-style:italic; 140 | font-weight:bold; 141 | } 142 | } 143 | // Lists 144 | ol, ul { 145 | margin:0 0 48px; 146 | counter-reset:list; 147 | li { 148 | text-indent:-2em; 149 | &:before { 150 | display:inline-block; 151 | width:2em; 152 | color:#AAA; 153 | text-align:right; 154 | } 155 | } 156 | ol, 157 | ul { 158 | margin:0 0 0 2em; 159 | } 160 | } 161 | ul > li:before { 162 | content:'\2022\00A0\00A0\2009'; 163 | } 164 | ul > li:lang(ru):before { 165 | content:'\2014\00A0\2009'; 166 | } 167 | ol > li:before { 168 | counter-increment:list; 169 | content:counter(list)'.\00A0\2009'; 170 | } 171 | // Code 172 | pre { 173 | margin:0 0 45px; 174 | padding:3px 0 0; 175 | counter-reset:code; 176 | white-space:normal; 177 | code { 178 | display:block; 179 | padding:0; 180 | background:none; 181 | white-space:pre; 182 | line-height:2; 183 | &:before { 184 | position:absolute; 185 | margin-left:-50px; 186 | color:#AAA; 187 | counter-increment:code; 188 | content:counter(code, decimal-leading-zero)'.'; 189 | } 190 | &:only-child:before { 191 | content:''; 192 | } 193 | } 194 | // Mark 195 | mark { 196 | background:none; 197 | color:$color; 198 | font-style:normal; 199 | &.important { 200 | padding:3px 7px 0; 201 | background:$color; 202 | color:#FFF; 203 | } 204 | &.comment { 205 | color:#AAA; 206 | } 207 | } 208 | } 209 | // Table 210 | table { 211 | margin:0 0 50px; 212 | width:100%; 213 | border-collapse:collapse; 214 | border-spacing:0; 215 | th, td { 216 | background:url($dot) 0 100% repeat-x; 217 | } 218 | th { 219 | text-align:left; 220 | font-weight:bold; 221 | } 222 | &.striped { 223 | tr:nth-child(even) { 224 | background:mix($color, #FFF, 8%); 225 | } 226 | } 227 | } 228 | // Cover Shout 229 | &.cover, 230 | &.shout { 231 | z-index:1; 232 | &:after { 233 | content:''; 234 | } 235 | } 236 | // Cover 237 | &.cover { 238 | background:#000; 239 | @mixin cover { 240 | img, svg, video, 241 | object, canvas, iframe { 242 | @content; 243 | } 244 | } 245 | @include cover { 246 | position:absolute; 247 | top:0; 248 | left:0; 249 | z-index:-1; 250 | } 251 | &.w { 252 | @include cover { 253 | top:50%; 254 | width:100%; 255 | transform:translateY(-50%); 256 | } 257 | } 258 | &.h { 259 | @include cover { 260 | left:50%; 261 | height:100%; 262 | transform:translateX(-50%); 263 | } 264 | } 265 | &.w.h { 266 | @include cover { 267 | top:0; 268 | left:0; 269 | transform:none; 270 | } 271 | } 272 | } 273 | // Shout 274 | &.shout { 275 | background:$color; 276 | h2 { 277 | position:absolute; 278 | top:50%; 279 | left:128px; 280 | right:96px; 281 | color:#FFF; 282 | font-size:100px; 283 | transform:translateY(-50%); 284 | a { 285 | border-bottom:none; 286 | color:#FFF; 287 | } 288 | } 289 | } 290 | // Place 291 | .place { 292 | position:absolute; 293 | top:50%; 294 | left:50%; 295 | transform:translate(-50%, -50%); 296 | &.t.l, &.t.r, &.b.r, &.b.l { 297 | transform:none; 298 | } 299 | &.t, &.b { 300 | transform:translate(-50%, 0); 301 | } 302 | &.l, &.r { 303 | transform:translate(0, -50%); 304 | } 305 | &.t, &.t.l, &.t.r { 306 | top:0; 307 | } 308 | &.r { 309 | right:0; 310 | left:auto; 311 | } 312 | &.b, &.b.r, &.b.l { 313 | top:auto; 314 | bottom:0; 315 | } 316 | &.l { 317 | left:0; 318 | } 319 | } 320 | // Notes 321 | footer { 322 | position:absolute; 323 | left:0; 324 | right:0; 325 | bottom:-$height; 326 | z-index:1; 327 | display:none; 328 | padding:20px $right 20px $left; 329 | background:#fafac4; 330 | box-shadow:0 0 0 2px rgba(#000, 0.05); 331 | transition:bottom 0.3s; 332 | } 333 | &:hover footer { 334 | bottom:0; 335 | } 336 | } 337 | 338 | // Screen 339 | @media screen { 340 | // List 341 | .list { 342 | position:absolute; 343 | clip:rect(0, auto, auto, 0); // Having fun with IE10 344 | padding:50px 0 50px 50px; 345 | background:#E2E2E2 inline("bright/mesh.png") 50% 0; 346 | background-size:256px; 347 | text-align:center; 348 | // Outfit 349 | .caption, 350 | .badge { 351 | display:block; 352 | } 353 | // Slide 354 | .slide { 355 | // Gap between slides 356 | $gap:50px; 357 | position:relative; 358 | top:$height/2 - $gap; 359 | display:inline-block; 360 | margin:($gap - $height/2) ($gap - $width/2) 0 0; 361 | text-align:left; 362 | transform-origin:0 0; 363 | transform:scale(0.5); 364 | @media (max-width:$break) { 365 | top:$height/2 + $height/4 - $gap; 366 | margin:($gap - ($height/2 + $height/4)) ($gap - ($width/2 + $width/4)) 0 0; 367 | transform:scale(0.25); 368 | } 369 | // Frame 370 | &:before { 371 | position:absolute; 372 | top:0; 373 | left:0; 374 | z-index:-1; 375 | width:$width/2; 376 | height:$height/2; 377 | box-shadow:0 0 0 1px #DDD; 378 | content:''; 379 | transform-origin:0 0; 380 | transform:scale(2); 381 | @media (max-width:$break) { 382 | width:$width/4; 383 | height:$height/4; 384 | transform:scale(4); 385 | } 386 | } 387 | // Number 388 | &:after { 389 | top:100%; 390 | bottom:auto; 391 | padding-top:50px; 392 | @media (max-width:$break) { 393 | width:$width/2; 394 | transform-origin:0 0; 395 | transform:scale(2); 396 | } 397 | } 398 | // Hover 399 | &:hover:before { 400 | box-shadow: 401 | 0 0 0 1px #EEE, 402 | 0 0 0 12px rgba(#FFF, 0.5); 403 | } 404 | // Current 405 | &:target { 406 | &:before { 407 | box-shadow: 408 | 0 0 10px 0 darken($color, 5%), 409 | 0 0 0 12px $color; 410 | } 411 | &:after { 412 | color:$color; 413 | } 414 | } 415 | // Inner 416 | > div { 417 | &:before { 418 | position:absolute; 419 | top:0; 420 | right:0; 421 | bottom:0; 422 | left:0; 423 | z-index:2; 424 | content:''; 425 | } 426 | } 427 | // Cover Shout 428 | &.cover, 429 | &.shout { 430 | &:after { 431 | content:counter(slide); 432 | } 433 | } 434 | // Notes 435 | footer { 436 | display:block; 437 | } 438 | } 439 | } 440 | // Full 441 | .full { 442 | position:absolute; 443 | top:50%; 444 | left:50%; 445 | overflow:hidden; 446 | margin:(-$height/2) 0 0 (-$width/2); 447 | width:$width; 448 | height:$height; 449 | background:#000; 450 | // Slide 451 | .slide { 452 | position:absolute; 453 | top:0; 454 | left:0; 455 | margin-left:150%; 456 | // Next 457 | .next { 458 | visibility:hidden; 459 | &.active { 460 | visibility:visible; 461 | } 462 | } 463 | // Current 464 | &:target { 465 | margin:0; 466 | } 467 | // Shout 468 | &.shout { 469 | &.right, &.up { 470 | h2 { 471 | opacity:0; 472 | transition:all 0.4s ease-out; 473 | } 474 | &:target h2 { 475 | opacity:1; 476 | transform:translateX(0) translateY(-50%); 477 | } 478 | } 479 | &.right h2 { 480 | transform:translateX(-100%) translateY(-50%); 481 | } 482 | &.up h2 { 483 | transform:translateX(0) translateY(100%); 484 | } 485 | } 486 | } 487 | // Progress 488 | .progress { 489 | position:absolute; 490 | right:0; 491 | bottom:0; 492 | left:0; 493 | z-index:1; 494 | div { 495 | position:absolute; 496 | left:0; 497 | bottom:0; 498 | width:0; 499 | height:8px; 500 | background:$color; 501 | transition:width 0.2s linear; 502 | } 503 | } 504 | } 505 | } 506 | 507 | // Print 508 | @page { 509 | margin:0; 510 | size:$width $height; 511 | } 512 | -------------------------------------------------------------------------------- /vendor/shower.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Shower HTML presentation engine: github.com/shower/shower 3 | * @copyright 2010–2013 Vadim Makeev, pepelsbey.net 4 | * @license MIT license: github.com/shower/shower/wiki/MIT-License 5 | */ 6 | window.shower = window.shower || (function(window, document, undefined) { 7 | var shower = {}, 8 | url = window.location, 9 | body = document.body, 10 | slides = [], 11 | progress = [], 12 | timer, 13 | isHistoryApiSupported = !!(window.history && window.history.pushState); 14 | 15 | /** 16 | * Slide constructor 17 | * 18 | * @param {Object} opts 19 | * @param {String} opts.id html id attribute or automaticaly assigned order number 20 | * @param {Number} opts.number slide number 21 | * @param {Boolean} opts.hasInnerNavigation 22 | * @param {Number} [opts.timing] 23 | * @param {Number} [opts.innerLength] 24 | * @param {Number} [opts.innerComplete = 0] 25 | * @constructor 26 | */ 27 | function Slide(opts) { 28 | for (var prop in opts) { 29 | if (opts.hasOwnProperty(prop)) { 30 | this[prop] = opts[prop]; 31 | } 32 | } 33 | } 34 | 35 | Slide.prototype = { 36 | /** 37 | * Get slide number. 38 | * @returns {Number} 39 | */ 40 | getSlideNumber : function() { 41 | return this.number; 42 | }, 43 | 44 | isLast : function() { 45 | return shower.slideList.length === this.number + 1; 46 | }, 47 | 48 | /** 49 | * Check if inner navigation is finished 50 | * @returns {boolean} 51 | */ 52 | isFinished : function() { 53 | return this.innerComplete >= this.innerLength; 54 | }, 55 | 56 | /** 57 | * Start inner navigation by timer or just switch slide after timer. 58 | * time sets in HTML: .slide[data-timing=MM:SS] 59 | * @returns {Object} Current slide 60 | */ 61 | process : function(shower) { 62 | if (this.timing) { 63 | this.initTimer(shower); 64 | return this; 65 | } 66 | 67 | this.next(shower); 68 | return this; 69 | }, 70 | 71 | /** 72 | * Init timer for inner navigation or for just turn to next slide 73 | * @param shower 74 | * @returns {Object|Boolean} Current slide 75 | */ 76 | initTimer : function(shower) { 77 | var slide = this; 78 | 79 | if ( ! slide.timing) { 80 | return false; 81 | } 82 | 83 | slide.stopTimer(); 84 | 85 | if (slide.isFinished()) { 86 | timer = setInterval(function() { 87 | slide.stopTimer(); 88 | shower.next(); 89 | }, 90 | slide.timing * (slide.innerLength || 1)); 91 | } else { 92 | timer = setInterval(function() { 93 | if (slide.isFinished()) { 94 | slide.stopTimer(); 95 | shower.next(); 96 | } else { 97 | slide.next(shower); 98 | } 99 | }, 100 | slide.timing); 101 | } 102 | 103 | return this; 104 | }, 105 | 106 | /** 107 | * Stop timer 108 | */ 109 | stopTimer : function() { 110 | if (timer) { 111 | clearInterval(timer); 112 | timer = false; 113 | } 114 | 115 | return this; 116 | }, 117 | 118 | /** 119 | * Previous step of inner navigation or if current step is step 0 then go to previous slide. 120 | * @returns {Object|Boolean} Current slide 121 | */ 122 | prev : function(shower) { 123 | var prevSteps, 124 | slide = this; 125 | 126 | if ( ! slide.hasInnerNavigation || slide.isFinished() || slide.innerComplete === 0) { 127 | shower.prev(); 128 | return false; 129 | } 130 | 131 | prevSteps = document.getElementById(slide.id).querySelectorAll('.next.active'); 132 | 133 | if ( ! prevSteps || prevSteps.length < 1) { 134 | return false; 135 | } 136 | 137 | if (slide.innerComplete > 0) { 138 | slide.innerComplete--; 139 | prevSteps[prevSteps.length - 1].classList.remove('active'); 140 | } else { 141 | shower.prev(); 142 | } 143 | 144 | return this; 145 | }, 146 | 147 | /** 148 | * Next step of inner navigation or if current step is last then go to next slide. 149 | * @returns {Object|Boolean} Current slide 150 | */ 151 | next : function(shower) { 152 | var nextSteps, 153 | slide = this; 154 | 155 | if ( ! slide.hasInnerNavigation || slide.isFinished()) { 156 | shower.next(); 157 | return false; 158 | } 159 | 160 | if ( ! slide.isFinished()) { 161 | nextSteps = document.getElementById(slide.id).querySelectorAll('.next:not(.active)'); 162 | nextSteps[0].classList.add('active'); 163 | 164 | slide.innerComplete++; 165 | } 166 | 167 | return this; 168 | } 169 | }; 170 | 171 | /** 172 | * Get value at named data store for the DOM element. 173 | * @private 174 | * @param {HTMLElement} element 175 | * @param {String} name 176 | * @returns {String} 177 | */ 178 | shower._getData = function(element, name) { 179 | return element.dataset ? element.dataset[name] : element.getAttribute('data-' + name); 180 | }; 181 | 182 | shower.slideList = []; 183 | 184 | /** 185 | * Shower initialization 186 | * @param {String} [slideSelector] 187 | * @param {String} [progressSelector] 188 | * @returns {Object} shower 189 | */ 190 | shower.init = function(slideSelector, progressSelector) { 191 | var timing; 192 | 193 | slideSelector = slideSelector || '.slide'; 194 | progressSelector = progressSelector || 'div.progress div'; 195 | 196 | slides = document.querySelectorAll(slideSelector); 197 | progress = document.querySelector(progressSelector); 198 | 199 | for (var i = 0; i < slides.length; i++) { 200 | // Slide IDs are optional. 201 | // In case of missing ID we set it to the slide number 202 | if ( ! slides[i].id) { 203 | slides[i].id = i + 1; 204 | } 205 | 206 | timing = shower._getData(slides[i], 'timing'); 207 | 208 | // Parsing timing in [S] or [M:S] format 209 | // and returning it in milliseconds 210 | if (timing && /^(\d{1,2}:)?\d{1,3}$/.test(timing)) { 211 | if (timing.indexOf(':') !== -1) { 212 | timing = timing.split(':'); 213 | timing = (parseInt(timing[0], 10) * 60 + parseInt(timing[1], 10)) * 1000; 214 | } else { 215 | timing = parseInt(timing, 10) * 1000; 216 | } 217 | if (timing === 0) { 218 | timing = false; 219 | } 220 | } else { 221 | timing = false; 222 | } 223 | 224 | shower.slideList.push(new Slide({ 225 | id : slides[i].id, 226 | number : i, 227 | hasInnerNavigation : null !== slides[i].querySelector('.next'), 228 | timing : timing, 229 | innerLength : slides[i].querySelectorAll('.next').length, 230 | innerComplete : 0 231 | })); 232 | } 233 | 234 | return shower; 235 | }; 236 | 237 | /** 238 | * Get slide scale value. 239 | * @private 240 | * @returns {String} 241 | */ 242 | shower._getTransform = function() { 243 | var denominator = Math.max( 244 | body.clientWidth / window.innerWidth, 245 | body.clientHeight / window.innerHeight 246 | ); 247 | 248 | return 'scale(' + (1 / denominator) + ')'; 249 | }; 250 | 251 | /** 252 | * Set CSS transform with prefixes to body. 253 | * @private 254 | * @returns {Boolean} 255 | */ 256 | shower._applyTransform = function(transform) { 257 | [ 258 | 'WebkitTransform', 259 | 'MozTransform', 260 | 'msTransform', 261 | 'OTransform', 262 | 'transform' 263 | ].forEach(function(prop) { 264 | body.style[prop] = transform; 265 | }); 266 | 267 | return true; 268 | }; 269 | 270 | /** 271 | * Check if arg is number. 272 | * @private 273 | * @param {String|Number} arg 274 | * @returns {Boolean} 275 | */ 276 | shower._isNumber = function(arg) { 277 | return ! isNaN(parseFloat(arg)) && isFinite(arg); 278 | }; 279 | 280 | /** 281 | * Normalize slide number. 282 | * @private 283 | * @param {Number} slideNumber slide number (sic!) 284 | * @returns {Number} 285 | */ 286 | shower._normalizeSlideNumber = function(slideNumber) { 287 | if ( ! shower._isNumber(slideNumber)) { 288 | throw new Error('Gimme slide number as Number, baby!'); 289 | } 290 | 291 | if (slideNumber < 0) { 292 | slideNumber = 0; 293 | } 294 | 295 | if (slideNumber >= shower.slideList.length) { 296 | slideNumber = shower.slideList.length - 1; 297 | } 298 | 299 | return slideNumber; 300 | }; 301 | 302 | /** 303 | * Get slide id from HTML element. 304 | * @private 305 | * @param {Node} el 306 | * @returns {String} 307 | */ 308 | shower._getSlideIdByEl = function(el) { 309 | while ('BODY' !== el.nodeName && 'HTML' !== el.nodeName) { 310 | if (el.classList.contains('slide')) { 311 | return el.id; 312 | } else { 313 | el = el.parentNode; 314 | } 315 | } 316 | 317 | return ''; 318 | }; 319 | 320 | /** 321 | * For touch devices: check if link is clicked. 322 | * 323 | * @TODO: add support for textarea/input/etc. 324 | * 325 | * @private 326 | * @param {HTMLElement} e 327 | * @returns {Boolean} 328 | */ 329 | shower._checkInteractiveElement = function(e) { 330 | return 'A' === e.target.nodeName; 331 | }; 332 | 333 | /** 334 | * Get slide number by slideId. 335 | * @param {String} slideId 336 | * @returns {Number} 337 | */ 338 | shower.getSlideNumber = function(slideId) { 339 | var i = shower.slideList.length - 1, 340 | slideNumber; 341 | 342 | if (slideId === '') { 343 | slideNumber = 0; 344 | } 345 | 346 | // As fast as you can ;-) 347 | // http://jsperf.com/for-vs-foreach/46 348 | for (; i >= 0; --i) { 349 | if (slideId === shower.slideList[i].id) { 350 | slideNumber = i; 351 | break; 352 | } 353 | } 354 | 355 | return slideNumber; 356 | }; 357 | 358 | /** 359 | * Go to slide number. 360 | * @param {Number} slideNumber slide number (sic!). Attention: starts from zero. 361 | * @param {Function} [callback] runs only if you not in List mode. 362 | * @returns {Number|Boolean} 363 | */ 364 | shower.go = function(slideNumber, callback) { 365 | var slide; 366 | 367 | if ( ! shower._isNumber(slideNumber)) { 368 | throw new Error('Gimme slide number as Number, baby!'); 369 | } 370 | 371 | if ( ! shower.slideList[slideNumber]) { 372 | return false; 373 | } 374 | 375 | // Also triggers popstate and invoke shower.enter__Mode() 376 | url.hash = shower.getSlideHash(slideNumber); 377 | 378 | shower.updateProgress(slideNumber); 379 | shower.updateActiveAndVisitedSlides(slideNumber); 380 | 381 | if (shower.isSlideMode()) { 382 | shower.showPresenterNotes(slideNumber); 383 | slide = shower.slideList[slideNumber]; 384 | if (slide.timing) { 385 | slide.initTimer(shower); 386 | } 387 | } 388 | 389 | if (typeof(callback) === 'function') { 390 | callback(); 391 | } 392 | 393 | return slideNumber; 394 | }; 395 | 396 | /** 397 | * Show next slide or show next Inner navigation item. 398 | * Returns false on a last slide, otherwise returns shower. 399 | * @param {Function} [callback] runs only if shower.next() is successfully completed. 400 | * @returns {Boolean} 401 | */ 402 | shower.next = function(callback) { 403 | var currentSlideNumber = shower.getCurrentSlideNumber(), 404 | nextSlide = shower.slideList[currentSlideNumber + 1]; 405 | 406 | // If don't exist next slide 407 | if (! nextSlide) { 408 | return false; 409 | } 410 | 411 | shower.go(currentSlideNumber + 1); 412 | 413 | if (typeof(callback) === 'function') { 414 | callback(); 415 | } 416 | 417 | return this; 418 | }; 419 | 420 | /** 421 | * 422 | * @param {Function} [callback] 423 | */ 424 | shower._turnNextSlide = function(callback) { 425 | var currentSlideNumber = shower.getCurrentSlideNumber(), 426 | slide = shower.slideList[currentSlideNumber]; 427 | 428 | 429 | if (shower.isSlideMode()) { 430 | slide.stopTimer(); 431 | slide.next(shower); 432 | } else { 433 | shower.go(currentSlideNumber + 1); 434 | } 435 | 436 | if (typeof(callback) === 'function') { 437 | callback(); 438 | } 439 | 440 | return; 441 | }; 442 | 443 | /** 444 | * Show previous slide. Returns false on a first slide, otherwise returns shown slide number. 445 | * @param {Function} [callback] runs only if shower.previous() is successfully completed. 446 | * @returns {Boolean} 447 | */ 448 | shower.prev = shower.previous = function(callback) { 449 | var currentSlideNumber = shower.getCurrentSlideNumber(); 450 | 451 | // Slides starts from 0 452 | if (currentSlideNumber < 1) { 453 | return false; 454 | } 455 | 456 | shower.go(currentSlideNumber - 1); 457 | 458 | if (typeof(callback) === 'function') { 459 | callback(); 460 | } 461 | 462 | return true; 463 | }; 464 | 465 | /** 466 | * Show previous slide. Returns false on a first slide, otherwise returns shown slide number. 467 | * @param {Function} [callback] runs only if shower.previous() is successfully completed. 468 | * @returns {Boolean} 469 | */ 470 | shower._turnPreviousSlide = function(callback) { 471 | var currentSlideNumber = shower.getCurrentSlideNumber(), 472 | slide = shower.slideList[currentSlideNumber]; 473 | 474 | slide.stopTimer(); 475 | 476 | if (shower.isSlideMode()) { 477 | slide.prev(shower); 478 | } else { 479 | shower.go(currentSlideNumber - 1); 480 | } 481 | 482 | if (typeof(callback) === 'function') { 483 | callback(); 484 | } 485 | 486 | return true; 487 | }; 488 | 489 | /** 490 | * Show first slide. 491 | * @param {Function} [callback] 492 | */ 493 | shower.first = function(callback) { 494 | var slide = shower.slideList[shower.getCurrentSlideNumber()]; 495 | 496 | slide && slide.timing && slide.stopTimer(); 497 | shower.go(0); 498 | 499 | if (typeof(callback) === 'function') { 500 | callback(); 501 | } 502 | }; 503 | 504 | /** 505 | * Show last slide. 506 | * @param {Function} [callback] 507 | */ 508 | shower.last = function(callback) { 509 | var slide = shower.slideList[shower.getCurrentSlideNumber()]; 510 | 511 | slide && slide.timing && slide.stopTimer(); 512 | shower.go(shower.slideList.length - 1); 513 | 514 | if (typeof(callback) === 'function') { 515 | callback(); 516 | } 517 | }; 518 | 519 | /** 520 | * Switch to slide view. 521 | * @param {Function} [callback] runs only if shower.enterSlideMode() is successfully completed. 522 | * @returns {Boolean} 523 | */ 524 | shower.enterSlideMode = function(callback) { 525 | var currentSlideNumber = shower.getCurrentSlideNumber(); 526 | 527 | // Anyway: change body class (@TODO: refactoring) 528 | body.classList.remove('list'); 529 | body.classList.add('full'); 530 | 531 | // Preparing URL for shower.go() 532 | if (shower.isListMode() && isHistoryApiSupported) { 533 | history.pushState(null, null, url.pathname + '?full' + shower.getSlideHash(currentSlideNumber)); 534 | } 535 | 536 | shower._applyTransform(shower._getTransform()); 537 | 538 | if (typeof(callback) === 'function') { 539 | callback(); 540 | } 541 | 542 | return true; 543 | }; 544 | 545 | /** 546 | * Switch to list view. 547 | * @param {Function} [callback] runs only if shower.enterListMode() is successfully completed. 548 | * @returns {Boolean} 549 | */ 550 | shower.enterListMode = function(callback) { 551 | var currentSlideNumber; 552 | 553 | // Anyway: change body class (@TODO: refactoring) 554 | body.classList.remove('full'); 555 | body.classList.add('list'); 556 | 557 | shower.clearPresenterNotes(); 558 | shower._applyTransform('none'); 559 | 560 | if (shower.isListMode()) { 561 | return false; 562 | } 563 | 564 | currentSlideNumber = shower.getCurrentSlideNumber(); 565 | 566 | shower.slideList[currentSlideNumber].stopTimer(); 567 | 568 | if (shower.isSlideMode() && isHistoryApiSupported) { 569 | history.pushState(null, null, url.pathname + shower.getSlideHash(currentSlideNumber)); 570 | } 571 | 572 | shower.scrollToSlide(currentSlideNumber); 573 | 574 | if (typeof(callback) === 'function') { 575 | callback(); 576 | } 577 | 578 | return true; 579 | }; 580 | 581 | /** 582 | * Toggle Mode: Slide and List. 583 | * @param {Function} [callback] 584 | */ 585 | shower.toggleMode = function(callback) { 586 | if (shower.isListMode()) { 587 | shower.enterSlideMode(); 588 | } else { 589 | shower.enterListMode(); 590 | } 591 | 592 | if (typeof(callback) === 'function') { 593 | callback(); 594 | } 595 | 596 | return true; 597 | }; 598 | 599 | /** 600 | * Get current slide number. Starts from zero. Warning: when you have 601 | * slide number 1 in URL this method will return 0. 602 | * If there is no slide number in url, return -1. 603 | * If there is a slide number in url, but the slide does not exist, return 0. 604 | * @returns {Number} 605 | */ 606 | shower.getCurrentSlideNumber = function() { 607 | var i = shower.slideList.length - 1, 608 | currentSlideId = url.hash.substr(1); 609 | 610 | if (currentSlideId === '') { 611 | return -1; 612 | } 613 | 614 | // As fast as you can ;-) 615 | // http://jsperf.com/for-vs-foreach/46 616 | for (; i >= 0; --i) { 617 | if (currentSlideId === shower.slideList[i].id) { 618 | return i; 619 | } 620 | } 621 | 622 | return 0; 623 | }; 624 | 625 | /** 626 | * Scroll to slide. 627 | * @param {Number} slideNumber slide number (sic!) 628 | * @returns {Boolean} 629 | */ 630 | shower.scrollToSlide = function(slideNumber) { 631 | var currentSlide, 632 | ret = false; 633 | 634 | if ( ! shower._isNumber(slideNumber)) { 635 | throw new Error('Gimme slide number as Number, baby!'); 636 | } 637 | 638 | if (shower.isSlideMode()) { 639 | throw new Error('You can\'t scroll to because you in slide mode. Please, switch to list mode.'); 640 | } 641 | 642 | // @TODO: WTF? 643 | if (-1 === slideNumber) { 644 | return ret; 645 | } 646 | 647 | if (shower.slideList[slideNumber]) { 648 | currentSlide = document.getElementById(shower.slideList[slideNumber].id); 649 | window.scrollTo(0, currentSlide.offsetTop); 650 | ret = true; 651 | } else { 652 | throw new Error('There is no slide with number ' + slideNumber); 653 | } 654 | 655 | return ret; 656 | }; 657 | 658 | /** 659 | * Check if it's List mode. 660 | * @returns {Boolean} 661 | */ 662 | shower.isListMode = function() { 663 | return isHistoryApiSupported ? ! /^full.*/.test(url.search.substr(1)) : body.classList.contains('list'); 664 | }; 665 | 666 | /** 667 | * Check if it's Slide mode. 668 | * @returns {Boolean} 669 | */ 670 | shower.isSlideMode = function() { 671 | return isHistoryApiSupported ? /^full.*/.test(url.search.substr(1)) : body.classList.contains('full'); 672 | }; 673 | 674 | /** 675 | * Update progress bar. 676 | * @param {Number} slideNumber slide number (sic!) 677 | * @returns {Boolean} 678 | */ 679 | shower.updateProgress = function(slideNumber) { 680 | // if progress bar doesn't exist 681 | if (null === progress) { 682 | return false; 683 | } 684 | 685 | if ( ! shower._isNumber(slideNumber)) { 686 | throw new Error('Gimme slide number as Number, baby!'); 687 | } 688 | 689 | progress.style.width = (100 / (shower.slideList.length - 1) * shower._normalizeSlideNumber(slideNumber)).toFixed(2) + '%'; 690 | 691 | return true; 692 | }; 693 | 694 | /** 695 | * Update active and visited slides. 696 | * @param {Number} slideNumber slide number (sic!) 697 | * @returns {Boolean} 698 | */ 699 | shower.updateActiveAndVisitedSlides = function(slideNumber) { 700 | var i, 701 | slide, 702 | l = shower.slideList.length; 703 | 704 | slideNumber = shower._normalizeSlideNumber(slideNumber); 705 | 706 | if ( ! shower._isNumber(slideNumber)) { 707 | throw new Error('Gimme slide number as Number, baby!'); 708 | } 709 | 710 | for (i = 0; i < l; ++i) { 711 | slide = document.getElementById(shower.slideList[i].id); 712 | 713 | if (i < slideNumber) { 714 | slide.classList.remove('active'); 715 | slide.classList.add('visited'); 716 | } else if (i > slideNumber) { 717 | slide.classList.remove('visited'); 718 | slide.classList.remove('active'); 719 | } else { 720 | slide.classList.remove('visited'); 721 | slide.classList.add('active'); 722 | } 723 | } 724 | 725 | return true; 726 | }; 727 | 728 | /** 729 | * Clear presenter notes in console (only for Slide Mode). 730 | */ 731 | shower.clearPresenterNotes = function() { 732 | if (shower.isSlideMode() && window.console && window.console.clear) { 733 | console.clear(); 734 | } 735 | }; 736 | 737 | /** 738 | * Show presenter notes in console. 739 | * @param {Number} slideNumber slide number (sic!). Attention: starts from zero. 740 | */ 741 | shower.showPresenterNotes = function(slideNumber) { 742 | shower.clearPresenterNotes(); 743 | 744 | if (window.console) { 745 | slideNumber = shower._normalizeSlideNumber(slideNumber); 746 | 747 | var slideId = shower.slideList[slideNumber].id, 748 | nextSlideId = shower.slideList[slideNumber + 1] ? shower.slideList[slideNumber + 1].id : null, 749 | notes = document.getElementById(slideId).querySelector('footer'); 750 | 751 | if (notes && notes.innerHTML) { 752 | console.info(notes.innerHTML.replace(/\n\s+/g,'\n')); 753 | } 754 | 755 | if (nextSlideId) { 756 | 757 | var next = document.getElementById(nextSlideId).querySelector('h2'); 758 | 759 | if (next) { 760 | next = next.innerHTML.replace(/^\s+|<[^>]+>/g,''); 761 | console.info('NEXT: ' + next); 762 | } 763 | } 764 | } 765 | }; 766 | 767 | /** 768 | * Get slide hash. 769 | * @param {Number} slideNumber slide number (sic!). Attention: starts from zero. 770 | * @returns {String} 771 | */ 772 | shower.getSlideHash = function(slideNumber) { 773 | if ( ! shower._isNumber(slideNumber)) { 774 | throw new Error('Gimme slide number as Number, baby!'); 775 | } 776 | 777 | slideNumber = shower._normalizeSlideNumber(slideNumber); 778 | 779 | return '#' + shower.slideList[slideNumber].id; 780 | }; 781 | 782 | /** 783 | * Wheel event listener 784 | * @param e event 785 | */ 786 | shower.wheel = function (e) { 787 | var body = document.querySelector('body'), 788 | wheelDown, 789 | lockedWheel = body.getAttribute('data-scroll') === 'locked'; 790 | 791 | if (!lockedWheel && !shower.isListMode()) { 792 | body.setAttribute('data-scroll', 'locked'); 793 | 794 | if (e.deltaY === undefined) { 795 | // Chrome, Opera, Safari 796 | wheelDown = e.wheelDeltaY < 0; 797 | } else { 798 | // Firefox 799 | wheelDown = e.deltaY > 0; 800 | } 801 | 802 | if (wheelDown) { 803 | shower._turnNextSlide(); 804 | } else { 805 | shower._turnPreviousSlide(); 806 | } 807 | 808 | setTimeout(function () { 809 | body.setAttribute('data-scroll', 'unlocked'); 810 | }, 200); 811 | } 812 | } 813 | 814 | // Event handlers 815 | 816 | window.addEventListener('DOMContentLoaded', function() { 817 | var currentSlideNumber = shower.getCurrentSlideNumber(), 818 | isSlideMode = body.classList.contains('full') || shower.isSlideMode(); 819 | 820 | if (currentSlideNumber === -1 && isSlideMode) { 821 | shower.go(0); 822 | } else if (currentSlideNumber === 0 || isSlideMode) { 823 | shower.go(currentSlideNumber); 824 | } 825 | 826 | if (isSlideMode) { 827 | shower.enterSlideMode(); 828 | } 829 | }, false); 830 | 831 | window.addEventListener('popstate', function() { 832 | var currentSlideNumber = shower.getCurrentSlideNumber(); 833 | 834 | if (currentSlideNumber !== -1) { 835 | shower.go(currentSlideNumber); 836 | } 837 | 838 | if (shower.isListMode()) { 839 | shower.enterListMode(); 840 | } else { 841 | shower.enterSlideMode(); 842 | } 843 | }, false); 844 | 845 | window.addEventListener('resize', function() { 846 | if (shower.isSlideMode()) { 847 | shower._applyTransform(shower._getTransform()); 848 | } 849 | }, false); 850 | 851 | document.addEventListener('keydown', function(e) { 852 | var currentSlideNumber = shower.getCurrentSlideNumber(), 853 | slide = shower.slideList[ currentSlideNumber !== -1 ? currentSlideNumber : 0 ], 854 | slideNumber; 855 | 856 | switch (e.which) { 857 | case 80: // P Alt Cmd 858 | if (shower.isListMode() && e.altKey && e.metaKey) { 859 | e.preventDefault(); 860 | 861 | slideNumber = slide.number; 862 | 863 | shower.go(slideNumber); 864 | shower.enterSlideMode(); 865 | shower.showPresenterNotes(slideNumber); 866 | 867 | slide.timing && slide.initTimer(shower); 868 | } 869 | break; 870 | 871 | case 116: // F5 (Shift) 872 | e.preventDefault(); 873 | if (shower.isListMode()) { 874 | slideNumber = e.shiftKey ? slide.number : 0; 875 | 876 | shower.go(slideNumber); 877 | shower.enterSlideMode(); 878 | shower.showPresenterNotes(slideNumber); 879 | 880 | slide.timing && slide.initTimer(shower); 881 | } else { 882 | shower.enterListMode(); 883 | } 884 | break; 885 | 886 | case 13: // Enter 887 | if (shower.isListMode() && -1 !== currentSlideNumber) { 888 | e.preventDefault(); 889 | 890 | shower.enterSlideMode(); 891 | shower.showPresenterNotes(currentSlideNumber); 892 | 893 | slide.timing && slide.initTimer(shower); 894 | } 895 | break; 896 | 897 | case 27: // Esc 898 | if (shower.isSlideMode()) { 899 | e.preventDefault(); 900 | shower.enterListMode(); 901 | } 902 | break; 903 | 904 | case 33: // PgUp 905 | case 38: // Up 906 | case 37: // Left 907 | case 72: // H 908 | case 75: // K 909 | if (e.altKey || e.ctrlKey || e.metaKey) { return; } 910 | e.preventDefault(); 911 | shower._turnPreviousSlide(); 912 | break; 913 | 914 | case 34: // PgDown 915 | case 40: // Down 916 | case 39: // Right 917 | case 76: // L 918 | case 74: // J 919 | if (e.altKey || e.ctrlKey || e.metaKey) { return; } 920 | e.preventDefault(); 921 | shower._turnNextSlide(); 922 | break; 923 | 924 | case 36: // Home 925 | e.preventDefault(); 926 | shower.first(); 927 | break; 928 | 929 | case 35: // End 930 | e.preventDefault(); 931 | shower.last(); 932 | break; 933 | 934 | case 9: // Tab (Shift) 935 | case 32: // Space (Shift) 936 | e.preventDefault(); 937 | shower[e.shiftKey ? '_turnPreviousSlide' : '_turnNextSlide'](); 938 | break; 939 | 940 | default: 941 | // Behave as usual 942 | } 943 | }, false); 944 | 945 | shower.init(); 946 | 947 | document.addEventListener('click', function(e) { 948 | var slideId = shower._getSlideIdByEl(e.target), 949 | slideNumber, 950 | slide; 951 | 952 | // Click on slide in List mode 953 | if (slideId && shower.isListMode()) { 954 | slideNumber = shower.getSlideNumber(slideId); 955 | // Warning: go must be before enterSlideMode. 956 | // Otherwise there is a bug in Chrome 957 | shower.go(slideNumber); 958 | shower.enterSlideMode(); 959 | shower.showPresenterNotes(slideNumber); 960 | 961 | slide = shower.slideList[slideNumber]; 962 | if (slide.timing) { 963 | slide.initTimer(shower); 964 | } 965 | } 966 | }, false); 967 | 968 | document.addEventListener('touchstart', function(e) { 969 | var slideId = shower._getSlideIdByEl(e.target), 970 | slideNumber, 971 | slide, 972 | x; 973 | 974 | if (slideId) { 975 | if (shower.isSlideMode() && ! shower._checkInteractiveElement(e)) { 976 | x = e.touches[0].pageX; 977 | 978 | if (x > window.innerWidth / 2) { 979 | shower._turnNextSlide(); 980 | } else { 981 | shower._turnPreviousSlide(); 982 | } 983 | } 984 | 985 | if (shower.isListMode()) { 986 | slideNumber = shower.getSlideNumber(slideId); 987 | // Warning: go must be before enterSlideMode. 988 | // Otherwise there is a bug in Chrome 989 | shower.go(slideNumber); 990 | shower.enterSlideMode(); 991 | shower.showPresenterNotes(slideNumber); 992 | 993 | slide = shower.slideList[slideNumber]; 994 | if (slide.timing) { 995 | slide.initTimer(shower); 996 | } 997 | } 998 | } 999 | 1000 | }, false); 1001 | 1002 | document.addEventListener('touchmove', function(e) { 1003 | if (shower.isSlideMode()) { 1004 | e.preventDefault(); 1005 | } 1006 | }, false); 1007 | 1008 | document.addEventListener('wheel', shower.wheel, false); 1009 | 1010 | document.addEventListener('mousewheel', shower.wheel, false); 1011 | 1012 | return shower; 1013 | 1014 | })(this, this.document); 1015 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. [http://fsf.org/] 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | {one line to give the program's name and a brief idea of what it does.} 635 | Copyright (C) {year} {name of author} 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see [http://www.gnu.org/licenses/]. 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | {project} Copyright (C) {year} {fullname} 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | [http://www.gnu.org/licenses/]. 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | [http://www.gnu.org/philosophy/why-not-lgpl.html]. 675 | --------------------------------------------------------------------------------