├── .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 |
--------------------------------------------------------------------------------