lots of changes

This commit is contained in:
james
2020-11-11 13:50:29 +00:00
parent 3d9efa1dc2
commit 12c6009895
365 changed files with 60 additions and 731 deletions

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 446 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 121 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 224 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 292 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 224 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 31 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -0,0 +1,5 @@
<slide class="end-slide">
<article>
</article>
</slide>

View File

@@ -0,0 +1,182 @@
<!--
Google IO 2012/2013 HTML5 Slide Template
Authors: Eric Bidelman <ebidel@gmail.com>
Luke Mahé <lukem@google.com>
URL: https://code.google.com/p/io-2012-slides
-->
{%- block doctype -%}
<!DOCTYPE html>
{%- endblock %}
{%- set reldelim1 = reldelim1 is not defined and ' &raquo;' or reldelim1 %}
{%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %}
{%- set render_sidebar = (not embedded) and (not theme_nosidebar|tobool) and
(sidebars != []) %}
{%- set url_root = pathto('', 1) %}
{# XXX necessary? #}
{%- if url_root == '#' %}{% set url_root = '' %}{% endif %}
{%- if not embedded and docstitle %}
{%- set titlesuffix = " &mdash; "|safe + docstitle|e %}
{%- else %}
{%- set titlesuffix = "" %}
{%- endif %}
{%- macro relbar() %}
{%- endmacro %}
{%- macro sidebar() %}
{%- endmacro %}
{%- macro script() %}
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '../',
VERSION: '1.21',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script data-main="{{ pathto('_static/js/slides', 1) }}"
src="{{ pathto('_static/js/require-1.0.8.min.js', 1) }}"></script>
{%- for scriptfile in script_files %}
<script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script>
{%- endfor %}
{% if theme_custom_js %}
<script type="text/javascript" src="{{ pathto('_static/' + theme_custom_js, 1) }}"></script>
{% endif %}
{%- endmacro %}
{%- macro css() %}
<link rel="stylesheet" media="all"
href="{{ pathto('_static/theme/css/default.css', 1) }}">
<link rel="stylesheet" media="all"
href="{{ pathto('_static/theme/css/hieroglyph.css', 1) }}">
<link rel="stylesheet" media="only screen and (max-device-width: 480px)"
href="{{ pathto('_static/theme/css/phone.css', 1) }}">
<link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1) }}" type="text/css" />
{% if theme_custom_css %}
<link rel="stylesheet" href="{{ pathto('_static/' + theme_custom_css, 1) }}"
type="text/css" />
{% endif %}
{%- for cssfile in css_files %}
<link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
{%- endfor %}
{%- endmacro %}
<html>
<head>
{%- block htmltitle %}
<title>{{ title|striptags|e }}{{ titlesuffix }}</title>
{%- endblock %}
<meta charset="{{ encoding }}">
{{ metatags }}
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<!-- comment -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<!--<meta name="viewport" content="width=device-width, initial-scale=1.0">-->
<!--This one seems to work all the time, but really small on ipad-->
<!--<meta name="viewport" content="initial-scale=0.4">-->
<!-- end comment -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="hieroglyph-title" data-config-title>
<meta name="hieroglyph-subtitle" data-config-subtitle>
<meta name="hieroglyph-presenter" data-config-presenter>
{{ css() }}
<base target="_blank"> <!-- This amazingness opens all links in a new tab. -->
{%- if not embedded %}
{{ script() }}
{%- if use_opensearch %}
<link rel="search" type="application/opensearchdescription+xml"
title="{% trans docstitle=docstitle|e %}Search within {{ docstitle }}{% endtrans %}"
href="{{ pathto('_static/opensearch.xml', 1) }}"/>
{%- endif %}
{%- if favicon %}
<link rel="shortcut icon" href="{{ pathto('_static/' + favicon, 1) }}"/>
{%- endif %}
{%- endif %}
{%- block linktags %}
{%- if hasdoc('about') %}
<link rel="author" title="{{ _('About these documents') }}" href="{{ pathto('about') }}" />
{%- endif %}
{%- if hasdoc('genindex') %}
<link rel="index" title="{{ _('Index') }}" href="{{ pathto('genindex') }}" />
{%- endif %}
{%- if hasdoc('search') %}
<link rel="search" title="{{ _('Search') }}" href="{{ pathto('search') }}" />
{%- endif %}
{%- if hasdoc('copyright') %}
<link rel="copyright" title="{{ _('Copyright') }}" href="{{ pathto('copyright') }}" />
{%- endif %}
<link rel="top" title="{{ docstitle|e }}" href="{{ pathto('index') }}" />
{%- if parents %}
<link rel="up" title="{{ parents[-1].title|striptags|e }}" href="{{ parents[-1].link|e }}" />
{%- endif %}
{%- if next %}
<link rel="next" title="{{ next.title|striptags|e }}" href="{{ next.link|e }}" />
{%- endif %}
{%- if prev %}
<link rel="prev" title="{{ prev.title|striptags|e }}" href="{{ prev.link|e }}" />
{%- endif %}
{%- endblock %}
{%- block extrahead %}
<link href="https://fonts.googleapis.com/css?family=Lato&display=swap" rel="stylesheet">
<link href='https://fonts.googleapis.com/css?family=Work+Sans&display=swap' rel='stylesheet'>
{% endblock %}
</head>
<body style="opacity: 0">
<slides class="layout-widescreen" id="slides">
<!-- {% include "title_slide.html" %} -->
{% block body %}{% endblock %}
{% include "end_slide.html" %}
<slide class="backdrop"></slide>
</slides>
<script type="text/javascript">
//insert info buttons on slides that have additional notes
$(".admonition.note").before("<button id='extra-notes'>&#9432;</button>");
$(".admonition-title").before("<button id='close-notes'>&times;</button>");
$(document).ready(function() {
$('button').click(function() {
document.body.classList.toggle('with-notes');
});
});
</script>
<script type="text/javascript">
//assigns font-size when document is ready
document.onreadystatechange = () => {
if (document.readyState === 'complete') {
var wrapperHeight = document.getElementById('slides').clientHeight;
var relativeFontSize = wrapperHeight / 45 + 'px'; //change integer to set desired font size
document.getElementById("slides").style.fontSize = relativeFontSize;
}
};
//then on window resize
window.onresize = function(event) {
var wrapperHeight = document.getElementById('slides').clientHeight;
var relativeFontSize = wrapperHeight / 45 + 'px'; //change integer to set for desired font size
document.getElementById("slides").style.fontSize = relativeFontSize;
};
</script>
</body>
</html>

View File

@@ -0,0 +1,19 @@
<slide class="{% if slide_number==1 %}title-slide segue nobackground {% endif %} {% if slide_classes %}{{ ' '.join(slide_classes) }} {% endif %}level-{{ level }}"{% if id %} id="{{ id }}"{% endif %}>
<hgroup>
<h{{ level }}>{{ title }}</h{{ level }}>
</hgroup>
<article class="{{ content_classes|join(' ') }}">
{{ content }}
{% if config.slide_numbers %}
<div class="slide-no">{{ slide_number }}</div>
{% endif %}
{% if config.slide_footer %}
<div class="slide-footer">{{ config.slide_footer }}</div>
{% endif %}
</article>
</slide>

View File

@@ -0,0 +1,24 @@
# Require any additional compass plugins here.
# Set this to the root of your project when deployed:
http_path = "/"
css_dir = "theme/css"
sass_dir = "theme/scss"
images_dir = "images"
javascripts_dir = "js"
# You can select your preferred output style here (can be overridden via the command line):
output_style = :expanded #:expanded or :nested or :compact or :compressed
# To enable relative paths to assets via compass helper functions. Uncomment:
# relative_assets = true
# To disable debugging comments that display the original location of your selectors. Uncomment:
# line_comments = false
# If you prefer the indented syntax, you might want to regenerate this
# project again passing --syntax sass, or you can uncomment this:
# preferred_syntax = :sass
# and then run:
# sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass

View File

@@ -0,0 +1,586 @@
/*
* Hammer.JS
* version 0.4
* author: Eight Media
* https://github.com/EightMedia/hammer.js
*/
function Hammer(element, options, undefined)
{
var self = this;
var defaults = {
// prevent the default event or not... might be buggy when false
prevent_default : false,
css_hacks : true,
drag : true,
drag_vertical : true,
drag_horizontal : true,
// minimum distance before the drag event starts
drag_min_distance : 20, // pixels
// pinch zoom and rotation
transform : true,
scale_treshold : 0.1,
rotation_treshold : 15, // degrees
tap : true,
tap_double : true,
tap_max_interval : 300,
tap_double_distance: 20,
hold : true,
hold_timeout : 500
};
options = mergeObject(defaults, options);
// some css hacks
(function() {
if(!options.css_hacks) {
return false;
}
var vendors = ['webkit','moz','ms','o',''];
var css_props = {
"userSelect": "none",
"touchCallout": "none",
"userDrag": "none",
"tapHighlightColor": "rgba(0,0,0,0)"
};
var prop = '';
for(var i = 0; i < vendors.length; i++) {
for(var p in css_props) {
prop = p;
if(vendors[i]) {
prop = vendors[i] + prop.substring(0, 1).toUpperCase() + prop.substring(1);
}
element.style[ prop ] = css_props[p];
}
}
})();
// holds the distance that has been moved
var _distance = 0;
// holds the exact angle that has been moved
var _angle = 0;
// holds the diraction that has been moved
var _direction = 0;
// holds position movement for sliding
var _pos = { };
// how many fingers are on the screen
var _fingers = 0;
var _first = false;
var _gesture = null;
var _prev_gesture = null;
var _touch_start_time = null;
var _prev_tap_pos = {x: 0, y: 0};
var _prev_tap_end_time = null;
var _hold_timer = null;
var _offset = {};
// keep track of the mouse status
var _mousedown = false;
var _event_start;
var _event_move;
var _event_end;
/**
* angle to direction define
* @param float angle
* @return string direction
*/
this.getDirectionFromAngle = function( angle )
{
var directions = {
down: angle >= 45 && angle < 135, //90
left: angle >= 135 || angle <= -135, //180
up: angle < -45 && angle > -135, //270
right: angle >= -45 && angle <= 45 //0
};
var direction, key;
for(key in directions){
if(directions[key]){
direction = key;
break;
}
}
return direction;
};
/**
* count the number of fingers in the event
* when no fingers are detected, one finger is returned (mouse pointer)
* @param event
* @return int fingers
*/
function countFingers( event )
{
// there is a bug on android (until v4?) that touches is always 1,
// so no multitouch is supported, e.g. no, zoom and rotation...
return event.touches ? event.touches.length : 1;
}
/**
* get the x and y positions from the event object
* @param event
* @return array [{ x: int, y: int }]
*/
function getXYfromEvent( event )
{
event = event || window.event;
// no touches, use the event pageX and pageY
if(!event.touches) {
var doc = document,
body = doc.body;
return [{
x: event.pageX || event.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && doc.clientLeft || 0 ),
y: event.pageY || event.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && doc.clientTop || 0 )
}];
}
// multitouch, return array with positions
else {
var pos = [], src;
for(var t=0, len=event.touches.length; t<len; t++) {
src = event.touches[t];
pos.push({ x: src.pageX, y: src.pageY });
}
return pos;
}
}
/**
* calculate the angle between two points
* @param object pos1 { x: int, y: int }
* @param object pos2 { x: int, y: int }
*/
function getAngle( pos1, pos2 )
{
return Math.atan2(pos2.y - pos1.y, pos2.x - pos1.x) * 180 / Math.PI;
}
/**
* trigger an event/callback by name with params
* @param string name
* @param array params
*/
function triggerEvent( eventName, params )
{
// return touches object
params.touches = getXYfromEvent(params.originalEvent);
params.type = eventName;
// trigger callback
if(isFunction(self["on"+ eventName])) {
self["on"+ eventName].call(self, params);
}
}
/**
* cancel event
* @param object event
* @return void
*/
function cancelEvent(event){
event = event || window.event;
if(event.preventDefault){
event.preventDefault();
}else{
event.returnValue = false;
event.cancelBubble = true;
}
}
/**
* reset the internal vars to the start values
*/
function reset()
{
_pos = {};
_first = false;
_fingers = 0;
_distance = 0;
_angle = 0;
_gesture = null;
}
var gestures = {
// hold gesture
// fired on touchstart
hold : function(event)
{
// only when one finger is on the screen
if(options.hold) {
_gesture = 'hold';
clearTimeout(_hold_timer);
_hold_timer = setTimeout(function() {
if(_gesture == 'hold') {
triggerEvent("hold", {
originalEvent : event,
position : _pos.start
});
}
}, options.hold_timeout);
}
},
// drag gesture
// fired on mousemove
drag : function(event)
{
// get the distance we moved
var _distance_x = _pos.move[0].x - _pos.start[0].x;
var _distance_y = _pos.move[0].y - _pos.start[0].y;
_distance = Math.sqrt(_distance_x * _distance_x + _distance_y * _distance_y);
// drag
// minimal movement required
if(options.drag && (_distance > options.drag_min_distance) || _gesture == 'drag') {
// calculate the angle
_angle = getAngle(_pos.start[0], _pos.move[0]);
_direction = self.getDirectionFromAngle(_angle);
// check the movement and stop if we go in the wrong direction
var is_vertical = (_direction == 'up' || _direction == 'down');
if(((is_vertical && !options.drag_vertical) || (!is_vertical && !options.drag_horizontal))
&& (_distance > options.drag_min_distance)) {
return;
}
_gesture = 'drag';
var position = { x: _pos.move[0].x - _offset.left,
y: _pos.move[0].y - _offset.top };
var event_obj = {
originalEvent : event,
position : position,
direction : _direction,
distance : _distance,
distanceX : _distance_x,
distanceY : _distance_y,
angle : _angle
};
// on the first time trigger the start event
if(_first) {
triggerEvent("dragstart", event_obj);
_first = false;
}
// normal slide event
triggerEvent("drag", event_obj);
cancelEvent(event);
}
},
// transform gesture
// fired on touchmove
transform : function(event)
{
if(options.transform) {
var scale = event.scale || 1;
var rotation = event.rotation || 0;
if(countFingers(event) != 2) {
return false;
}
if(_gesture != 'drag' &&
(_gesture == 'transform' || Math.abs(1-scale) > options.scale_treshold
|| Math.abs(rotation) > options.rotation_treshold)) {
_gesture = 'transform';
_pos.center = { x: ((_pos.move[0].x + _pos.move[1].x) / 2) - _offset.left,
y: ((_pos.move[0].y + _pos.move[1].y) / 2) - _offset.top };
var event_obj = {
originalEvent : event,
position : _pos.center,
scale : scale,
rotation : rotation
};
// on the first time trigger the start event
if(_first) {
triggerEvent("transformstart", event_obj);
_first = false;
}
triggerEvent("transform", event_obj);
cancelEvent(event);
return true;
}
}
return false;
},
// tap and double tap gesture
// fired on touchend
tap : function(event)
{
// compare the kind of gesture by time
var now = new Date().getTime();
var touch_time = now - _touch_start_time;
// dont fire when hold is fired
if(options.hold && !(options.hold && options.hold_timeout > touch_time)) {
return;
}
// when previous event was tap and the tap was max_interval ms ago
var is_double_tap = (function(){
if (_prev_tap_pos && options.tap_double && _prev_gesture == 'tap' && (_touch_start_time - _prev_tap_end_time) < options.tap_max_interval) {
var x_distance = Math.abs(_prev_tap_pos[0].x - _pos.start[0].x);
var y_distance = Math.abs(_prev_tap_pos[0].y - _pos.start[0].y);
return (_prev_tap_pos && _pos.start && Math.max(x_distance, y_distance) < options.tap_double_distance);
}
return false;
})();
if(is_double_tap) {
_gesture = 'double_tap';
_prev_tap_end_time = null;
triggerEvent("doubletap", {
originalEvent : event,
position : _pos.start
});
cancelEvent(event);
}
// single tap is single touch
else {
_gesture = 'tap';
_prev_tap_end_time = now;
_prev_tap_pos = _pos.start;
if(options.tap) {
triggerEvent("tap", {
originalEvent : event,
position : _pos.start
});
cancelEvent(event);
}
}
}
};
function handleEvents(event)
{
switch(event.type)
{
case 'mousedown':
case 'touchstart':
_pos.start = getXYfromEvent(event);
_touch_start_time = new Date().getTime();
_fingers = countFingers(event);
_first = true;
_event_start = event;
// borrowed from jquery offset https://github.com/jquery/jquery/blob/master/src/offset.js
var box = element.getBoundingClientRect();
var clientTop = element.clientTop || document.body.clientTop || 0;
var clientLeft = element.clientLeft || document.body.clientLeft || 0;
var scrollTop = window.pageYOffset || element.scrollTop || document.body.scrollTop;
var scrollLeft = window.pageXOffset || element.scrollLeft || document.body.scrollLeft;
_offset = {
top: box.top + scrollTop - clientTop,
left: box.left + scrollLeft - clientLeft
};
_mousedown = true;
// hold gesture
gestures.hold(event);
if(options.prevent_default) {
cancelEvent(event);
}
break;
case 'mousemove':
case 'touchmove':
if(!_mousedown) {
return false;
}
_event_move = event;
_pos.move = getXYfromEvent(event);
if(!gestures.transform(event)) {
gestures.drag(event);
}
break;
case 'mouseup':
case 'mouseout':
case 'touchcancel':
case 'touchend':
if(!_mousedown || (_gesture != 'transform' && event.touches && event.touches.length > 0)) {
return false;
}
_mousedown = false;
_event_end = event;
// drag gesture
// dragstart is triggered, so dragend is possible
if(_gesture == 'drag') {
triggerEvent("dragend", {
originalEvent : event,
direction : _direction,
distance : _distance,
angle : _angle
});
}
// transform
// transformstart is triggered, so transformed is possible
else if(_gesture == 'transform') {
triggerEvent("transformend", {
originalEvent : event,
position : _pos.center,
scale : event.scale,
rotation : event.rotation
});
}
else {
gestures.tap(_event_start);
}
_prev_gesture = _gesture;
// reset vars
reset();
break;
}
}
// bind events for touch devices
// except for windows phone 7.5, it doesnt support touch events..!
if('ontouchstart' in window) {
element.addEventListener("touchstart", handleEvents, false);
element.addEventListener("touchmove", handleEvents, false);
element.addEventListener("touchend", handleEvents, false);
element.addEventListener("touchcancel", handleEvents, false);
}
// for non-touch
else {
if(element.addEventListener){ // prevent old IE errors
element.addEventListener("mouseout", function(event) {
if(!isInsideHammer(element, event.relatedTarget)) {
handleEvents(event);
}
}, false);
element.addEventListener("mouseup", handleEvents, false);
element.addEventListener("mousedown", handleEvents, false);
element.addEventListener("mousemove", handleEvents, false);
// events for older IE
}else if(document.attachEvent){
element.attachEvent("onmouseout", function(event) {
if(!isInsideHammer(element, event.relatedTarget)) {
handleEvents(event);
}
}, false);
element.attachEvent("onmouseup", handleEvents);
element.attachEvent("onmousedown", handleEvents);
element.attachEvent("onmousemove", handleEvents);
}
}
/**
* find if element is (inside) given parent element
* @param object element
* @param object parent
* @return bool inside
*/
function isInsideHammer(parent, child) {
// get related target for IE
if(!child && window.event && window.event.toElement){
child = window.event.toElement;
}
if(parent === child){
return true;
}
// loop over parentNodes of child until we find hammer element
if(child){
var node = child.parentNode;
while(node !== null){
if(node === parent){
return true;
};
node = node.parentNode;
}
}
return false;
}
/**
* merge 2 objects into a new object
* @param object obj1
* @param object obj2
* @return object merged object
*/
function mergeObject(obj1, obj2) {
var output = {};
if(!obj2) {
return obj1;
}
for (var prop in obj1) {
if (prop in obj2) {
output[prop] = obj2[prop];
} else {
output[prop] = obj1[prop];
}
}
return output;
}
function isFunction( obj ){
return Object.prototype.toString.call( obj ) == "[object Function]";
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,8 @@
/*
RequireJS order 1.0.5 Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
Available via the MIT or new BSD license.
see: http://github.com/jrburke/requirejs for details
*/
(function(){function k(a){var b=a.currentTarget||a.srcElement,c;if(a.type==="load"||l.test(b.readyState)){a=b.getAttribute("data-requiremodule");j[a]=!0;for(a=0;c=g[a];a++)if(j[c.name])c.req([c.name],c.onLoad);else break;a>0&&g.splice(0,a);setTimeout(function(){b.parentNode.removeChild(b)},15)}}function m(a){var b,c;a.setAttribute("data-orderloaded","loaded");for(a=0;c=h[a];a++)if((b=i[c])&&b.getAttribute("data-orderloaded")==="loaded")delete i[c],require.addScriptToDom(b);else break;a>0&&h.splice(0,
a)}var f=typeof document!=="undefined"&&typeof window!=="undefined"&&document.createElement("script"),n=f&&(f.async||window.opera&&Object.prototype.toString.call(window.opera)==="[object Opera]"||"MozAppearance"in document.documentElement.style),o=f&&f.readyState==="uninitialized",l=/^(complete|loaded)$/,g=[],j={},i={},h=[],f=null;define({version:"1.0.5",load:function(a,b,c,e){var d;b.nameToUrl?(d=b.nameToUrl(a,null),require.s.skipAsync[d]=!0,n||e.isBuild?b([a],c):o?(e=require.s.contexts._,!e.urlFetched[d]&&
!e.loaded[a]&&(e.urlFetched[d]=!0,require.resourcesReady(!1),e.scriptCount+=1,d=require.attach(d,e,a,null,null,m),i[a]=d,h.push(a)),b([a],c)):b.specified(a)?b([a],c):(g.push({name:a,req:b,onLoad:c}),require.attach(d,null,a,k,"script/cache"))):b([a],c)}})})();

View File

@@ -0,0 +1,2 @@
/* @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js*/
"use strict";if(typeof document!=="undefined"&&!("classList" in document.createElement("a"))){(function(a){var f="classList",d="prototype",e=(a.HTMLElement||a.Element)[d],g=Object;strTrim=String[d].trim||function(){return this.replace(/^\s+|\s+$/g,"")},arrIndexOf=Array[d].indexOf||function(k){for(var j=0,h=this.length;j<h;j++){if(j in this&&this[j]===k){return j}}return -1},DOMEx=function(h,i){this.name=h;this.code=DOMException[h];this.message=i},checkTokenAndGetIndex=function(i,h){if(h===""){throw new DOMEx("SYNTAX_ERR","An invalid or illegal string was specified")}if(/\s/.test(h)){throw new DOMEx("INVALID_CHARACTER_ERR","String contains an invalid character")}return arrIndexOf.call(i,h)},ClassList=function(m){var l=strTrim.call(m.className),k=l?l.split(/\s+/):[];for(var j=0,h=k.length;j<h;j++){this.push(k[j])}this._updateClassName=function(){m.className=this.toString()}},classListProto=ClassList[d]=[],classListGetter=function(){return new ClassList(this)};DOMEx[d]=Error[d];classListProto.item=function(h){return this[h]||null};classListProto.contains=function(h){h+="";return checkTokenAndGetIndex(this,h)!==-1};classListProto.add=function(h){h+="";if(checkTokenAndGetIndex(this,h)===-1){this.push(h);this._updateClassName()}};classListProto.remove=function(i){i+="";var h=checkTokenAndGetIndex(this,i);if(h!==-1){this.splice(h,1);this._updateClassName()}};classListProto.toggle=function(h){h+="";if(checkTokenAndGetIndex(this,h)===-1){this.add(h)}else{this.remove(h)}};classListProto.toString=function(){return this.join(" ")};if(g.defineProperty){var c={get:classListGetter,enumerable:true,configurable:true};try{g.defineProperty(e,f,c)}catch(b){if(b.number===-2146823252){c.enumerable=false;g.defineProperty(e,f,c)}}}else{if(g[d].__defineGetter__){e.__defineGetter__(f,classListGetter)}}}(self))};

View File

@@ -0,0 +1,2 @@
(function(){function c(){d=!0;this.removeEventListener("DOMAttrModified",c,!1)}function g(b){return b.replace(h,function(b,a){return a.toUpperCase()})}function e(){var b={};i.call(this.attributes,function(a){if(f=a.name.match(j))b[g(f[1])]=a.value});return b}var i=[].forEach,j=/^data-(.+)/,h=/\-([a-z])/ig,a=document.createElement("div"),d=!1,f;a.dataset==void 0&&(a.addEventListener("DOMAttrModified",c,!1),a.setAttribute("foo","bar"),Element.prototype.__defineGetter__("dataset",d?function(){if(!this._datasetCache)this._datasetCache=
e.call(this);return this._datasetCache}:e),document.addEventListener("DOMAttrModified",function(a){delete a.target._datasetCache},!1))})();

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
PR.registerLangHandler(PR.createSimpleLexer([["com",/^#[^\n\r]*/,null,"#"],["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r <20>\xa0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,null,'"']],[["kwd",/^(?:ADS|AD|AUG|BZF|BZMF|CAE|CAF|CA|CCS|COM|CS|DAS|DCA|DCOM|DCS|DDOUBL|DIM|DOUBLE|DTCB|DTCF|DV|DXCH|EDRUPT|EXTEND|INCR|INDEX|NDX|INHINT|LXCH|MASK|MSK|MP|MSU|NOOP|OVSK|QXCH|RAND|READ|RELINT|RESUME|RETURN|ROR|RXOR|SQUARE|SU|TCR|TCAA|OVSK|TCF|TC|TS|WAND|WOR|WRITE|XCH|XLQ|XXALQ|ZL|ZQ|ADD|ADZ|SUB|SUZ|MPY|MPR|MPZ|DVP|COM|ABS|CLA|CLZ|LDQ|STO|STQ|ALS|LLS|LRS|TRA|TSQ|TMI|TOV|AXT|TIX|DLY|INP|OUT)\s/,
null],["typ",/^(?:-?GENADR|=MINUS|2BCADR|VN|BOF|MM|-?2CADR|-?[1-6]DNADR|ADRES|BBCON|[ES]?BANK=?|BLOCK|BNKSUM|E?CADR|COUNT\*?|2?DEC\*?|-?DNCHAN|-?DNPTR|EQUALS|ERASE|MEMORY|2?OCT|REMADR|SETLOC|SUBRO|ORG|BSS|BES|SYN|EQU|DEFINE|END)\s/,null],["lit",/^'(?:-*(?:\w|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?)?/],["pln",/^-*(?:[!-z]|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?/],["pun",/^[^\w\t\n\r "'-);\\\xa0]+/]]),["apollo","agc","aea"]);

View File

@@ -0,0 +1,18 @@
/*
Copyright (C) 2011 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
var a=null;
PR.registerLangHandler(PR.createSimpleLexer([["opn",/^[([{]+/,a,"([{"],["clo",/^[)\]}]+/,a,")]}"],["com",/^;[^\n\r]*/,a,";"],["pln",/^[\t\n\r \xa0]+/,a,"\t\n\r \xa0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,a,'"']],[["kwd",/^(?:def|if|do|let|quote|var|fn|loop|recur|throw|try|monitor-enter|monitor-exit|defmacro|defn|defn-|macroexpand|macroexpand-1|for|doseq|dosync|dotimes|and|or|when|not|assert|doto|proxy|defstruct|first|rest|cons|defprotocol|deftype|defrecord|reify|defmulti|defmethod|meta|with-meta|ns|in-ns|create-ns|import|intern|refer|alias|namespace|resolve|ref|deref|refset|new|set!|memfn|to-array|into-array|aset|gen-class|reduce|map|filter|find|nil?|empty?|hash-map|hash-set|vec|vector|seq|flatten|reverse|assoc|dissoc|list|list?|disj|get|union|difference|intersection|extend|extend-type|extend-protocol|prn)\b/,a],
["typ",/^:[\dA-Za-z-]+/]]),["clj"]);

View File

@@ -0,0 +1,2 @@
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com",
/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]);

View File

@@ -0,0 +1 @@
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r <20>\xa0"],["pln",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])+(?:'|$)|`[^`]*(?:`|$))/,null,"\"'"]],[["com",/^(?:\/\/[^\n\r]*|\/\*[\S\s]*?\*\/)/],["pln",/^(?:[^"'/`]|\/(?![*/]))+/]]),["go"]);

View File

@@ -0,0 +1,2 @@
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t-\r ]+/,null,"\t\n \r "],["str",/^"(?:[^\n\f\r"\\]|\\[\S\s])*(?:"|$)/,null,'"'],["str",/^'(?:[^\n\f\r'\\]|\\[^&])'?/,null,"'"],["lit",/^(?:0o[0-7]+|0x[\da-f]+|\d+(?:\.\d+)?(?:e[+-]?\d+)?)/i,null,"0123456789"]],[["com",/^(?:--+[^\n\f\r]*|{-(?:[^-]|-+[^}-])*-})/],["kwd",/^(?:case|class|data|default|deriving|do|else|if|import|in|infix|infixl|infixr|instance|let|module|newtype|of|then|type|where|_)(?=[^\d'A-Za-z]|$)/,
null],["pln",/^(?:[A-Z][\w']*\.)*[A-Za-z][\w']*/],["pun",/^[^\d\t-\r "'A-Za-z]+/]]),["hs"]);

View File

@@ -0,0 +1,3 @@
var a=null;
PR.registerLangHandler(PR.createSimpleLexer([["opn",/^\(+/,a,"("],["clo",/^\)+/,a,")"],["com",/^;[^\n\r]*/,a,";"],["pln",/^[\t\n\r \xa0]+/,a,"\t\n\r \xa0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,a,'"']],[["kwd",/^(?:block|c[ad]+r|catch|con[ds]|def(?:ine|un)|do|eq|eql|equal|equalp|eval-when|flet|format|go|if|labels|lambda|let|load-time-value|locally|macrolet|multiple-value-call|nil|progn|progv|quote|require|return-from|setq|symbol-macrolet|t|tagbody|the|throw|unwind)\b/,a],
["lit",/^[+-]?(?:[#0]x[\da-f]+|\d+\/\d+|(?:\.\d+|\d+(?:\.\d*)?)(?:[de][+-]?\d+)?)/i],["lit",/^'(?:-*(?:\w|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?)?/],["pln",/^-*(?:[_a-z]|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?/i],["pun",/^[^\w\t\n\r "'-);\\\xa0]+/]]),["cl","el","lisp","scm"]);

View File

@@ -0,0 +1,2 @@
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r <20>\xa0"],["str",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$))/,null,"\"'"]],[["com",/^--(?:\[(=*)\[[\S\s]*?(?:]\1]|$)|[^\n\r]*)/],["str",/^\[(=*)\[[\S\s]*?(?:]\1]|$)/],["kwd",/^(?:and|break|do|else|elseif|end|false|for|function|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,null],["lit",/^[+-]?(?:0x[\da-f]+|(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?)/i],
["pln",/^[_a-z]\w*/i],["pun",/^[^\w\t\n\r \xa0][^\w\t\n\r "'+=\xa0-]*/]]),["lua"]);

View File

@@ -0,0 +1,2 @@
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r <20>\xa0"],["com",/^#(?:if[\t\n\r \xa0]+(?:[$_a-z][\w']*|``[^\t\n\r`]*(?:``|$))|else|endif|light)/i,null,"#"],["str",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])(?:'|$))/,null,"\"'"]],[["com",/^(?:\/\/[^\n\r]*|\(\*[\S\s]*?\*\))/],["kwd",/^(?:abstract|and|as|assert|begin|class|default|delegate|do|done|downcast|downto|elif|else|end|exception|extern|false|finally|for|fun|function|if|in|inherit|inline|interface|internal|lazy|let|match|member|module|mutable|namespace|new|null|of|open|or|override|private|public|rec|return|static|struct|then|to|true|try|type|upcast|use|val|void|when|while|with|yield|asr|land|lor|lsl|lsr|lxor|mod|sig|atomic|break|checked|component|const|constraint|constructor|continue|eager|event|external|fixed|functor|global|include|method|mixin|object|parallel|process|protected|pure|sealed|trait|virtual|volatile)\b/],
["lit",/^[+-]?(?:0x[\da-f]+|(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?)/i],["pln",/^(?:[_a-z][\w']*[!#?]?|``[^\t\n\r`]*(?:``|$))/i],["pun",/^[^\w\t\n\r "'\xa0]+/]]),["fs","ml"]);

View File

@@ -0,0 +1,4 @@
var a=null;
PR.registerLangHandler(PR.createSimpleLexer([["str",/^(?:'(?:[^\n\r'\\]|\\.)*'|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,a,'"'],["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,a,"#"],["pln",/^\s+/,a," \r\n\t\xa0"]],[["str",/^@"(?:[^"]|"")*(?:"|$)/,a],["str",/^<#[^#>]*(?:#>|$)/,a],["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,a],["com",/^\/\/[^\n\r]*/,a],["com",/^\/\*[\S\s]*?(?:\*\/|$)/,
a],["kwd",/^(?:abstract|and|as|base|catch|class|def|delegate|enum|event|extern|false|finally|fun|implements|interface|internal|is|macro|match|matches|module|mutable|namespace|new|null|out|override|params|partial|private|protected|public|ref|sealed|static|struct|syntax|this|throw|true|try|type|typeof|using|variant|virtual|volatile|when|where|with|assert|assert2|async|break|checked|continue|do|else|ensures|for|foreach|if|late|lock|new|nolate|otherwise|regexp|repeat|requires|return|surroundwith|unchecked|unless|using|while|yield)\b/,
a],["typ",/^(?:array|bool|byte|char|decimal|double|float|int|list|long|object|sbyte|short|string|ulong|uint|ufloat|ulong|ushort|void)\b/,a],["lit",/^@[$_a-z][\w$@]*/i,a],["typ",/^@[A-Z]+[a-z][\w$@]*/,a],["pln",/^'?[$_a-z][\w$@]*/i,a],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,a,"0123456789"],["pun",/^.[^\s\w"-$'./@`]*/,a]]),["n","nemerle"]);

View File

@@ -0,0 +1 @@
PR.registerLangHandler(PR.sourceDecorator({keywords:"bytes,default,double,enum,extend,extensions,false,group,import,max,message,option,optional,package,repeated,required,returns,rpc,service,syntax,to,true",types:/^(bool|(double|s?fixed|[su]?int)(32|64)|float|string)\b/,cStyleComments:!0}),["proto"]);

View File

@@ -0,0 +1,2 @@
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r <20>\xa0"],["str",/^"(?:""(?:""?(?!")|[^"\\]|\\.)*"{0,3}|(?:[^\n\r"\\]|\\.)*"?)/,null,'"'],["lit",/^`(?:[^\n\r\\`]|\\.)*`?/,null,"`"],["pun",/^[!#%&(--:-@[-^{-~]+/,null,"!#%&()*+,-:;<=>?@[\\]^{|}~"]],[["str",/^'(?:[^\n\r'\\]|\\(?:'|[^\n\r']+))'/],["lit",/^'[$A-Z_a-z][\w$]*(?![\w$'])/],["kwd",/^(?:abstract|case|catch|class|def|do|else|extends|final|finally|for|forSome|if|implicit|import|lazy|match|new|object|override|package|private|protected|requires|return|sealed|super|throw|trait|try|type|val|var|while|with|yield)\b/],
["lit",/^(?:true|false|null|this)\b/],["lit",/^(?:0(?:[0-7]+|x[\da-f]+)l?|(?:0|[1-9]\d*)(?:(?:\.\d+)?(?:e[+-]?\d+)?f?|l?)|\\.\d+(?:e[+-]?\d+)?f?)/i],["typ",/^[$_]*[A-Z][\d$A-Z_]*[a-z][\w$]*/],["pln",/^[$A-Z_a-z][\w$]*/],["com",/^\/(?:\/.*|\*(?:\/|\**[^*/])*(?:\*+\/?)?)/],["pun",/^(?:\.+|\/)/]]),["scala"]);

View File

@@ -0,0 +1,2 @@
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r <20>\xa0"],["str",/^(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/,null,"\"'"]],[["com",/^(?:--[^\n\r]*|\/\*[\S\s]*?(?:\*\/|$))/],["kwd",/^(?:add|all|alter|and|any|as|asc|authorization|backup|begin|between|break|browse|bulk|by|cascade|case|check|checkpoint|close|clustered|coalesce|collate|column|commit|compute|constraint|contains|containstable|continue|convert|create|cross|current|current_date|current_time|current_timestamp|current_user|cursor|database|dbcc|deallocate|declare|default|delete|deny|desc|disk|distinct|distributed|double|drop|dummy|dump|else|end|errlvl|escape|except|exec|execute|exists|exit|fetch|file|fillfactor|for|foreign|freetext|freetexttable|from|full|function|goto|grant|group|having|holdlock|identity|identitycol|identity_insert|if|in|index|inner|insert|intersect|into|is|join|key|kill|left|like|lineno|load|match|merge|national|nocheck|nonclustered|not|null|nullif|of|off|offsets|on|open|opendatasource|openquery|openrowset|openxml|option|or|order|outer|over|percent|plan|precision|primary|print|proc|procedure|public|raiserror|read|readtext|reconfigure|references|replication|restore|restrict|return|revoke|right|rollback|rowcount|rowguidcol|rule|save|schema|select|session_user|set|setuser|shutdown|some|statistics|system_user|table|textsize|then|to|top|tran|transaction|trigger|truncate|tsequal|union|unique|update|updatetext|use|user|using|values|varying|view|waitfor|when|where|while|with|writetext)(?=[^\w-]|$)/i,
null],["lit",/^[+-]?(?:0x[\da-f]+|(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?)/i],["pln",/^[_a-z][\w-]*/i],["pun",/^[^\w\t\n\r "'\xa0][^\w\t\n\r "'+\xa0-]*/]]),["sql"]);

View File

@@ -0,0 +1 @@
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r <20>\xa0"],["com",/^%[^\n\r]*/,null,"%"]],[["kwd",/^\\[@-Za-z]+/],["kwd",/^\\./],["typ",/^[$&]/],["lit",/[+-]?(?:\.\d+|\d+(?:\.\d*)?)(cm|em|ex|in|pc|pt|bp|mm)/i],["pun",/^[()=[\]{}]+/]]),["latex","tex"]);

View File

@@ -0,0 +1,2 @@
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0\u2028\u2029]+/,null,"\t\n\r <20>\xa0"],["str",/^(?:["\u201c\u201d](?:[^"\u201c\u201d]|["\u201c\u201d]{2})(?:["\u201c\u201d]c|$)|["\u201c\u201d](?:[^"\u201c\u201d]|["\u201c\u201d]{2})*(?:["\u201c\u201d]|$))/i,null,'"“”'],["com",/^['\u2018\u2019].*/,null,"'"]],[["kwd",/^(?:addhandler|addressof|alias|and|andalso|ansi|as|assembly|auto|boolean|byref|byte|byval|call|case|catch|cbool|cbyte|cchar|cdate|cdbl|cdec|char|cint|class|clng|cobj|const|cshort|csng|cstr|ctype|date|decimal|declare|default|delegate|dim|directcast|do|double|each|else|elseif|end|endif|enum|erase|error|event|exit|finally|for|friend|function|get|gettype|gosub|goto|handles|if|implements|imports|in|inherits|integer|interface|is|let|lib|like|long|loop|me|mod|module|mustinherit|mustoverride|mybase|myclass|namespace|new|next|not|notinheritable|notoverridable|object|on|option|optional|or|orelse|overloads|overridable|overrides|paramarray|preserve|private|property|protected|public|raiseevent|readonly|redim|removehandler|resume|return|select|set|shadows|shared|short|single|static|step|stop|string|structure|sub|synclock|then|throw|to|try|typeof|unicode|until|variant|wend|when|while|with|withevents|writeonly|xor|endif|gosub|let|variant|wend)\b/i,
null],["com",/^rem.*/i],["lit",/^(?:true\b|false\b|nothing\b|\d+(?:e[+-]?\d+[dfr]?|[dfilrs])?|(?:&h[\da-f]+|&o[0-7]+)[ils]?|\d*\.\d+(?:e[+-]?\d+)?[dfr]?|#\s+(?:\d+[/-]\d+[/-]\d+(?:\s+\d+:\d+(?::\d+)?(\s*(?:am|pm))?)?|\d+:\d+(?::\d+)?(\s*(?:am|pm))?)\s+#)/i],["pln",/^(?:(?:[a-z]|_\w)\w*|\[(?:[a-z]|_\w)\w*])/i],["pun",/^[^\w\t\n\r "'[\]\xa0\u2018\u2019\u201c\u201d\u2028\u2029]+/],["pun",/^(?:\[|])/]]),["vb","vbs"]);

View File

@@ -0,0 +1,3 @@
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r <20>\xa0"]],[["str",/^(?:[box]?"(?:[^"]|"")*"|'.')/i],["com",/^--[^\n\r]*/],["kwd",/^(?:abs|access|after|alias|all|and|architecture|array|assert|attribute|begin|block|body|buffer|bus|case|component|configuration|constant|disconnect|downto|else|elsif|end|entity|exit|file|for|function|generate|generic|group|guarded|if|impure|in|inertial|inout|is|label|library|linkage|literal|loop|map|mod|nand|new|next|nor|not|null|of|on|open|or|others|out|package|port|postponed|procedure|process|pure|range|record|register|reject|rem|report|return|rol|ror|select|severity|shared|signal|sla|sll|sra|srl|subtype|then|to|transport|type|unaffected|units|until|use|variable|wait|when|while|with|xnor|xor)(?=[^\w-]|$)/i,
null],["typ",/^(?:bit|bit_vector|character|boolean|integer|real|time|string|severity_level|positive|natural|signed|unsigned|line|text|std_u?logic(?:_vector)?)(?=[^\w-]|$)/i,null],["typ",/^'(?:active|ascending|base|delayed|driving|driving_value|event|high|image|instance_name|last_active|last_event|last_value|left|leftof|length|low|path_name|pos|pred|quiet|range|reverse_range|right|rightof|simple_name|stable|succ|transaction|val|value)(?=[^\w-]|$)/i,null],["lit",/^\d+(?:_\d+)*(?:#[\w.\\]+#(?:[+-]?\d+(?:_\d+)*)?|(?:\.\d+(?:_\d+)*)?(?:e[+-]?\d+(?:_\d+)*)?)/i],
["pln",/^(?:[a-z]\w*|\\[^\\]*\\)/i],["pun",/^[^\w\t\n\r "'\xa0][^\w\t\n\r "'\xa0-]*/]]),["vhdl","vhd"]);

View File

@@ -0,0 +1,2 @@
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\d\t a-gi-z\xa0]+/,null,"\t <20>\xa0abcdefgijklmnopqrstuvwxyz0123456789"],["pun",/^[*=[\]^~]+/,null,"=*~^[]"]],[["lang-wiki.meta",/(?:^^|\r\n?|\n)(#[a-z]+)\b/],["lit",/^[A-Z][a-z][\da-z]+[A-Z][a-z][^\W_]+\b/],["lang-",/^{{{([\S\s]+?)}}}/],["lang-",/^`([^\n\r`]+)`/],["str",/^https?:\/\/[^\s#/?]*(?:\/[^\s#?]*)?(?:\?[^\s#]*)?(?:#\S*)?/i],["pln",/^(?:\r\n|[\S\s])[^\n\r#*=A-[^`h{~]*/]]),["wiki"]);
PR.registerLangHandler(PR.createSimpleLexer([["kwd",/^#[a-z]+/i,null,"#"]],[]),["wiki.meta"]);

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
var a=null;
PR.registerLangHandler(PR.createSimpleLexer([["pun",/^[:>?|]+/,a,":|>?"],["dec",/^%(?:YAML|TAG)[^\n\r#]+/,a,"%"],["typ",/^&\S+/,a,"&"],["typ",/^!\S*/,a,"!"],["str",/^"(?:[^"\\]|\\.)*(?:"|$)/,a,'"'],["str",/^'(?:[^']|'')*(?:'|$)/,a,"'"],["com",/^#[^\n\r]*/,a,"#"],["pln",/^\s+/,a," \t\r\n"]],[["dec",/^(?:---|\.\.\.)(?:[\n\r]|$)/],["pun",/^-/],["kwd",/^\w+:[\n\r ]/],["pln",/^\w+/]]),["yaml","yml"]);

View File

@@ -0,0 +1 @@
.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}

View File

@@ -0,0 +1,28 @@
var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c<i;++c){var j=f[c];if(/\\[bdsw]/i.test(j))a.push(j);else{var j=m(j),d;c+2<i&&"-"===f[c+1]?(d=m(f[c+2]),c+=2):d=j;b.push([j,d]);d<65||j>122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c<b.length;++c)i=b[c],i[0]<=j[1]+1?j[1]=Math.max(j[1],i[1]):f.push(j=i);b=["["];o&&b.push("^");b.push.apply(b,a);for(c=0;c<
f.length;++c)i=f[c],b.push(e(i[0])),i[1]>i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c<b;++c){var j=f[c];j==="("?++i:"\\"===j.charAt(0)&&(j=+j.substring(1))&&j<=i&&(d[j]=-1)}for(c=1;c<d.length;++c)-1===d[c]&&(d[c]=++t);for(i=c=0;c<b;++c)j=f[c],j==="("?(++i,d[i]===void 0&&(f[c]="(?:")):"\\"===j.charAt(0)&&
(j=+j.substring(1))&&j<=i&&(f[c]="\\"+d[i]);for(i=c=0;c<b;++c)"^"===f[c]&&"^"!==f[c+1]&&(f[c]="");if(a.ignoreCase&&s)for(c=0;c<b;++c)j=f[c],a=j.charAt(0),j.length>=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p<d;++p){var g=a[p];if(g.ignoreCase)l=!0;else if(/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){s=!0;l=!1;break}}for(var r=
{b:8,t:9,n:10,v:11,f:12,r:13},n=[],p=0,d=a.length;p<d;++p){g=a[p];if(g.global||g.multiline)throw Error(""+g);n.push("(?:"+y(g)+")")}return RegExp(n.join("|"),l?"gi":"g")}function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.className))break;for(var g=a.firstChild;g;g=g.nextSibling)m(g);g=a.nodeName;if("BR"===g||"LI"===g)h[s]="\n",t[s<<1]=y++,t[s++<<1|1]=a;break;case 3:case 4:g=a.nodeValue,g.length&&(g=p?g.replace(/\r\n?/g,"\n"):g.replace(/[\t\n\r ]+/g," "),h[s]=g,t[s<<1]=y,y+=g.length,
t[s++<<1|1]=a)}}var e=/(?:^|\s)nocode(?:\s|$)/,h=[],y=0,t=[],s=0,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=document.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);m(a);return{a:h.join("").replace(/\n$/,""),c:t}}function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(y)||[],r={},n=0,z=g.length;n<z;++n){var f=g[n],b=r[f],o=void 0,c;if(typeof b===
"string")c=!1;else{var i=h[f.charAt(0)];if(i)o=f.match(i[1]),b=i[0];else{for(c=0;c<t;++c)if(i=m[c],o=f.match(i[1])){b=i[0];break}o||(b="pln")}if((c=b.length>=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
l=[],p={},d=0,g=e.length;d<g;++d){var r=e[d],n=r[3];if(n)for(var k=n.length;--k>=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g<d.length;++g)e(d[g]);m===(m|0)&&d[0].setAttribute("value",
m);var r=s.createElement("OL");r.className="linenums";for(var n=Math.max(0,m-1|0)||0,g=0,z=d.length;g<z;++g)l=d[g],l.className="L"+(g+n)%10,l.firstChild||l.appendChild(s.createTextNode("\xa0")),r.appendChild(l);a.appendChild(r)}function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-markup":"default-code";return A[a]}function E(a){var m=
a.g;try{var e=M(a.h),h=e.a;a.a=h;a.c=e.c;a.d=0;C(m,h)(a);var k=/\bMSIE\b/.test(navigator.userAgent),m=/\n/g,t=a.a,s=t.length,e=0,l=a.c,p=l.length,h=0,d=a.e,g=d.length,a=0;d[g]=s;var r,n;for(n=r=0;n<g;)d[n]!==d[n+2]?(d[r++]=d[n++],d[r++]=d[n++]):n+=2;g=r;for(n=r=0;n<g;){for(var z=d[n],f=d[n+1],b=n+2;b+2<=g&&d[b+1]===f;)b+=2;d[r++]=z;d[r++]=f;n=b}for(d.length=r;h<p;){var o=l[h+2]||s,c=d[a+2]||s,b=Math.min(o,c),i=l[h+1],j;if(i.nodeType!==1&&(j=t.substring(e,b))){k&&(j=j.replace(m,"\r"));i.nodeValue=
j;var u=i.ownerDocument,v=u.createElement("SPAN");v.className=d[a+1];var x=i.parentNode;x.replaceChild(v,i);v.appendChild(i);e<o&&(l[h+1]=i=u.createTextNode(t.substring(b,o)),x.insertBefore(i,v.nextSibling))}e=b;e>=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),
["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",
/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),
["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes",
hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p<h.length&&l.now()<e;p++){var n=h[p],k=n.className;if(k.indexOf("prettyprint")>=0){var k=k.match(g),f,b;if(b=
!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p<h.length?setTimeout(m,
250):a&&a()}for(var e=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],h=[],k=0;k<e.length;++k)for(var t=0,s=e[k].length;t<s;++t)h.push(e[k][t]);var e=q,l=Date;l.now||(l={now:function(){return+new Date}});var p=0,d,g=/\blang(?:uage)?-([\w.]+)(?!\S)/;m()};window.PR={createSimpleLexer:x,registerLangHandler:k,sourceDecorator:u,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",
PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ"}})();

View File

@@ -0,0 +1,33 @@
/*
RequireJS 1.0.8 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
Available via the MIT or new BSD license.
see: http://github.com/jrburke/requirejs for details
*/
var requirejs,require,define;
(function(r){function K(a){return O.call(a)==="[object Function]"}function G(a){return O.call(a)==="[object Array]"}function $(a,c,l){for(var j in c)if(!(j in L)&&(!(j in a)||l))a[j]=c[j];return d}function P(a,c,d){a=Error(c+"\nhttp://requirejs.org/docs/errors.html#"+a);if(d)a.originalError=d;return a}function aa(a,c,d){var j,k,t;for(j=0;t=c[j];j++){t=typeof t==="string"?{name:t}:t;k=t.location;if(d&&(!k||k.indexOf("/")!==0&&k.indexOf(":")===-1))k=d+"/"+(k||t.name);a[t.name]={name:t.name,location:k||
t.name,main:(t.main||"main").replace(fa,"").replace(ba,"")}}}function V(a,c){a.holdReady?a.holdReady(c):c?a.readyWait+=1:a.ready(!0)}function ga(a){function c(b,f){var g,m;if(b&&b.charAt(0)===".")if(f){q.pkgs[f]?f=[f]:(f=f.split("/"),f=f.slice(0,f.length-1));g=b=f.concat(b.split("/"));var a;for(m=0;a=g[m];m++)if(a===".")g.splice(m,1),m-=1;else if(a==="..")if(m===1&&(g[2]===".."||g[0]===".."))break;else m>0&&(g.splice(m-1,2),m-=2);m=q.pkgs[g=b[0]];b=b.join("/");m&&b===g+"/"+m.main&&(b=g)}else b.indexOf("./")===
0&&(b=b.substring(2));return b}function l(b,f){var g=b?b.indexOf("!"):-1,m=null,a=f?f.name:null,h=b,e,d;g!==-1&&(m=b.substring(0,g),b=b.substring(g+1,b.length));m&&(m=c(m,a));b&&(m?e=(g=n[m])&&g.normalize?g.normalize(b,function(b){return c(b,a)}):c(b,a):(e=c(b,a),d=G[e],d||(d=i.nameToUrl(b,null,f),G[e]=d)));return{prefix:m,name:e,parentMap:f,url:d,originalName:h,fullName:m?m+"!"+(e||""):e}}function j(){var b=!0,f=q.priorityWait,g,a;if(f){for(a=0;g=f[a];a++)if(!s[g]){b=!1;break}b&&delete q.priorityWait}return b}
function k(b,f,g){return function(){var a=ha.call(arguments,0),c;if(g&&K(c=a[a.length-1]))c.__requireJsBuild=!0;a.push(f);return b.apply(null,a)}}function t(b,f,g){f=k(g||i.require,b,f);$(f,{nameToUrl:k(i.nameToUrl,b),toUrl:k(i.toUrl,b),defined:k(i.requireDefined,b),specified:k(i.requireSpecified,b),isBrowser:d.isBrowser});return f}function p(b){var f,g,a,c=b.callback,h=b.map,e=h.fullName,ca=b.deps;a=b.listeners;var j=q.requireExecCb||d.execCb;if(c&&K(c)){if(q.catchError.define)try{g=j(e,b.callback,
ca,n[e])}catch(k){f=k}else g=j(e,b.callback,ca,n[e]);if(e)(c=b.cjsModule)&&c.exports!==r&&c.exports!==n[e]?g=n[e]=b.cjsModule.exports:g===r&&b.usingExports?g=n[e]:(n[e]=g,H[e]&&(T[e]=!0))}else e&&(g=n[e]=c,H[e]&&(T[e]=!0));if(x[b.id])delete x[b.id],b.isDone=!0,i.waitCount-=1,i.waitCount===0&&(J=[]);delete M[e];if(d.onResourceLoad&&!b.placeholder)d.onResourceLoad(i,h,b.depArray);if(f)return g=(e?l(e).url:"")||f.fileName||f.sourceURL,a=f.moduleTree,f=P("defineerror",'Error evaluating module "'+e+'" at location "'+
g+'":\n'+f+"\nfileName:"+g+"\nlineNumber: "+(f.lineNumber||f.line),f),f.moduleName=e,f.moduleTree=a,d.onError(f);for(f=0;c=a[f];f++)c(g);return r}function u(b,f){return function(g){b.depDone[f]||(b.depDone[f]=!0,b.deps[f]=g,b.depCount-=1,b.depCount||p(b))}}function o(b,f){var g=f.map,a=g.fullName,c=g.name,h=N[b]||(N[b]=n[b]),e;if(!f.loading)f.loading=!0,e=function(b){f.callback=function(){return b};p(f);s[f.id]=!0;A()},e.fromText=function(b,f){var g=Q;s[b]=!1;i.scriptCount+=1;i.fake[b]=!0;g&&(Q=!1);
d.exec(f);g&&(Q=!0);i.completeLoad(b)},a in n?e(n[a]):h.load(c,t(g.parentMap,!0,function(b,a){var c=[],e,m;for(e=0;m=b[e];e++)m=l(m,g.parentMap),b[e]=m.fullName,m.prefix||c.push(b[e]);f.moduleDeps=(f.moduleDeps||[]).concat(c);return i.require(b,a)}),e,q)}function y(b){x[b.id]||(x[b.id]=b,J.push(b),i.waitCount+=1)}function D(b){this.listeners.push(b)}function v(b,f){var g=b.fullName,a=b.prefix,c=a?N[a]||(N[a]=n[a]):null,h,e;g&&(h=M[g]);if(!h&&(e=!0,h={id:(a&&!c?O++ +"__p@:":"")+(g||"__r@"+O++),map:b,
depCount:0,depDone:[],depCallbacks:[],deps:[],listeners:[],add:D},B[h.id]=!0,g&&(!a||N[a])))M[g]=h;a&&!c?(g=l(a),a in n&&!n[a]&&(delete n[a],delete R[g.url]),a=v(g,!0),a.add(function(){var f=l(b.originalName,b.parentMap),f=v(f,!0);h.placeholder=!0;f.add(function(b){h.callback=function(){return b};p(h)})})):e&&f&&(s[h.id]=!1,i.paused.push(h),y(h));return h}function C(b,f,a,c){var b=l(b,c),d=b.name,h=b.fullName,e=v(b),j=e.id,k=e.deps,o;if(h){if(h in n||s[j]===!0||h==="jquery"&&q.jQuery&&q.jQuery!==
a().fn.jquery)return;B[j]=!0;s[j]=!0;h==="jquery"&&a&&W(a())}e.depArray=f;e.callback=a;for(a=0;a<f.length;a++)if(j=f[a])j=l(j,d?b:c),o=j.fullName,f[a]=o,o==="require"?k[a]=t(b):o==="exports"?(k[a]=n[h]={},e.usingExports=!0):o==="module"?e.cjsModule=k[a]={id:d,uri:d?i.nameToUrl(d,null,c):r,exports:n[h]}:o in n&&!(o in x)&&(!(h in H)||h in H&&T[o])?k[a]=n[o]:(h in H&&(H[o]=!0,delete n[o],R[j.url]=!1),e.depCount+=1,e.depCallbacks[a]=u(e,a),v(j,!0).add(e.depCallbacks[a]));e.depCount?y(e):p(e)}function w(b){C.apply(null,
b)}function F(b,f){var a=b.map.fullName,c=b.depArray,d=!0,h,e,i,l;if(b.isDone||!a||!s[a])return l;if(f[a])return b;f[a]=!0;if(c){for(h=0;h<c.length;h++){e=c[h];if(!s[e]&&!ia[e]){d=!1;break}if((i=x[e])&&!i.isDone&&s[e])if(l=F(i,f))break}d||(l=r,delete f[a])}return l}function z(b,a){var g=b.map.fullName,c=b.depArray,d,h,e,i;if(b.isDone||!g||!s[g])return r;if(g){if(a[g])return n[g];a[g]=!0}if(c)for(d=0;d<c.length;d++)if(h=c[d])if((e=l(h).prefix)&&(i=x[e])&&z(i,a),(e=x[h])&&!e.isDone&&s[h])h=z(e,a),b.depCallbacks[d](h);
return n[g]}function E(){var b=q.waitSeconds*1E3,b=b&&i.startTime+b<(new Date).getTime(),a="",c=!1,l=!1,k=[],h,e;if(i.pausedCount>0)return r;if(q.priorityWait)if(j())A();else return r;for(h in s)if(!(h in L)&&(c=!0,!s[h]))if(b)a+=h+" ";else if(l=!0,h.indexOf("!")===-1){k=[];break}else(e=M[h]&&M[h].moduleDeps)&&k.push.apply(k,e);if(!c&&!i.waitCount)return r;if(b&&a)return b=P("timeout","Load timeout for modules: "+a),b.requireType="timeout",b.requireModules=a,b.contextName=i.contextName,d.onError(b);
if(l&&k.length)for(a=0;h=x[k[a]];a++)if(h=F(h,{})){z(h,{});break}if(!b&&(l||i.scriptCount)){if((I||da)&&!X)X=setTimeout(function(){X=0;E()},50);return r}if(i.waitCount){for(a=0;h=J[a];a++)z(h,{});i.paused.length&&A();Y<5&&(Y+=1,E())}Y=0;d.checkReadyState();return r}var i,A,q={waitSeconds:7,baseUrl:"./",paths:{},pkgs:{},catchError:{}},S=[],B={require:!0,exports:!0,module:!0},G={},n={},s={},x={},J=[],R={},O=0,M={},N={},H={},T={},Z=0;W=function(b){if(!i.jQuery&&(b=b||(typeof jQuery!=="undefined"?jQuery:
null))&&!(q.jQuery&&b.fn.jquery!==q.jQuery)&&("holdReady"in b||"readyWait"in b))if(i.jQuery=b,w(["jquery",[],function(){return jQuery}]),i.scriptCount)V(b,!0),i.jQueryIncremented=!0};A=function(){var b,a,c,l,k,h;i.takeGlobalQueue();Z+=1;if(i.scriptCount<=0)i.scriptCount=0;for(;S.length;)if(b=S.shift(),b[0]===null)return d.onError(P("mismatch","Mismatched anonymous define() module: "+b[b.length-1]));else w(b);if(!q.priorityWait||j())for(;i.paused.length;){k=i.paused;i.pausedCount+=k.length;i.paused=
[];for(l=0;b=k[l];l++)a=b.map,c=a.url,h=a.fullName,a.prefix?o(a.prefix,b):!R[c]&&!s[h]&&((q.requireLoad||d.load)(i,h,c),c.indexOf("empty:")!==0&&(R[c]=!0));i.startTime=(new Date).getTime();i.pausedCount-=k.length}Z===1&&E();Z-=1;return r};i={contextName:a,config:q,defQueue:S,waiting:x,waitCount:0,specified:B,loaded:s,urlMap:G,urlFetched:R,scriptCount:0,defined:n,paused:[],pausedCount:0,plugins:N,needFullExec:H,fake:{},fullExec:T,managerCallbacks:M,makeModuleMap:l,normalize:c,configure:function(b){var a,
c,d;b.baseUrl&&b.baseUrl.charAt(b.baseUrl.length-1)!=="/"&&(b.baseUrl+="/");a=q.paths;d=q.pkgs;$(q,b,!0);if(b.paths){for(c in b.paths)c in L||(a[c]=b.paths[c]);q.paths=a}if((a=b.packagePaths)||b.packages){if(a)for(c in a)c in L||aa(d,a[c],c);b.packages&&aa(d,b.packages);q.pkgs=d}if(b.priority)c=i.requireWait,i.requireWait=!1,A(),i.require(b.priority),A(),i.requireWait=c,q.priorityWait=b.priority;if(b.deps||b.callback)i.require(b.deps||[],b.callback)},requireDefined:function(b,a){return l(b,a).fullName in
n},requireSpecified:function(b,a){return l(b,a).fullName in B},require:function(b,c,g){if(typeof b==="string"){if(K(c))return d.onError(P("requireargs","Invalid require call"));if(d.get)return d.get(i,b,c);c=l(b,c);b=c.fullName;return!(b in n)?d.onError(P("notloaded","Module name '"+c.fullName+"' has not been loaded yet for context: "+a)):n[b]}(b&&b.length||c)&&C(null,b,c,g);if(!i.requireWait)for(;!i.scriptCount&&i.paused.length;)A();return i.require},takeGlobalQueue:function(){U.length&&(ja.apply(i.defQueue,
[i.defQueue.length-1,0].concat(U)),U=[])},completeLoad:function(b){var a;for(i.takeGlobalQueue();S.length;)if(a=S.shift(),a[0]===null){a[0]=b;break}else if(a[0]===b)break;else w(a),a=null;a?w(a):w([b,[],b==="jquery"&&typeof jQuery!=="undefined"?function(){return jQuery}:null]);d.isAsync&&(i.scriptCount-=1);A();d.isAsync||(i.scriptCount-=1)},toUrl:function(b,a){var c=b.lastIndexOf("."),d=null;c!==-1&&(d=b.substring(c,b.length),b=b.substring(0,c));return i.nameToUrl(b,d,a)},nameToUrl:function(b,a,g){var l,
k,h,e,j=i.config,b=c(b,g&&g.fullName);if(d.jsExtRegExp.test(b))a=b+(a?a:"");else{l=j.paths;k=j.pkgs;g=b.split("/");for(e=g.length;e>0;e--)if(h=g.slice(0,e).join("/"),l[h]){g.splice(0,e,l[h]);break}else if(h=k[h]){b=b===h.name?h.location+"/"+h.main:h.location;g.splice(0,e,b);break}a=g.join("/")+(a||".js");a=(a.charAt(0)==="/"||a.match(/^[\w\+\.\-]+:/)?"":j.baseUrl)+a}return j.urlArgs?a+((a.indexOf("?")===-1?"?":"&")+j.urlArgs):a}};i.jQueryCheck=W;i.resume=A;return i}function ka(){var a,c,d;if(C&&C.readyState===
"interactive")return C;a=document.getElementsByTagName("script");for(c=a.length-1;c>-1&&(d=a[c]);c--)if(d.readyState==="interactive")return C=d;return null}var la=/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,ma=/require\(\s*["']([^'"\s]+)["']\s*\)/g,fa=/^\.\//,ba=/\.js$/,O=Object.prototype.toString,u=Array.prototype,ha=u.slice,ja=u.splice,I=!!(typeof window!=="undefined"&&navigator&&document),da=!I&&typeof importScripts!=="undefined",na=I&&navigator.platform==="PLAYSTATION 3"?/^complete$/:/^(complete|loaded)$/,
ea=typeof opera!=="undefined"&&opera.toString()==="[object Opera]",L={},D={},U=[],C=null,Y=0,Q=!1,ia={require:!0,module:!0,exports:!0},d,u={},J,y,v,E,o,w,F,B,z,W,X;if(typeof define==="undefined"){if(typeof requirejs!=="undefined")if(K(requirejs))return;else u=requirejs,requirejs=r;typeof require!=="undefined"&&!K(require)&&(u=require,require=r);d=requirejs=function(a,c,d){var j="_",k;!G(a)&&typeof a!=="string"&&(k=a,G(c)?(a=c,c=d):a=[]);if(k&&k.context)j=k.context;d=D[j]||(D[j]=ga(j));k&&d.configure(k);
return d.require(a,c)};d.config=function(a){return d(a)};require||(require=d);d.toUrl=function(a){return D._.toUrl(a)};d.version="1.0.8";d.jsExtRegExp=/^\/|:|\?|\.js$/;y=d.s={contexts:D,skipAsync:{}};if(d.isAsync=d.isBrowser=I)if(v=y.head=document.getElementsByTagName("head")[0],E=document.getElementsByTagName("base")[0])v=y.head=E.parentNode;d.onError=function(a){throw a;};d.load=function(a,c,l){d.resourcesReady(!1);a.scriptCount+=1;d.attach(l,a,c);if(a.jQuery&&!a.jQueryIncremented)V(a.jQuery,!0),
a.jQueryIncremented=!0};define=function(a,c,d){var j,k;typeof a!=="string"&&(d=c,c=a,a=null);G(c)||(d=c,c=[]);!c.length&&K(d)&&d.length&&(d.toString().replace(la,"").replace(ma,function(a,d){c.push(d)}),c=(d.length===1?["require"]:["require","exports","module"]).concat(c));if(Q&&(j=J||ka()))a||(a=j.getAttribute("data-requiremodule")),k=D[j.getAttribute("data-requirecontext")];(k?k.defQueue:U).push([a,c,d]);return r};define.amd={multiversion:!0,plugins:!0,jQuery:!0};d.exec=function(a){return eval(a)};
d.execCb=function(a,c,d,j){return c.apply(j,d)};d.addScriptToDom=function(a){J=a;E?v.insertBefore(a,E):v.appendChild(a);J=null};d.onScriptLoad=function(a){var c=a.currentTarget||a.srcElement,l;if(a.type==="load"||c&&na.test(c.readyState))C=null,a=c.getAttribute("data-requirecontext"),l=c.getAttribute("data-requiremodule"),D[a].completeLoad(l),c.detachEvent&&!ea?c.detachEvent("onreadystatechange",d.onScriptLoad):c.removeEventListener("load",d.onScriptLoad,!1)};d.attach=function(a,c,l,j,k,o){var p;
if(I)return j=j||d.onScriptLoad,p=c&&c.config&&c.config.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script"),p.type=k||c&&c.config.scriptType||"text/javascript",p.charset="utf-8",p.async=!y.skipAsync[a],c&&p.setAttribute("data-requirecontext",c.contextName),p.setAttribute("data-requiremodule",l),p.attachEvent&&!(p.attachEvent.toString&&p.attachEvent.toString().indexOf("[native code]")<0)&&!ea?(Q=!0,o?p.onreadystatechange=function(){if(p.readyState===
"loaded")p.onreadystatechange=null,p.attachEvent("onreadystatechange",j),o(p)}:p.attachEvent("onreadystatechange",j)):p.addEventListener("load",j,!1),p.src=a,o||d.addScriptToDom(p),p;else da&&(importScripts(a),c.completeLoad(l));return null};if(I){o=document.getElementsByTagName("script");for(B=o.length-1;B>-1&&(w=o[B]);B--){if(!v)v=w.parentNode;if(F=w.getAttribute("data-main")){if(!u.baseUrl)o=F.split("/"),w=o.pop(),o=o.length?o.join("/")+"/":"./",u.baseUrl=o,F=w.replace(ba,"");u.deps=u.deps?u.deps.concat(F):
[F];break}}}d.checkReadyState=function(){var a=y.contexts,c;for(c in a)if(!(c in L)&&a[c].waitCount)return;d.resourcesReady(!0)};d.resourcesReady=function(a){var c,l;d.resourcesDone=a;if(d.resourcesDone)for(l in a=y.contexts,a)if(!(l in L)&&(c=a[l],c.jQueryIncremented))V(c.jQuery,!1),c.jQueryIncremented=!1};d.pageLoaded=function(){if(document.readyState!=="complete")document.readyState="complete"};if(I&&document.addEventListener&&!document.readyState)document.readyState="loading",window.addEventListener("load",
d.pageLoaded,!1);d(u);if(d.isAsync&&typeof setTimeout!=="undefined")z=y.contexts[u.context||"_"],z.requireWait=!0,setTimeout(function(){z.requireWait=!1;z.scriptCount||z.resume();d.checkReadyState()},0)}})();

View File

@@ -0,0 +1,109 @@
(function(window) {
var ORIGIN_ = location.protocol + '//' + location.host;
function SlideController() {
this.popup = null;
this.isPopup = window.opener;
if (this.setupDone()) {
window.addEventListener('message', this.onMessage_.bind(this), false);
// Close popups if we reload the main window.
window.addEventListener('beforeunload', function(e) {
if (this.popup) {
this.popup.close();
}
}.bind(this), false);
}
}
SlideController.PRESENTER_MODE_PARAM = 'presentme';
SlideController.prototype.setupDone = function() {
var params = location.search.substring(1).split('&').map(function(el) {
return el.split('=');
});
var presentMe = null;
for (var i = 0, param; param = params[i]; ++i) {
if (param[0].toLowerCase() == SlideController.PRESENTER_MODE_PARAM) {
presentMe = param[1] == 'true';
break;
}
}
if (presentMe !== null) {
localStorage.ENABLE_PRESENTOR_MODE = presentMe;
// TODO: use window.history.pushState to update URL instead of the redirect.
if (window.history.replaceState) {
window.history.replaceState({}, '', location.pathname);
} else {
location.replace(location.pathname);
return false;
}
}
var enablePresenterMode = localStorage.getItem('ENABLE_PRESENTOR_MODE');
if (enablePresenterMode && JSON.parse(enablePresenterMode)) {
// Only open popup from main deck. Don't want recursive popup opening!
if (!this.isPopup) {
var opts = 'menubar=no,location=yes,resizable=yes,scrollbars=no,status=no';
this.popup = window.open(location.href, 'mywindow', opts);
// Loading in the popup? Trigger the hotkey for turning presenter mode on.
this.popup.addEventListener('load', function(e) {
var evt = this.popup.document.createEvent('Event');
evt.initEvent('keydown', true, true);
evt.keyCode = 'P'.charCodeAt(0);
this.popup.document.dispatchEvent(evt);
// this.popup.document.body.classList.add('with-notes');
// document.body.classList.add('popup');
}.bind(this), false);
}
}
return true;
}
SlideController.prototype.onMessage_ = function(e) {
var data = e.data;
// Restrict messages to being from this origin. Allow local developmet
// from file:// though.
// TODO: It would be dope if FF implemented location.origin!
if (e.origin != ORIGIN_ && ORIGIN_.indexOf('file://') != 0) {
alert('Someone tried to postMessage from an unknown origin');
return;
}
// if (e.source.location.hostname != 'localhost') {
// alert('Someone tried to postMessage from an unknown origin');
// return;
// }
if ('keyCode' in data) {
var evt = document.createEvent('Event');
evt.initEvent('keydown', true, true);
evt.keyCode = data.keyCode;
document.dispatchEvent(evt);
}
};
SlideController.prototype.sendMsg = function(msg) {
// // Send message to popup window.
// if (this.popup) {
// this.popup.postMessage(msg, ORIGIN_);
// }
// Send message to main window.
if (this.isPopup) {
// TODO: It would be dope if FF implemented location.origin.
window.opener.postMessage(msg, '*');
}
};
window.SlideController = SlideController;
})(window);

View File

@@ -0,0 +1,13 @@
// Polyfill missing APIs (if we need to), then create the slide deck.
// iOS < 5 needs classList, dataset, and window.matchMedia. Modernizr contains
// the last one.
(function() {
Modernizr.load({
test: !!document.body.classList && !!document.body.dataset,
nope: ['js/polyfills/classList.min.js', 'js/polyfills/dataset.min.js'],
complete: function() {
window.slidedeck = new SlideDeck();
}
});
})();

View File

@@ -0,0 +1,897 @@
/**
* @authors Luke Mahe
* @authors Eric Bidelman
* @fileoverview TODO
*/
document.cancelFullScreen = document.webkitCancelFullScreen ||
document.mozCancelFullScreen;
/**
* @constructor
*/
function SlideDeck(el) {
this.curSlide_ = 0;
this.prevSlide_ = 0;
this.config_ = null;
this.container = el || document.querySelector('slides');
this.slides = [];
this.controller = null;
this.getCurrentSlideFromHash_();
// Call this explicitly. Modernizr.load won't be done until after DOM load.
this.onDomLoaded_.bind(this)();
}
/**
* @const
* @private
*/
SlideDeck.prototype.SLIDE_CLASSES_ = [
'far-past', 'past', 'current', 'next', 'far-next'];
/**
* @const
* @private
*/
SlideDeck.prototype.CSS_DIR_ = '_static/theme/css/';
/**
* @private
*/
SlideDeck.prototype.findSlideById = function(title_id) {
// Return the 1-base index of the Slide with id ``title_id``
//
// The index must be 1-based, as it's passed to code which assumes
// it was specified as the location fragment.
slideEls = document.querySelectorAll('slides > slide');
for (var i = 0; i < slideEls.length; i++) {
if (slideEls.item(i).id == title_id) {
return i + 1;
}
}
// no match on a slide, perhaps it's an explicit reference?
var
target_link = document.querySelector("span[id='" + title_id + "']"),
// XXX this is pretty strict, may need to be more flexible in the future
slide = (target_link && target_link.parentNode);
if (slide && slide.tagName == 'SLIDE') {
return this.findSlideById(slide.id);
}
return false;
};
/**
* @private
*/
SlideDeck.prototype.getCurrentSlideFromHash_ = function() {
var slideNo = parseInt(document.location.hash.substr(1));
if (slideNo && isNaN(slideNo)) {
// must be a section title reference
slideNo = this.findSlideById(location.hash.substr(1));
}
if (slideNo) {
this.curSlide_ = slideNo - 1;
} else {
this.curSlide_ = 0;
}
};
/**
* @param {number} slideNo
*/
SlideDeck.prototype.loadSlide = function(slideNo) {
if (slideNo) {
this.curSlide_ = slideNo - 1;
this.updateSlides_();
}
};
/**
* @private
*/
SlideDeck.prototype.onDomLoaded_ = function(e) {
document.body.classList.add('loaded'); // Add loaded class for templates to use.
this.slides = this.container.querySelectorAll('slide:not([hidden]):not(.hidden):not(.backdrop)');
// If we're on a smartphone, apply special sauce.
if (Modernizr.mq('only screen and (max-device-width: 480px)')) {
// var style = document.createElement('link');
// style.rel = 'stylesheet';
// style.type = 'text/css';
// style.href = this.CSS_DIR_ + 'phone.css';
// document.querySelector('head').appendChild(style);
// No need for widescreen layout on a phone.
this.container.classList.remove('layout-widescreen');
}
this.loadConfig_(SLIDE_CONFIG);
this.addEventListeners_();
this.updateSlides_();
// Add slide numbers and total slide count metadata to each slide.
var that = this;
for (var i = 0, slide; slide = this.slides[i]; ++i) {
slide.dataset.slideNum = i + 1;
slide.dataset.totalSlides = this.slides.length;
slide.addEventListener('click', function(e) {
if (document.body.classList.contains('overview')) {
that.loadSlide(this.dataset.slideNum);
e.preventDefault();
window.setTimeout(function() {
that.toggleOverview();
}, 500);
}
}, false);
}
// Note: this needs to come after addEventListeners_(), which adds a
// 'keydown' listener that this controller relies on.
// Modernizr.touch isn't a sufficient check for devices that support both
// touch and mouse. Create the controller in all cases.
// // Also, no need to set this up if we're on mobile.
// if (!Modernizr.touch) {
this.controller = new SlideController(this);
if (this.controller.isPopup) {
document.body.classList.add('popup');
}
//}
};
/**
* @private
*/
SlideDeck.prototype.addEventListeners_ = function() {
document.addEventListener('keydown', this.onBodyKeyDown_.bind(this), false);
window.addEventListener('popstate', this.onPopState_.bind(this), false);
// var transEndEventNames = {
// 'WebkitTransition': 'webkitTransitionEnd',
// 'MozTransition': 'transitionend',
// 'OTransition': 'oTransitionEnd',
// 'msTransition': 'MSTransitionEnd',
// 'transition': 'transitionend'
// };
//
// // Find the correct transitionEnd vendor prefix.
// window.transEndEventName = transEndEventNames[
// Modernizr.prefixed('transition')];
//
// // When slides are done transitioning, kickoff loading iframes.
// // Note: we're only looking at a single transition (on the slide). This
// // doesn't include autobuilds the slides may have. Also, if the slide
// // transitions on multiple properties (e.g. not just 'all'), this doesn't
// // handle that case.
// this.container.addEventListener(transEndEventName, function(e) {
// this.enableSlideFrames_(this.curSlide_);
// }.bind(this), false);
// document.addEventListener('slideenter', function(e) {
// var slide = e.target;
// window.setTimeout(function() {
// this.enableSlideFrames_(e.slideNumber);
// this.enableSlideFrames_(e.slideNumber + 1);
// }.bind(this), 300);
// }.bind(this), false);
};
/**
* @private
* @param {Event} e The pop event.
*/
SlideDeck.prototype.onPopState_ = function(e) {
if (e.state != null) {
this.curSlide_ = e.state;
this.updateSlides_(true);
}
};
/**
* @param {Event} e
*/
SlideDeck.prototype.onBodyKeyDown_ = function(e) {
if (/^(input|textarea)$/i.test(e.target.nodeName) ||
e.target.isContentEditable) {
return;
}
// Forward keydowns to the main slides if we're the popup.
if (this.controller && this.controller.isPopup) {
this.controller.sendMsg({keyCode: e.keyCode});
}
switch (e.keyCode) {
case 13: // Enter
if (document.body.classList.contains('overview')) {
this.toggleOverview();
}
break;
case 39: // right arrow
case 32: // space
case 34: // PgDn
this.nextSlide();
e.preventDefault();
break;
case 37: // left arrow
case 8: // Backspace
case 33: // PgUp
this.prevSlide();
e.preventDefault();
break;
case 40: // down arrow
this.nextSlide();
e.preventDefault();
break;
case 38: // up arrow
this.prevSlide();
e.preventDefault();
break;
case 72: // H: Toggle code highlighting
document.body.classList.toggle('highlight-code');
break;
case 79: // O: Toggle overview
this.toggleOverview();
break;
case 80: // P
if (this.controller && this.controller.isPopup) {
document.body.classList.toggle('with-notes');
} else if (this.controller && !this.controller.popup) {
document.body.classList.toggle('with-notes');
}
break;
case 82: // R
// TODO: implement refresh on main slides when popup is refreshed.
break;
case 27: // ESC: Hide notes and highlighting
document.body.classList.remove('with-notes');
document.body.classList.remove('highlight-code');
if (document.body.classList.contains('overview')) {
this.toggleOverview();
}
break;
case 70: // F: Toggle fullscreen
// Only respect 'f' on body. Don't want to capture keys from an <input>.
// Also, ignore browser's fullscreen shortcut (cmd+shift+f) so we don't
// get trapped in fullscreen!
if (e.target == document.body && !(e.shiftKey && e.metaKey)) {
if (document.mozFullScreen !== undefined && !document.mozFullScreen) {
document.body.mozRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
} else if (document.webkitIsFullScreen !== undefined && !document.webkitIsFullScreen) {
document.body.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
} else {
document.cancelFullScreen();
}
}
break;
case 87: // W: Toggle widescreen
// Only respect 'w' on body. Don't want to capture keys from an <input>.
if (e.target == document.body && !(e.shiftKey && e.metaKey)) {
this.container.classList.toggle('layout-widescreen');
}
break;
}
};
/**
*
*/
SlideDeck.prototype.focusOverview_ = function() {
var overview = document.body.classList.contains('overview');
for (var i = 0, slide; slide = this.slides[i]; i++) {
slide.style[Modernizr.prefixed('transform')] = overview ?
'translateZ(-2500px) translate(' + (( i - this.curSlide_ ) * 105) +
'%, 0%)' : '';
}
};
/**
*/
SlideDeck.prototype.toggleOverview = function() {
document.body.classList.toggle('overview');
this.focusOverview_();
};
/**
* @private
*/
SlideDeck.prototype.loadConfig_ = function(config) {
if (!config) {
return;
}
this.config_ = config;
var settings = this.config_.settings;
this.loadTheme_(settings.theme || []);
if (settings.favIcon) {
this.addFavIcon_(settings.favIcon);
}
// Prettyprint. Default to on.
if (!!!('usePrettify' in settings) || settings.usePrettify) {
prettyPrint();
}
if (settings.analytics) {
this.loadAnalytics_();
}
if (settings.fonts) {
this.addFonts_(settings.fonts);
}
// Builds. Default to on.
if (!!!('useBuilds' in settings) || settings.useBuilds) {
this.makeBuildLists_();
}
if (settings.title) {
document.title = settings.title.replace(/<br\/?>/, ' ');
if (settings.eventInfo && settings.eventInfo.title) {
document.title += ' - ' + settings.eventInfo.title;
}
document.querySelector('[data-config-title]').innerHTML = settings.title;
}
if (settings.subtitle) {
document.querySelector('[data-config-subtitle]').innerHTML = settings.subtitle;
}
if (this.config_.presenters) {
var presenters = this.config_.presenters;
var dataConfigContact = document.querySelector('[data-config-contact]');
var html = [];
if (presenters.length == 1) {
var p = presenters[0];
var presenterTitle = [p.name];
if (p.company) {
presenterTitle.push(p.company);
}
html = presenterTitle.join(' - ') + '<br>';
var gplus = p.gplus ? '<span>g+</span><a href="' + p.gplus +
'">' + p.gplus.replace(/https?:\/\//, '') + '</a>' : '';
var twitter = p.twitter ? '<span>twitter</span>' +
'<a href="http://twitter.com/' + p.twitter + '">' +
p.twitter + '</a>' : '';
var www = p.www ? '<span>www</span><a href="' + p.www +
'">' + p.www.replace(/https?:\/\//, '') + '</a>' : '';
var github = p.github ? '<span>github</span><a href="' + p.github +
'">' + p.github.replace(/https?:\/\//, '') + '</a>' : '';
var html2 = [gplus, twitter, www, github].join('<br>');
if (dataConfigContact) {
dataConfigContact.innerHTML = html2;
}
} else {
for (var i = 0, p; p = presenters[i]; ++i) {
html.push(p.name + ' - ' + p.company);
}
html = html.join('<br>');
if (dataConfigContact) {
dataConfigContact.innerHTML = html;
}
}
var dataConfigPresenter = document.querySelector('[data-config-presenter]');
if (dataConfigPresenter) {
dataConfigPresenter.innerHTML = html;
if (settings.eventInfo) {
var date = settings.eventInfo.date;
var dateInfo = date ? ' - <time>' + date + '</time>' : '';
dataConfigPresenter.innerHTML += settings.eventInfo.title + dateInfo;
}
}
}
/* Left/Right tap areas. Default to including. */
if (!!!('enableSlideAreas' in settings) || settings.enableSlideAreas) {
var el = document.createElement('div');
el.classList.add('slide-area');
el.id = 'prev-slide-area';
el.addEventListener('click', this.prevSlide.bind(this,undefined), false);
this.container.appendChild(el);
var el = document.createElement('div');
el.classList.add('slide-area');
el.id = 'next-slide-area';
el.addEventListener('click', this.nextSlide.bind(this,undefined), false);
this.container.appendChild(el);
}
if (Modernizr.touch && (!!!('enableTouch' in settings) ||
settings.enableTouch)) {
var self = this;
// Note: this prevents mobile zoom in/out but prevents iOS from doing
// it's crazy scroll over effect and disaligning the slides.
window.addEventListener('touchstart', function(e) {
e.preventDefault();
}, false);
var hammer = new Hammer(this.container);
hammer.ondragend = function(e) {
if (e.direction == 'right' || e.direction == 'down') {
self.prevSlide();
} else if (e.direction == 'left' || e.direction == 'up') {
self.nextSlide();
}
};
}
};
/**
* @private
* @param {Array.<string>} fonts
*/
SlideDeck.prototype.addFonts_ = function(fonts) {
var el = document.createElement('link');
el.rel = 'stylesheet';
el.href = ('https:' == document.location.protocol ? 'https' : 'http') +
'://fonts.googleapis.com/css?family=' + fonts.join('|') + '&v2';
document.querySelector('head').appendChild(el);
};
/**
* @private
*/
SlideDeck.prototype.buildNextBuildItem_ = function() {
var slide = this.slides[this.curSlide_];
var toBuild = slide.querySelector('.to-build');
var built = slide.querySelector('.build-current');
if (built) {
built.classList.remove('build-current');
if (built.classList.contains('fade')) {
built.classList.add('build-fade');
}
}
if (!toBuild) {
var items = slide.querySelectorAll('.build-fade');
for (var j = 0, item; item = items[j]; j++) {
item.classList.remove('build-fade');
}
return false;
}
toBuild.classList.remove('to-build');
toBuild.classList.add('build-current');
return true;
};
SlideDeck.prototype.buildNextItem_ = function() {
var slide = this.slides[this.curSlide_];
var built = slide.querySelectorAll('.build-current');
var buildItems = slide.querySelectorAll('[class*="build-item-"]');
var show_items;
// Remove the classes from the previously built item
if (built) {
for (var j = 0, built_item; built_item = built[j]; ++j) {
built_item.classList.remove('build-current');
if (built_item.classList.contains('fade')) {
built_item.classList.add('build-fade');
}
if (built_item.getAttribute('data-build-show-only')) {
if (built_item.getAttribute('data-build-class')) {
built_item.classList.remove(
built_item.getAttribute('data-build-class')
);
} else {
built_item.classList.add('build-hide');
}
}
};
}
if (slide._buildItems && slide._buildItems.length) {
while ((show_items = slide._buildItems.shift()) === undefined) {};
if (show_items) {
// show the next items
show_items.forEach(function(item, index, items) {
item.classList.remove('to-build');
item.classList.add('build-current');
if (item.getAttribute('data-build-class')) {
item.classList.add(item.getAttribute('data-build-class'));
}
});
return true;
}
}
return this.buildNextBuildItem_();
};
/**
* @param {boolean=} opt_dontPush
*/
SlideDeck.prototype.prevSlide = function(opt_dontPush) {
if (this.curSlide_ > 0) {
var bodyClassList = document.body.classList;
bodyClassList.remove('highlight-code');
// Toggle off speaker notes if they're showing when we move backwards on the
// main slides. If we're the speaker notes popup, leave them up.
if (this.controller && !this.controller.isPopup) {
bodyClassList.remove('with-notes');
} else if (!this.controller) {
bodyClassList.remove('with-notes');
}
this.prevSlide_ = this.curSlide_--;
this.updateSlides_(opt_dontPush);
}
};
/**
* @param {boolean=} opt_dontPush
*/
SlideDeck.prototype.nextSlide = function(opt_dontPush) {
if (!document.body.classList.contains('overview') && this.buildNextItem_()) {
return;
}
if (this.curSlide_ < this.slides.length - 1) {
var bodyClassList = document.body.classList;
bodyClassList.remove('highlight-code');
// Toggle off speaker notes if they're showing when we advanced on the main
// slides. If we're the speaker notes popup, leave them up.
if (this.controller && !this.controller.isPopup) {
bodyClassList.remove('with-notes');
} else if (!this.controller) {
bodyClassList.remove('with-notes');
}
this.prevSlide_ = this.curSlide_++;
this.updateSlides_(opt_dontPush);
}
};
/* Slide events */
/**
* Triggered when a slide enter/leave event should be dispatched.
*
* @param {string} type The type of event to trigger
* (e.g. 'slideenter', 'slideleave').
* @param {number} slideNo The index of the slide that is being left.
*/
SlideDeck.prototype.triggerSlideEvent = function(type, slideNo) {
var el = this.getSlideEl_(slideNo);
if (!el) {
return;
}
// Call onslideenter/onslideleave if the attribute is defined on this slide.
var func = el.getAttribute(type);
if (func) {
new Function(func).call(el); // TODO: Don't use new Function() :(
}
// Dispatch event to listeners setup using addEventListener.
var evt = document.createEvent('Event');
evt.initEvent(type, true, true);
evt.slideNumber = slideNo + 1; // Make it readable
evt.slide = el;
el.dispatchEvent(evt);
};
/**
* @private
*/
SlideDeck.prototype.updateSlides_ = function(opt_dontPush) {
var dontPush = opt_dontPush || false;
var curSlide = this.curSlide_;
for (var i = 0; i < this.slides.length; ++i) {
switch (i) {
case curSlide - 2:
this.updateSlideClass_(i, 'far-past');
break;
case curSlide - 1:
this.updateSlideClass_(i, 'past');
break;
case curSlide:
this.updateSlideClass_(i, 'current');
break;
case curSlide + 1:
this.updateSlideClass_(i, 'next');
break;
case curSlide + 2:
this.updateSlideClass_(i, 'far-next');
break;
default:
this.updateSlideClass_(i);
break;
}
};
this.triggerSlideEvent('slideleave', this.prevSlide_);
this.triggerSlideEvent('slideenter', curSlide);
// window.setTimeout(this.disableSlideFrames_.bind(this, curSlide - 2), 301);
//
// this.enableSlideFrames_(curSlide - 1); // Previous slide.
// this.enableSlideFrames_(curSlide + 1); // Current slide.
// this.enableSlideFrames_(curSlide + 2); // Next slide.
// Enable current slide's iframes (needed for page loat at current slide).
this.enableSlideFrames_(curSlide + 1);
// No way to tell when all slide transitions + auto builds are done.
// Give ourselves a good buffer to preload the next slide's iframes.
window.setTimeout(this.enableSlideFrames_.bind(this, curSlide + 2), 1000);
this.updateHash_(dontPush);
if (document.body.classList.contains('overview')) {
this.focusOverview_();
return;
}
};
/**
* @private
* @param {number} slideNo
*/
SlideDeck.prototype.enableSlideFrames_ = function(slideNo) {
var el = this.slides[slideNo - 1];
if (!el) {
return;
}
var frames = el.querySelectorAll('iframe');
for (var i = 0, frame; frame = frames[i]; i++) {
this.enableFrame_(frame);
}
};
/**
* @private
* @param {number} slideNo
*/
SlideDeck.prototype.enableFrame_ = function(frame) {
var src = frame.dataset.src;
if (src && frame.src != src) {
frame.src = src;
}
};
/**
* @private
* @param {number} slideNo
*/
SlideDeck.prototype.disableSlideFrames_ = function(slideNo) {
var el = this.slides[slideNo - 1];
if (!el) {
return;
}
var frames = el.querySelectorAll('iframe');
for (var i = 0, frame; frame = frames[i]; i++) {
this.disableFrame_(frame);
}
};
/**
* @private
* @param {Node} frame
*/
SlideDeck.prototype.disableFrame_ = function(frame) {
frame.src = 'about:blank';
};
/**
* @private
* @param {number} slideNo
*/
SlideDeck.prototype.getSlideEl_ = function(no) {
if ((no < 0) || (no >= this.slides.length)) {
return null;
} else {
return this.slides[no];
}
};
/**
* @private
* @param {number} slideNo
* @param {string} className
*/
SlideDeck.prototype.updateSlideClass_ = function(slideNo, className) {
var el = this.getSlideEl_(slideNo);
if (!el) {
return;
}
if (className) {
el.classList.add(className);
}
for (var i = 0, slideClass; slideClass = this.SLIDE_CLASSES_[i]; ++i) {
if (className != slideClass) {
el.classList.remove(slideClass);
}
}
};
/**
* @private
*/
SlideDeck.prototype.BUILD_ITEM_RE = /build-item-(\d+)(-class-(\w+))?(-only)?/;
SlideDeck.prototype.makeBuildLists_ = function () {
for (var i = this.curSlide_, slide; slide = this.slides[i]; ++i) {
var items = slide.querySelectorAll('.build > *');
for (var j = 0, item; item = items[j]; ++j) {
if (item.classList) {
item.classList.add('to-build');
if (item.parentNode.classList.contains('fade')) {
item.classList.add('fade');
}
}
}
var items = slide.querySelectorAll('[class*="build-item-"]');
if (items.length) {
slide._buildItems = [];
};
for (var j = 0, item; item = items[j]; ++j) {
if (item.classList) {
item.classList.add('to-build');
if (!item.parentNode.classList.contains('build')) {
item.parentNode.classList.add('build');
}
if (item.parentNode.classList.contains('fade')) {
item.classList.add('fade');
}
}
var build_info = this.BUILD_ITEM_RE.exec(item.classList),
build_index = build_info[1],
build_class = build_info[3],
build_only = build_info[4];
if (slide._buildItems[build_index] === undefined) {
slide._buildItems[build_index] = [];
}
slide._buildItems[build_index].push(item);
if (build_class) {
item.setAttribute('data-build-class', build_class);
}
if (build_only) {
// add the data-attribute
item.setAttribute('data-build-show-only', build_index);
}
}
}
};
/**
* @private
* @param {boolean} dontPush
*/
SlideDeck.prototype.updateHash_ = function(dontPush) {
if (!dontPush) {
var slideNo = this.curSlide_ + 1;
var hash = '#' + slideNo;
if (window.history.pushState) {
window.history.pushState(this.curSlide_, 'Slide ' + slideNo, hash);
} else {
window.location.replace(hash);
}
// Record GA hit on this slide.
window['_gaq'] && window['_gaq'].push(['_trackPageview',
document.location.href]);
}
};
/**
* @private
* @param {string} favIcon
*/
SlideDeck.prototype.addFavIcon_ = function(favIcon) {
var el = document.createElement('link');
el.rel = 'icon';
el.type = 'image/png';
el.href = favIcon;
document.querySelector('head').appendChild(el);
};
/**
* @private
* @param {string} theme
*/
SlideDeck.prototype.loadTheme_ = function(theme) {
var styles = [];
if (theme.constructor.name === 'String') {
styles.push(theme);
} else {
styles = theme;
}
for (var i = 0, style; themeUrl = styles[i]; i++) {
var style = document.createElement('link');
style.rel = 'stylesheet';
style.type = 'text/css';
if (themeUrl.indexOf('http') == -1) {
style.href = this.CSS_DIR_ + themeUrl + '.css';
} else {
style.href = themeUrl;
}
document.querySelector('head').appendChild(style);
}
};
/**
* @private
*/
SlideDeck.prototype.loadAnalytics_ = function() {
var _gaq = window['_gaq'] || [];
_gaq.push(['_setAccount', this.config_.settings.analytics]);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
};

View File

@@ -0,0 +1,6 @@
require(['order!modernizr.custom.45394',
'order!prettify/prettify', 'order!hammer', 'order!slide-controller',
'order!slide-deck',
'order!slide-deck-instantiate'], function(someModule) {
});

View File

@@ -0,0 +1,6 @@
require(['order!../slide_config', 'order!modernizr.custom.45394',
'order!prettify/prettify', 'order!hammer', 'order!slide-controller',
'order!slide-deck',
'order!slide-deck-instantiate'], function(someModule) {
});

View File

@@ -0,0 +1,40 @@
var SLIDE_CONFIG = {
// Slide settings
settings: {
title: 'Title Goes Here<br>Up To Two Lines',
subtitle: 'Subtitle Goes Here',
//eventInfo: {
// title: 'Google I/O',
// date: '6/x/2013'
//},
useBuilds: true, // Default: true. False will turn off slide animation builds.
usePrettify: true, // Default: true
enableSlideAreas: true, // Default: true. False turns off the click areas on either slide of the slides.
enableTouch: true, // Default: true. If touch support should enabled. Note: the device must support touch.
//analytics: 'UA-XXXXXXXX-1', // TODO: Using this breaks GA for some reason (probably requirejs). Update your tracking code in template.html instead.
favIcon: 'images/google_developers_logo_tiny.png',
fonts: [
'Open Sans:regular,semibold,italic,italicsemibold',
'Source Code Pro'
],
//theme: ['mytheme'], // Add your own custom themes or styles in /theme/css. Leave off the .css extension.
},
// Author information
presenters: [{
name: 'Firstname Lastname',
company: 'Job Title<br>Google',
gplus: 'http://plus.google.com/1234567890',
twitter: '@yourhandle',
www: 'http://www.you.com',
github: 'http://github.com/you'
}/*, {
name: 'Second Name',
company: 'Job Title, Google',
gplus: 'http://plus.google.com/1234567890',
twitter: '@yourhandle',
www: 'http://www.you.com',
github: 'http://github.com/you'
}*/]
};

View File

@@ -0,0 +1,27 @@
var SLIDE_CONFIG = {
// Slide settings
settings: {
title: '{{ docstitle|e }}',
subtitle: '{{ theme_subtitle|e }}',
//eventInfo: {
// title: 'Google I/O',
// date: '6/x/2013'
//},
useBuilds: {{ theme_use_builds }}, // Default: true. False will turn off slide animation builds.
usePrettify: {{ theme_use_prettify }}, // Default: true
enableSlideAreas: {{ theme_enable_slide_areas }}, // Default: true. False turns off the click areas on either slide of the slides.
enableTouch: {{ theme_enable_touch }}, // Default: true. If touch support should enabled. Note: the device must support touch.
//analytics: 'UA-XXXXXXXX-1', // TODO: Using this breaks GA for some reason (probably requirejs). Update your tracking code in template.html instead.
favIcon: {{ theme_favicon }},
fonts: [
'Open Sans:regular,semibold,italic,italicsemibold',
'Source Code Pro'
],
//theme: ['mytheme'], // Add your own custom themes or styles in /theme/css. Leave off the .css extension.
},
// Author information
presenters: {% if theme_presenters %}{{ theme_presenters|json }}
{% else %}[]
{% endif %}
};

View File

@@ -0,0 +1,84 @@
/* line 5, ../scss/hieroglyph.scss */
ol {
margin-left: 1.2em;
margin-bottom: 1em;
position: relative;
list-style: decimal;
}
/* line 11, ../scss/hieroglyph.scss */
ol li {
margin-bottom: 0.5em;
}
/* line 14, ../scss/hieroglyph.scss */
ol li ol {
margin-left: 2em;
margin-bottom: 0;
list-style: decimal;
}
/* line 19, ../scss/hieroglyph.scss */
ol li ol li:before {
font-weight: 600;
}
/* line 25, ../scss/hieroglyph.scss */
ol ol {
margin-top: .5em;
list-style: decimal;
}
/* line 32, ../scss/hieroglyph.scss */
slide.title-image {
padding-right: 0px;
}
/* line 36, ../scss/hieroglyph.scss */
slide.title-image hgroup {
position: static !important;
margin-top: 35%;
padding-left: 30px;
background: rgba(255, 255, 255, 0.7);
border-top-left-radius: 5px;
-webkit-border-top-left-radius: 5px;
-moz-border-top-left-radius: 5px;
-o-border-top-left-radius: 5px;
}
/* line 50, ../scss/hieroglyph.scss */
slide.title-image hgroup + article {
background: rgba(255, 255, 255, 0.7);
margin-top: 0px;
padding-left: 30px;
border-bottom-left-radius: 5px;
-webkit-border-bottom-left-radius: 5px;
-moz-border-bottom-left-radius: 5px;
-o-border-bottom-left-radius: 5px;
}
/* line 62, ../scss/hieroglyph.scss */
slide.title-image h1 {
color: #222;
font-size: 3.2em;
line-height: 1.5em;
font-weight: 500;
}
/* line 72, ../scss/hieroglyph.scss */
slide.title-image div.figure img {
position: absolute;
left: 0;
top: 0;
min-width: 100%;
min-height: 100%;
border-radius: 5px;
-o-border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
z-index: -1;
}
/* line 87, ../scss/hieroglyph.scss */
slide.title-image div.figure .caption {
color: black;
background: rgba(255, 255, 255, 0.25);
padding: 0 5px;
border-bottom-left-radius: 5px;
border-top-right-radius: 5px;
position: absolute;
left: 0;
bottom: 0;
margin-bottom: 0;
}

View File

@@ -0,0 +1,55 @@
/* line 5, ../scss/io2013.scss */
* {
line-height: 1.3;
}
/* line 9, ../scss/io2013.scss */
h2 {
font-weight: bold;
}
/* line 12, ../scss/io2013.scss */
h2, h3 {
color: #515151;
}
/* line 16, ../scss/io2013.scss */
q, blockquote {
font-weight: bold;
}
/* line 20, ../scss/io2013.scss */
slides > slide {
color: #515151;
}
/* line 24, ../scss/io2013.scss */
slides > slide.title-slide:after {
content: '';
background: url(../../images/io2013/google-io-lockup-1.png) no-repeat 100% 50%;
-moz-background-size: contain;
-o-background-size: contain;
-webkit-background-size: contain;
background-size: contain;
position: absolute;
bottom: 80px;
right: 40px;
width: 100%;
height: 90px;
}
/* line 36, ../scss/io2013.scss */
slides > slide.title-slide hgroup h1 {
font-weight: bold;
line-height: 1.1;
}
/* line 40, ../scss/io2013.scss */
slides > slide.title-slide hgroup h2, slides > slide.title-slide hgroup p {
color: #515151;
}
/* line 43, ../scss/io2013.scss */
slides > slide.title-slide hgroup h2 {
margin-top: 0.25em;
}
/* line 46, ../scss/io2013.scss */
slides > slide.title-slide hgroup p {
margin-top: 3em;
}

View File

@@ -0,0 +1,26 @@
/*Smartphones (portrait and landscape) ----------- */
/*@media only screen
and (min-width : 320px)
and (max-width : 480px) {
}*/
/* Smartphones (portrait) ----------- */
/* Styles */
/* line 17, ../scss/phone.scss */
slides > slide {
/* width: $slide-width !important;
height: $slide-height !important;
margin-left: -$slide-width / 2 !important;
margin-top: -$slide-height / 2 !important;
*/
-webkit-transition: none !important;
-moz-transition: none !important;
-o-transition: none !important;
-webkit-transition: none !important;
transition: none !important;
}
/* iPhone 4 ----------- */
@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-device-pixel-ratio: 1.5) {
/* Styles */
}

View File

@@ -0,0 +1,139 @@
@charset "UTF-8";
@import "compass/reset";
@import "compass/css3/border-radius";
@import "compass/css3/box";
@import "compass/css3/box-shadow";
@import "compass/css3/box-sizing";
@import "compass/css3/images";
@import "compass/css3/text-shadow";
@import "compass/css3/background-size";
@import "compass/css3/transform";
@import "compass/css3/transition";
@import "variables";
@mixin font-smoothing($val: antialiased) {
-webkit-font-smoothing: $val;
-moz-font-smoothing: $val;
-ms-font-smoothing: $val;
-o-font-smoothing: $val;
}
@mixin flexbox {
display: -webkit-box !important;
display: -moz-box !important;
display: -ms-box !important;
display: -o-box !important;
display: box !important;
}
@mixin flex-center-center {
@include box-orient(vertical);
@include box-align(center);
@include box-pack(center);
}
@mixin flex-left-center {
@include box-orient(vertical);
@include box-align(left);
@include box-pack(center);
}
@mixin flex-right-center {
@include box-orient(vertical);
@include box-align(end);
@include box-pack(center);
}
/**
* Base SlideDeck Styles
*/
html {
height: 100%;
overflow: hidden;
}
body {
margin: 0;
padding: 0;
opacity: 0;
height: 100%;
min-height: 740px;
width: 100%;
overflow: hidden;
color: #fff;
@include font-smoothing(antialiased);
@include transition(opacity 800ms ease-in 100ms); // Add small delay to prevent jank.
&.loaded {
opacity: 1 !important;
}
}
input, button {
vertical-align: middle;
}
slides > slide[hidden] {
display: none !important;
}
slides {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
@include transform(translate3d(0, 0, 0));
@include perspective(1000);
@include transform-style(preserve-3d);
@include transition(opacity 800ms ease-in 100ms); // Add small delay to prevent jank.
}
slides > slide {
display: block;
position: absolute;
overflow: hidden;
left: 50%;
top: 50%;
@include box-sizing(border-box);
}
/* Slide styles */
/*article.fill iframe {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
border: 0;
margin: 0;
@include border-radius(10px);
z-index: -1;
}
slide.fill {
background-repeat: no-repeat;
@include background-size(cover);
}
slide.fill img {
position: absolute;
left: 0;
top: 0;
min-width: 100%;
min-height: 100%;
z-index: -1;
}
*/

View File

@@ -0,0 +1,34 @@
$social-tags: '';
$brand-small-icon-size: 30px;
$gray-1: #e6e6e6;
$gray-2: #a9a9a9;
$gray-3: #797979;
$gray-4: #515151;
$brand-blue: rgb(67, 135, 253);
$brand-blue-secondary: #3c8ef3;
$brand-blue-secondary2: #2a7cdf;
$brand-red: rgb(244, 74, 63);
$brand-red-secondary: #e0543e;
$brand-red-secondary2: #d94d3a;
$brand-yellow: rgb(255, 209, 77);
$brand-yellow-secondary: #f9cc46;
$brand-yellow-secondary2: #f6c000;
$brand-green: rgb(13, 168, 97);
$brand-green-secondary: #00a86d;
$brand-green-secondary2: #009f5d;
$slide-width: 900px;
$slide-height: 700px;
$slide-width-widescreen: 1100px;
$slide-top-bottom-padding: 40px;
$slide-left-right-padding: 60px;
$slide-border-radius: 5px;
$slide-tap-area-width: 100px;
$article-content-top-padding: 45px;

View File

@@ -0,0 +1,100 @@
@import "compass/css3/background-size";
@import "variables";
ol {
margin-left: 1.2em;
margin-bottom: 1em;
position: relative;
list-style: decimal;
li {
margin-bottom: 0.5em;
ol {
margin-left: 2em;
margin-bottom: 0;
list-style: decimal;
li:before {
font-weight: 600;
}
}
}
ol {
margin-top: .5em;
list-style: decimal;
}
}
slide.title-image {
padding-right: 0px;
hgroup {
position: static !important;
margin-top: 35%;
padding-left: 30px;
background: rgba(255, 255, 255, 0.7);
border-top-left-radius: $slide-border-radius;
-webkit-border-top-left-radius: $slide-border-radius;
-moz-border-top-left-radius: $slide-border-radius;
-o-border-top-left-radius: $slide-border-radius;
}
hgroup + article {
background: rgba(255, 255, 255, 0.7);
margin-top: 0px;
padding-left: 30px;
border-bottom-left-radius: $slide-border-radius;
-webkit-border-bottom-left-radius: $slide-border-radius;
-moz-border-bottom-left-radius: $slide-border-radius;
-o-border-bottom-left-radius: $slide-border-radius;
}
h1 {
color: #222;
font-size: 3.2em;
line-height: 1.5em;
font-weight: 500;
}
div.figure {
img {
position: absolute;
left: 0;
top: 0;
min-width: 100%;
min-height: 100%;
border-radius: $slide-border-radius;
-o-border-radius: $slide-border-radius;
-moz-border-radius: $slide-border-radius;
-webkit-border-radius: $slide-border-radius;
z-index: -1;
}
.caption {
color: black;
background: rgba(255, 255, 255, 0.25);
padding: 0 5px;
border-bottom-left-radius: $slide-border-radius;
border-top-right-radius: $slide-border-radius;
position: absolute;
left: 0;
bottom: 0;
margin-bottom: 0;
}
}
}

View File

@@ -0,0 +1,51 @@
@import "compass/css3/background-size";
@import "variables";
* {
line-height: 1.3;
}
h2 {
font-weight: bold;
}
h2, h3 {
color: $gray-4;
}
q, blockquote {
font-weight: bold;
}
slides > slide {
color: $gray-4;
&.title-slide {
&:after {
content: '';
background: url(../../images/io2013/google-io-lockup-1.png) no-repeat 100% 50%;
@include background-size(contain);
position: absolute;
bottom: $slide-top-bottom-padding + 40;
right: $slide-top-bottom-padding;
width: 100%;
height: 90px;
}
hgroup {
h1 {
font-weight: bold;
line-height: 1.1;
}
h2, p {
color: $gray-4;
}
h2 {
margin-top: 0.25em;
}
p {
margin-top: 3em;
}
}
}
}

View File

@@ -0,0 +1,35 @@
@import "compass/css3/transition";
/*Smartphones (portrait and landscape) ----------- */
/*@media only screen
and (min-width : 320px)
and (max-width : 480px) {
}*/
/* Smartphones (portrait) ----------- */
//@media only screen and (max-device-width: 480px) {
/* Styles */
//$slide-width: 350px;
//$slide-height: 500px;
slides > slide {
/* width: $slide-width !important;
height: $slide-height !important;
margin-left: -$slide-width / 2 !important;
margin-top: -$slide-height / 2 !important;
*/
// Don't do full slide transitions on mobile.
-webkit-transition: none !important; // Bug in compass? Not sure why the below is not working
@include transition(none !important);
}
//}
/* iPhone 4 ----------- */
@media
only screen and (-webkit-min-device-pixel-ratio : 1.5),
only screen and (min-device-pixel-ratio : 1.5) {
/* Styles */
}

View File

@@ -0,0 +1,15 @@
[theme]
inherit = basic
stylesheet = slides.css
[options]
custom_css =
custom_js =
subtitle =
use_builds = true
use_prettify = true
enable_slide_areas = true
enable_touch = true
favicon = ''
presenters =

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 98 KiB

View File

@@ -0,0 +1,125 @@
# -*- coding: utf-8 -*-
#
# CodeQL training slides build configuration file
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# For details of all possible config values,
# see https://www.sphinx-doc.org/en/master/usage/configuration.html
##################################################################################
# -- GLOBAL GENERAL CONFIG VALUES ------------------------------------------------
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# If your documentation needs a minimal Sphinx version, state it here.
# needs_sphinx = '1.7.9'
# Beware that some of the extensions don't work in version 1.8
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.intersphinx',
'sphinx.ext.mathjax',
'hieroglyph',
'sphinx.ext.graphviz',
]
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# Import the QL Lexer to use for syntax highlighting
import sys
import os
def setup(sphinx):
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), os.path.pardir, 'global-sphinx-files')))
from qllexer import QLLexer
sphinx.add_lexer("ql", QLLexer())
# Set QL as the default language for highlighting code. Set to none to disable
# syntax highlighting. If omitted or left blank, it defaults to Python 3.
highlight_language = 'ql'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'CodeQL training and variant analysis examples'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static-training']
# Add any paths that contain templates here, relative to this directory.
#templates_path = ['../rst-styles/_templates-training']
#slide_theme_options = {'custom_css':'custom.css'}
slide_theme = 'slides-semmle-2'
slide_theme_path = ["_static-training/"]
# -- Project-specifc options for HTML output ----------------------------------------------
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
html_title = 'CodeQL training and variant analysis examples'
# Output file base name for HTML help builder.
htmlhelp_basename = 'CodeQL training'
# The Semmle version info for the current release you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = u'1.24'
# The full version, including alpha/beta/rc tags.
release = u'1.24'
copyright = u'2019 Semmle Ltd'
author = u'Semmle Ltd'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
language = None
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# If true, links to the reST sources are added to the pages.
html_show_sourcelink = False
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
html_show_sphinx = False
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
html_theme_options = {'font_size': '16px',
'body_text': '#333',
'link': '#2F1695',
'link_hover': '#2F1695',
'font_family': 'Lato, sans-serif',
'head_font_family': 'Moderat, sans-serif',
'show_powered_by': False,
'nosidebar':True,
}
# Exclude the slide snippets from the build
exclude_patterns = ['slide-snippets']
##############################################################################

View File

@@ -0,0 +1,232 @@
===========================
Example: Bad overflow guard
===========================
CodeQL for C/C++
.. rst-class:: setup
Setup
=====
For this example you should download:
- `CodeQL for Visual Studio Code <https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html>`__
- `ChakraCore database <https://downloads.lgtm.com/snapshots/cpp/microsoft/chakracore/ChakraCore-revision-2017-April-12--18-13-26.zip>`__
.. note::
For the examples in this presentation, we will be analyzing `ChakraCore <https://github.com/microsoft/ChakraCore>`__.
You can query the project in `the query console <https://lgtm.com/query/project:2034240708/lang:cpp/>`__ on LGTM.com.
.. insert database-note.rst to explain differences between database available to download and the version available in the query console.
.. include:: ../slide-snippets/database-note.rst
.. resume slides
Checking for overflow in C
==========================
- Arithmetic operations overflow if the result is too large for their type.
- Developers sometimes exploit this to write overflow checks:
.. code-block:: cpp
if (v + b < v) {
handle_error("overflow");
} else {
result = v + b;
}
Where might this go wrong?
.. note::
- In C/C++ we often need to check for whether an operation `overflows <https://en.wikipedia.org/wiki/Integer_overflow>`__.
- An overflow is when an arithmetic operation, such as an addition, results in a number which is too large to be stored in the type.
- When an operation overflows, the value “wraps” around.
- A typical way to check for overflow of an addition, therefore, is whether the result is less than one of the argumentsthat is the result has **wrapped**.
Integer promotion
=================
From `https://en.cppreference.com/w/c/language/conversion <https://en.cppreference.com/w/c/language/conversion>`__:
.. rst-class:: quote
Integer promotion is the implicit conversion of a value of any integer type with rank less or equal to rank of ``int`` ... to the value of type ``int`` or ``unsigned int``.
- The arguments of the following arithmetic operators undergo implicit conversions:
- binary arithmetic ``* / % + -``
- relational operators ``< > <= >= == !=``
- binary bitwise operators ``& ^ |``
- the conditional operator ``?:``
.. note::
- Most of the time integer conversion works fine. However, the rules governing addition in C/C++ are complex, and it's easy to get bitten.
- CPUs generally prefer to perform arithmetic operations on 32-bit or larger integers, as the architectures are optimized to perform those efficiently.
- The compiler therefore performs “integer promotion” for arguments to arithmetic operations that are smaller than 32-bit.
Checking for overflow in C revisited
====================================
Which branch gets executed in this example? What is the value of ``result``?
.. code-block:: cpp
uint16_t v = 65535;
uint16_t b = 1;
uint16_t result;
if (v + b < v) {
handle_error("overflow");
} else {
result = v + b;
}
.. note::
In this example the second branch is executed, even though there is a 16-bit overflow, and ``result`` is set to zero.
Checking for overflow in C revisited
====================================
Here is the example again, with the conversions made explicit:
.. code-block:: cpp
:emphasize-lines: 4,7
uint16_t v = 65535;
uint16_t b = 1;
uint16_t result;
if ((int)v + (int)b < (int)v) {
handle_error("overflow");
} else {
result = (uint16_t)((int)v + (int)b);
}
.. note::
In this example the second branch is executed, even though there is a 16-bit overflow, and result is set to zero.
Explanation:
- The two integer arguments to the addition, ``v`` and ``b``, are promoted to 32-bit integers.
- The comparison (``<``) is also an arithmetic operation, therefore it will also be completed on 32-bit integers.
- This means that ``v + b < v`` will never be true, because v and b can hold at most 2 :sup:`16`.
- Therefore, the second branch is executed, but the result of the addition is stored into the result variable. Overflow will still occur as result is a 16-bit integer.
This happens even though the overflow check passed!
.. rst-class:: background2
Developing a CodeQL query
=========================
Finding bad overflow guards
CodeQL query: bad overflow guards
==================================
Lets look for overflow guards of the form ``v + b < v``, using the classes
``AddExpr``, ``Variable`` and ``RelationalOperation`` from the ``cpp`` library.
.. rst-class:: build
.. literalinclude:: ../query-examples/cpp/bad-overflow-guard-1.ql
:language: ql
.. note::
- When performing variant analysis, it is usually helpful to write a simple query that finds the simple syntactic pattern, before trying to go on to describe the cases where it goes wrong.
- In this case, we start by looking for all the *overflow* checks, before trying to refine the query to find all *bad overflow* checks.
- The ``select`` clause defines what this query is looking for:
- an ``AddExpr``: the expression that is being checked for overflow.
- a ``RelationalOperation``: the overflow comparison check.
- a ``Variable``: used as an argument to both the addition and comparison.
- The ``where`` part of the query ties these three variables together using `predicates <https://help.semmle.com/QL/ql-handbook/predicates.html>`__ defined in the `standard CodeQL for C/C++ library <https://help.semmle.com/qldoc/cpp/>`__.
CodeQL query: bad overflow guards
=================================
We want to ensure the operands being added have size less than 4 bytes.
We may want to reuse this logic, so let us create a separate predicate.
Looking at autocomplete suggestions, we see that we can get the type of an expression using the ``getType()`` method.
We can get the size (in bytes) of a type using the ``getSize()`` method.
.. rst-class:: build
.. code-block:: ql
predicate isSmall(Expr e) {
e.getType().getSize() < 4
}
.. note::
- An important part of the query is to determine whether a given expression has a “small” type that is going to trigger integer promotion.
- We therefore write a helper predicate for small expressions.
- This predicate effectively represents the set of all expressions in the database where the size of the type of the expression is less than 4 bytes, that is, less than 32-bits.
CodeQL query: bad overflow guards
==================================
We can ensure the operands being added have size less than 4 bytes, using our new predicate.
QL has logical quantifiers like ``exists`` and ``forall``, allowing us to declare variables and enforce a certain condition on them.
Now our query becomes:
.. rst-class:: build
.. literalinclude:: ../query-examples/cpp/bad-overflow-guard-2.ql
:language: ql
.. note::
- Recall from earlier that what makes an overflow check a “bad” check is that all the arguments to the addition are integers smaller than 32-bits.
- We could write this by using our helper predicate ``isSmall`` to specify that each individual operand to the addition ``isSmall`` (that is under 32-bits):
.. code-block:: ql
isSmall(a.getLeftOperand()) and
isSmall(a.getRightOperand())
- However, this is a little bit repetitive. What we really want to say is that: all the operands of the addition are small. Fortunately, QL provides a ``forall`` formula that we can use in these circumstances.
- A ``forall`` has three parts:
- A “declaration” part, where we can introduce variables.
- A “range” part, which allows us to restrict those variables.
- A “condition” part. The ``forall`` as a whole holds if the condition holds for each of the values in the range.
- In our case:
- The declaration introduces a variable for expressions, called ``op``. At this stage, this variable represents all the expressions in the program.
- The “range” part, ``op = a.getAnOperand()``, restricts ``op`` to being one of the two operands to the addition.
- The “condition” part, ``isSmall(op)``, says that the ``forall`` holds only if the condition (that the ``op`` is small) holds for everything in the rangethat is, both the arguments to the addition.
CodeQL query: bad overflow guards
=================================
Sometimes the result of the addition is cast to a small type of size less than 4 bytes, preventing automatic widening. We dont want our query to flag these instances.
We can use predicate ``Expr.getExplicitlyConverted()`` to reason about casts that are applied to an expression, adding this restriction to our query:
.. code-block:: ql
not isSmall(a.getExplicitlyConverted())
The final query
===============
.. literalinclude:: ../query-examples/cpp/bad-overflow-guard-3.ql
:language: ql
This query finds a single result in our historic database, which was `a genuine bug in ChakraCore <https://github.com/Microsoft/ChakraCore/commit/2500e1cdc12cb35af73d5c8c9b85656aba6bab4d>`__.

View File

@@ -0,0 +1,367 @@
======================
Analyzing control flow
======================
CodeQL for C/C++
.. Include information slides here
.. rst-class:: setup
Setup
=====
For this example you should download:
- `CodeQL for Visual Studio Code <https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html>`__
- `ChakraCore database <https://downloads.lgtm.com/snapshots/cpp/microsoft/chakracore/ChakraCore-revision-2017-April-12--18-13-26.zip>`__
.. note::
For the examples in this presentation, we will be analyzing `ChakraCore <https://github.com/microsoft/ChakraCore>`__.
You can query the project in `the query console <https://lgtm.com/query/project:2034240708/lang:cpp/>`__ on LGTM.com.
.. insert database-note.rst to explain differences between database available to download and the version available in the query console.
.. include:: ../slide-snippets/database-note.rst
.. resume slides
.. rst-class:: agenda
Agenda
======
- Control flow graphs
- Exercise: use after free
- Recursion over the control flow graph
- Basic blocks
- Guard conditions
Control flow graphs
===================
.. container:: column-left
We frequently want to ask questions about the possible *order of execution* for a program.
Example:
.. code-block:: cpp
if (x) {
return 1;
} else {
return 2;
}
.. container:: column-right
Possible execution order is usually represented by a *control flow graph*:
.. graphviz::
digraph {
graph [ dpi = 1000 ]
node [shape=polygon,sides=4,color=blue4,style="filled,rounded",fontname=consolas,fontcolor=white]
a [label=<if<BR /><FONT POINT-SIZE="10">IfStmt</FONT>>]
b [label=<x<BR /><FONT POINT-SIZE="10">VariableAccess</FONT>>]
c [label=<1<BR /><FONT POINT-SIZE="10">Literal</FONT>>]
d [label=<2<BR /><FONT POINT-SIZE="10">Literal</FONT>>]
e [label=<return<BR /><FONT POINT-SIZE="10">ReturnStmt</FONT>>]
f [label=<return<BR /><FONT POINT-SIZE="10">ReturnStmt</FONT>>]
a -> b
b -> {c, d}
c -> e
d -> f
}
.. note::
The control flow graph is a static over-approximation of possible control flow at runtime.
Its nodes are program elements such as expressions and statements.
If there is an edge from one node to another, then it means that the semantic operation corresponding to the first node may be immediately followed by the operation corresponding to the second node.
Some nodes (such as conditions of “if” statements or loop conditions) have more than one successor, representing conditional control flow at runtime.
Modeling control flow
=====================
The control flow is modeled with a CodeQL class, ``ControlFlowNode``. Examples of control flow nodes include statements and expressions.
- ``ControlFlowNode`` provides API for traversing the control flow graph:
- ``ControlFlowNode ControlFlowNode.getASuccessor()``
- ``ControlFlowNode ControlFlowNode.getAPredecessor()``
- ``ControlFlowNode ControlFlowNode.getATrueSuccessor()``
- ``ControlFlowNode ControlFlowNode.getAFalseSuccessor()``
The control-flow graph is *intra-procedural*in other words, only models paths within a function. To find the associated function, use
- ``Function ControlFlowNode.getControlFlowScope()``
.. note::
The control flow graph is similar in concept to data flow graphs. In contrast to data flow, however, the AST nodes are directly control flow graph nodes.
The predecessor/successor predicates are prime examples of member predicates with results that are used in functional syntax, but that are not actually functions. This is because a control flow node may have any number of predecessors and successors (including zero or more than one).
Example: malloc/free pairs
==========================
Find calls to ``free`` that are reachable from an allocation on the same variable:
.. literalinclude:: ../query-examples/cpp/control-flow-cpp-1.ql
:language: ql
.. note::
Predicates ``allocationCall`` and ``freeCall`` are defined in the standard library and model a number of standard alloc/free-like functions.
Exercise: use after free
========================
Based on this query, write a query that finds accesses to the variable that occur after the free.
.. rst-class:: build
- What do you find? What problems occur with this approach to detecting use-after-free vulnerabilities?
.. rst-class:: build
.. literalinclude:: ../query-examples/cpp/control-flow-cpp-2.ql
:language: ql
Utilizing recursion
===================
The main problem we observed in the previous exercise was that the successor's relation is unaware of changes to the variable that would invalidate our results.
We can fix this by writing our own successor predicate that stops traversing the CFG if the variable is re-defined.
Utilizing recursion
===================
.. code-block:: ql
ControlFlowNode reachesWithoutReassignment(FunctionCall free, LocalScopeVariable v)
{
freeCall(free, v.getAnAccess()) and
(
// base case
result = free
or
// recursive case
exists(ControlFlowNode mid |
mid = reachesWithoutReassignment(free, v) and
result = mid.getASuccessor() and
// stop tracking when the value may change
not result = v.getAnAssignedValue() and
not result.(AddressOfExpr).getOperand() = v.getAnAccess()
)
)
}
Exercise
========
Find local variables that are written to, and then never accessed again.
**Hint**: Use ``LocalVariable.getAnAssignment()``.
.. rst-class:: build
.. literalinclude:: ../query-examples/cpp/control-flow-cpp-3.ql
:language: ql
.. rst-class:: background2
More control flow
=================
Basic blocks
============
``BasicBlock`` represents basic blocks, that is, straight-line sequences of control flow nodes without branching.
- ``ControlFlowNode BasicBlock.getNode(int)``
- ``BasicBlock BasicBlock.getASuccessor()``
- ``BasicBlock BasicBlock.getAPredecessor()``
- ``BasicBlock BasicBlock.getATrueSuccessor()``
- ``BasicBlock BasicBlock.getAFalseSuccessor()``
Often, queries can be made more efficient by treating basic blocks as a unit instead of reasoning about individual control flow nodes.
Exercise: unreachable blocks
============================
Write a query to find unreachable basic blocks.
**Hint**: First define a recursive predicate to identify reachable blocks. Class ``EntryBasicBlock`` may be useful.
.. rst-class:: build
.. literalinclude:: ../query-examples/cpp/control-flow-cpp-4.ql
:language: ql
.. note::
This query has a good number of false positives on Chakra, many of them to do with templating and macros.
Guard conditions
================
A ``GuardCondition`` is a ``Boolean`` condition that controls one or more basic blocks in the sense that it is known to be true/false at the entry of those blocks.
- ``GuardCondition.controls(BasicBlock bb, boolean outcome):`` the entry of bb can only be reached if the guard evaluates to outcome
- ``GuardCondition.comparesLt, GuardCondition.ensuresLt, GuardCondition.comparesEq:`` auxiliary predicates to identify conditions that guarantee that one expression is less than/equal to another
Further materials
=================
- CodeQL for C/C++: https://help.semmle.com/QL/learn-ql/ql/cpp/ql-for-cpp.html
- API reference: https://help.semmle.com/qldoc/cpp
.. rst-class:: end-slide
Extra slides
============
.. rst-class:: background2
Appendix: Library customizations
================================
Call graph customizations
=========================
The default implementation of call target resolution does not handle function pointers, because they are difficult to deal with in general.
We can, however, add support for particular patterns of use by contributing a new override of ``Call.getTarget``.
Exercise: unresolvable calls
============================
Write a query that finds all calls for which no call target can be determined, and run it on libjpeg-turbo.
Examine the results. What do you notice?
.. rst-class:: build
.. code-block:: ql
import cpp
from Call c
where not exists(c.getTarget())
select c
.. rst-class:: build
- Many results are calls through struct fields emulating virtual dispatch.
Exercise: resolving calls through variables
===========================================
Write a query that resolves the call at `cjpeg.c:640 <https://github.com/libjpeg-turbo/libjpeg-turbo/blob/9bc8eb6449a32f452ab3fc9f94af672a0af13f81/cjpeg.c#L640>`__.
**Hint**: Use classes ``ExprCall``, ``PointerDereferenceExpr``, and ``Access``.
.. rst-class:: build
.. literalinclude:: ../query-examples/cpp/control-flow-cpp-5.ql
:language: ql
Exercise: customizing the call graph
====================================
Create a subclass of ``ExprCall`` that uses your query to implement ``getTarget``.
.. rst-class:: build
.. code-block:: ql
class CallThroughVariable extends ExprCall {
Variable v;
CallThroughVariable() {
exists(PointerDereferenceExpr callee | callee = getExpr() |
callee.getOperand() = v.getAnAccess()
)
}
override Function getTarget() {
result = super.getTarget() or
exists(Access init | init = v.getAnAssignedValue() |
result = init.getTarget()
)
}
}
Control-flow graph customizations
=================================
The default control-flow graph implementation recognizes a few common patterns for non-returning functions, but sometimes it fails to spot them, which can cause imprecision.
We can add support for new non-returning functions by overriding ``ControlFlowNode.getASuccessor()``.
Exercise: calls to ``error_exit``
=================================
Write a query that finds all calls to a field called ``error_exit``.
**Hint**: Reuse (parts of) the ``CallThroughVariable`` class from before.
.. rst-class:: build
.. code-block:: ql
class CallThroughVariable extends ExprCall { ... }
class ErrorExitCall extends CallThroughVariable {
override Field v;
ErrorExitCall() { v.getName() = "error_exit" }
}
from ErrorExitCall eec
select eec
Exercise: customizing the control-flow graph
============================================
Override ``ControlFlowNode`` to mark calls to ``error_exit`` as non-returning.
**Hint**: ``ExprCall`` is an indirect subclass of ``ControlFlowNode``.
.. rst-class:: build
.. code-block:: ql
class CallThroughVariable extends ExprCall { ... }
class ErrorExitCall extends CallThroughVariable {
override Field v;
ErrorExitCall() { v.getName() = "error_exit" }
override ControlFlowNode getASuccessor() { none() }
}
``CustomOptions`` class
=======================
The Options library defines a ``CustomOptions`` class with various member predicates that can be overridden to customize aspects of the analysis.
In particular, it has an ``exprExits`` predicate that can be overridden to more easily perform the customization on the previous slide:
.. code-block:: ql
import Options
class MyOptions extends CustomOptions {
override predicate exprExits(Expr e) {
super.exprExits(e) or ...
}
}

View File

@@ -0,0 +1,195 @@
=========================
Introduction to data flow
=========================
Finding string formatting vulnerabilities in C/C++
.. rst-class:: setup
Setup
=====
For this example you should download:
- `CodeQL for Visual Studio Code <https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html>`__
- `dotnet/coreclr database <http://downloads.lgtm.com/snapshots/cpp/dotnet/coreclr/dotnet_coreclr_fbe0c77.zip>`__
.. note::
For the examples in this presentation, we will be analyzing `dotnet/coreclr <https://github.com/dotnet/coreclr>`__.
You can query the project in `the query console <https://lgtm.com/query/projects:1505958977333/lang:cpp/>`__ on LGTM.com.
.. insert database-note.rst to explain differences between database available to download and the version available in the query console.
.. include:: ../slide-snippets/database-note.rst
.. resume slides
.. rst-class:: agenda
Agenda
======
- Non-constant format string
- Data flow
- Modules and libraries
- Local data flow
- Local taint tracking
Motivation
==========
Lets write a query to identify instances of `CWE-134 <https://cwe.mitre.org/data/definitions/134.html>`__ **Use of externally controlled format string**.
.. code-block:: cpp
printf(userControlledString, arg1);
**Goal**: Find uses of ``printf`` (or similar) where the format string can be controlled by an attacker.
.. note::
Formatting functions allow the programmer to construct a string output using a *format string* and an optional set of arguments. The *format string* is specified using a simple template language, where the output string is constructed by processing the format string to find *format specifiers*, and inserting values provided as arguments. For example:
.. code-block:: cpp
printf("Name: %s, Age: %d", "Freddie", 2);
would produce the output ``"Name: Freddie, Age: 2”``. So far, so good. However, problems arise if there is a mismatch between the number of formatting specifiers, and the number of arguments. For example:
.. code-block:: cpp
printf("Name: %s, Age: %d", "Freddie");
In this case, we have one more format specifier than we have arguments. In a managed language such as Java or C#, this simply leads to a runtime exception. However, in C/C++, the formatting functions are typically implemented by reading values from the stack without any validation of the number of arguments. This means a mismatch in the number of format specifiers and format arguments can lead to information disclosure.
Of course, in practice this happens rarely with *constant* formatting strings. Instead, its most problematic when the formatting string can be specified by the user, allowing an attacker to provide a formatting string with the wrong number of format specifiers. Furthermore, if an attacker can control the format string, they may be able to provide the ``%n`` format specifier, which causes ``printf`` to write the number characters in the generated output string to a specified location.
See https://en.wikipedia.org/wiki/Uncontrolled_format_string for more background.
Exercise: Non-constant format string
====================================
Write a query that flags ``printf`` calls where the format argument is not a ``StringLiteral``.
**Hint**: Import ``semmle.code.cpp.commons.Printf`` and use class ``FormattingFunction`` and ``getFormatParameterIndex()``.
.. rst-class:: build
.. literalinclude:: ../query-examples/cpp/data-flow-cpp-1.ql
:language: ql
.. note::
This first query is about finding places where the format specifier is not a constant string. In the CodeQL libraries for C/C++, constant strings are modeled as ``StringLiteral`` nodes, so we are looking for calls to format functions where the format specifier argument is not a string literal.
The `C/C++ standard libraries <https://help.semmle.com/qldoc/cpp/>`__ include many different formatting functions that may be vulnerable to this particular attackincluding ``printf``, ``snprintf``, and others. Furthermore, each of these different formatting functions may include the format string in a different position in the argument list. Instead of laboriously listing all these different variants, we can make use of the standard CodeQL class ``FormattingFunction``, which provides an interface that models common formatting functions in C/C++.
Meh...
======
Results are unsatisfactory:
- Query flags cases where the format string is a symbolic constant.
- Query flags cases where the format string is itself a format argument.
- Query doesn't recognize wrapper functions around ``printf``-like functions.
We need something better.
.. note::
For example, consider the results which appear in ``/src/ToolBox/SOS/Strike/util.h``, between lines 965 and 970:
.. code-block:: cpp
const char *format = align == AlignLeft ? "%-*.*s" : "%*.*s";
if (IsDMLEnabled())
DMLOut(format, width, precision, mValue);
else
ExtOut(format, width, precision, mValue);
Here, ``DMLOut`` and ``ExtOut`` are macros that expand to formatting calls. The format specifier is not constant, in the sense that the format argument is not a string literal. However, it is clearly one of two possible constants, both with the same number of format specifiers.
What we need is a way to determine whether the format argument is ever set to something that is not constant.
.. include general data flow slides
.. include:: ../slide-snippets/local-data-flow.rst
.. resume language-specific slides
Exercise: source nodes
======================
Define a subclass of ``DataFlow::Node`` representing “source” nodes, that is, nodes without a (local) data flow predecessor.
**Hint**: use ``not exists()``.
.. rst-class:: build
.. code-block:: ql
class SourceNode extends DataFlow::Node {
SourceNode() {
not DataFlow::localFlowStep(_, this)
}
}
.. note::
Note the scoping of the `dont-care variable <https://help.semmle.com/QL/ql-handbook/expressions.html#don-t-care-expressions>`__ “_” in this example: the body of the characteristic predicate is equivalent to:
.. code-block:: ql
not exists(DataFlow::Node pred | DataFlow::localFlowStep(pred, this))
which is not the same as:
.. code-block:: ql
exists(DataFlow::Node pred | not DataFlow::localFlowStep(pred, this)).
Revisiting non-constant format strings
======================================
Refine the query to find calls to ``printf``-like functions where the format argument derives from a local source that is not a constant string.
.. rst-class:: build
.. code-block:: ql
import cpp
import semmle.code.cpp.dataflow.DataFlow
import semmle.code.cpp.commons.Printf
class SourceNode extends DataFlow::Node { ... }
from FormattingFunction f, Call c, SourceNode src, DataFlow::Node arg
where c.getTarget() = f and
arg.asExpr() = c.getArgument(f.getFormatParameterIndex()) and
DataFlow::localFlow(src, arg) and
not src.asExpr() instanceof StringLiteral
select arg, "Non-constant format string."
Refinements (take home exercise)
================================
Audit the results and apply any refinements you deem necessary.
Suggestions:
- Replace ``DataFlow::localFlowStep`` with a custom predicate that includes steps through global variable definitions.
**Hint**: Use class ``GlobalVariable`` and its member predicates ``getAnAssignedValue()`` and ``getAnAccess()``.
- Exclude calls in wrapper functions that just forward their format argument to another ``printf``-like function; instead, flag calls to those functions.
Beyond local data flow
======================
- Results are still underwhelming.
- Dealing with parameter passing becomes cumbersome.
- Instead, lets turn the problem around and find user-controlled data that flows into a ``printf`` format argument, potentially through calls.
- This needs :doc:`global data flow <global-data-flow-cpp>`.

View File

@@ -0,0 +1,191 @@
================================
Introduction to global data flow
================================
CodeQL for C/C++
.. rst-class:: setup
Setup
=====
For this example you should download:
- `CodeQL for Visual Studio Code <https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html>`__
- `dotnet/coreclr database <http://downloads.lgtm.com/snapshots/cpp/dotnet/coreclr/dotnet_coreclr_fbe0c77.zip>`__
.. note::
For the examples in this presentation, we will be analyzing `dotnet/coreclr <https://github.com/dotnet/coreclr>`__.
You can query the project in `the query console <https://lgtm.com/query/projects:1505958977333/lang:cpp/>`__ on LGTM.com.
.. insert database-note.rst to explain differences between database available to download and the version available in the query console.
.. include:: ../slide-snippets/database-note.rst
.. resume slides
.. rst-class:: agenda
Agenda
======
- Global taint tracking
- Sanitizers
- Path queries
- Data flow models
.. insert common global data flow slides
.. include:: ../slide-snippets/global-data-flow.rst
.. resume language-specific global data flow slides
Finding tainted format strings (outline)
========================================
.. literalinclude:: ../query-examples/cpp/global-data-flow-cpp-1.ql
:language: ql
.. note::
Heres the outline for a inter-procedural (that is, “global”) version of the tainted formatting strings query we saw in the previous slide deck. The same template will be applicable for most taint tracking problems.
Defining sources
================
The library class ``SecurityOptions`` provides a (configurable) model of what counts as user-controlled data:
.. code-block:: ql
import semmle.code.cpp.security.Security
class TaintedFormatConfig extends TaintTracking::Configuration {
override predicate isSource(DataFlow::Node source) {
exists (SecurityOptions opts |
opts.isUserInput(source.asExpr(), _)
)
}
...
}
.. note::
We first define what it means to be a *source* of tainted data for this particular problem. In this case, what we care about is whether the format string can be provided by an external user to our application or service. As there are many such ways external data could be introduced into the system, the standard CodeQL libraries for C/C++ include an extensible API for modeling user input. In this case, we will simply use the predefined set of *user inputs*, which includes arguments provided to command line applications.
Defining sinks (exercise)
=========================
Use the ``FormattingFunction`` class to fill in the definition of ``isSink``.
.. code-block:: ql
import semmle.code.cpp.security.Security
class TaintedFormatConfig extends TaintTracking::Configuration {
override predicate isSink(DataFlow::Node sink) {
/* Fill me in */
}
...
}
.. note::
The second part is to define what it means to be a sink for this particular problem. The queries from the previous slide deck will be useful for this exercise.
Defining sinks (answer)
=======================
Use the ``FormattingFunction`` class, we can write the sink as:
.. code-block:: ql
import semmle.code.cpp.security.Security
class TaintedFormatConfig extends TaintTracking::Configuration {
override predicate isSink(DataFlow::Node sink) {
exists (FormattingFunction ff, Call c |
c.getTarget() = ff and
c.getArgument(ff.getFormatParameterIndex()) = sink.asExpr()
)
}
...
}
.. note::
When we run this query, we should find a single result. However, it is tricky to determine whether this result is a true positive (a “real” result) because our query only reports the source and the sink, and not the path through the graph between the two.
.. insert path queries slides
.. include:: ../slide-snippets/path-queries.rst
.. resume language-specific global data flow slides
Defining additional taint steps
===============================
Add an additional taint step that (heuristically) taints a local variable if it is a pointer, and it is passed to a function in a parameter position that taints it.
.. code-block:: ql
class TaintedFormatConfig extends TaintTracking::Configuration {
override predicate isAdditionalTaintStep(DataFlow::Node pred,
DataFlow::Node succ) {
exists (Call c, Expr arg, LocalVariable lv |
arg = c.getAnArgument() and
arg = pred.asExpr() and
arg.getFullyConverted().getUnderlyingType() instanceof PointerType and
arg = lv.getAnAccess() and
succ.asUninitialized() = lv
)
}
...
}
Defining sanitizers
===================
Add a sanitizer, stopping propagation at parameters of formatting functions, to avoid double-reporting:
.. code-block:: ql
class TaintedFormatConfig extends TaintTracking::Configuration {
override predicate isSanitizer(DataFlow::Node nd) {
exists (FormattingFunction ff, int idx |
idx = ff.getFormatParameterIndex() and
nd = DataFlow::parameterNode(ff.getParameter(idx))
)
}
...
}
Data flow models
================
- To provide models of data/taint flow through library functions, you can implement subclasses of ``DataFlowFunction`` (from ``semmle.code.cpp.models.interfaces.DataFlow``) and ``TaintFunction`` (from ``semmle.code.cpp.models.interfaces.Taint``), respectively
- Example: model of taint flow from third to first parameter of ``memcpy``
.. code-block:: ql
class MemcpyFunction extends TaintFunction {
MemcpyFunction() { this.hasName("memcpy") }
override predicate hasTaintFlow(FunctionInput i, FunctionOutput o)
i.isInParameter(2) and o.isOutParameterPointer(0)
}
}
.. note::
See the API documentation for more details about ``FunctionInput`` and ``FunctionOutput``.
.. rst-class:: end-slide
Extra slides
============
.. include:: ../slide-snippets/global-data-flow-extra-slides.rst

View File

@@ -0,0 +1,208 @@
================================
Introduction to variant analysis
================================
CodeQL for C/C++
.. rst-class:: setup
Setup
=====
For this example you should download:
- `CodeQL for Visual Studio Code <https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html>`__
- `exiv2 database <http://downloads.lgtm.com/snapshots/cpp/exiv2/Exiv2_exiv2_b090f4d.zip>`__
.. note::
For this example, we will be analyzing `exiv2 <https://github.com/Exiv2/exiv2>`__.
You can also query the project in `the query console <https://lgtm.com/query/project:1506532406873/lang:cpp/>`__ on LGTM.com.
.. insert database-note.rst to explain differences between database available to download and the version available in the query console.
.. include:: ../slide-snippets/database-note.rst
.. resume slides
.. Include language-agnostic section here
.. include:: ../slide-snippets/intro-ql-general.rst
Oops
====
.. code-block:: cpp
:emphasize-lines: 3
int write(int buf[], int size, int loc, int val) {
if (loc >= size) {
// return -1;
}
buf[loc] = val;
return 0;
}
- The return statement has been commented out (during debugging?)
- The if statement is now dead code
- No bounds checking!
.. note::
Heres a simple (artificial) bug, which well develop a query to catch.
This function writes a value to a given location in an array, first trying to do a bounds check to validate that the location is within bounds. However, the return statement has been commented out, leaving a redundant if statement and no bounds checking.
This case can act as our “patient zero” in the variant analysis game.
A simple CodeQL query
=====================
.. literalinclude:: ../query-examples/cpp/empty-if-cpp.ql
:language: ql
.. note::
We are going to write a simple query which finds “if statements” with empty “then” blocks, so we can highlight the results like those on the previous slide. The query can be run in the `query console on LGTM <https://lgtm.com/query>`__, or in your `IDE <https://lgtm.com/help/lgtm/running-queries-ide>`__.
A `query <https://help.semmle.com/QL/ql-handbook/queries.html>`__ consists of a “select” clause that indicates what results should be returned. Typically it will also provide a “from” clause to declare some variables, and a “where” clause to state conditions over those variables. For more information on the structure of query files (including links to useful topics in the `QL language reference <https://help.semmle.com/QL/ql-handbook/index.html>`__), see `About CodeQL queries <https://help.semmle.com/QL/learn-ql/ql/writing-queries/introduction-to-queries.html>`__.
In our example here, the first line of the query imports the `CodeQL library for C/C++ <https://help.semmle.com/qldoc/cpp/>`__, which defines concepts like ``IfStmt`` and ``Block``.
The query proper starts by declaring two variablesifStmt and block. These variables represent sets of values in the database, according to the type of each of the variables. For example, ifStmt has the type IfStmt, which means it represents the set of all if statements in the program.
If we simply selected these two variables::
from IfStmt ifStmt, Block block
select ifStmt, block
We would get a result row for every combination of blocks and if statements in the program. This is known as a cross-product, because there is no logical condition linking the two variables. We can use the where clause to specify the condition that we are only interested in rows where the “block” is the “then” part of the if statement. We do this by specifying::
block = ifStmt.getThen()
This states that the block is equal to (not assigned!) the “then” part of the ``ifStmt``. ``getThen()`` is an operation which is available on any IfStmt. One way to interpret this is as a filtering operation starting with every pair of block and if statements, check each one to whether the logical condition holds, and only keep the row if that is the case.
We can add a second condition that specifies the block must be empty::
and block.isEmpty()
The ``isEmpty()`` operation is available on any Block, and is only true if the “block” has no children.
Finally, we select a location, at which to report the problem, and a message, to explain what the problem is.
Structure of a query
====================
A **query file** has the extension ``.ql`` and contains a **query clause**, and optionally **predicates**, **classes**, and **modules**.
A **query library** has the extension ``.qll`` and does not contain a query clause, but may contain modules, classes, and predicates.
Each query library also implicitly defines a module.
**Import** statements allow the classes and predicates defined in one module to be used in another.
.. note::
Queries are always contained in query files with the file extension ``.ql``.
Parts of queries can be lifted into `library files <https://help.semmle.com/QL/ql-handbook/modules.html#library-modules>`__ with the extension ``.qll``. Definitions within such libraries can be brought into scope using ``import`` statements, and similarly QLL files can import each others definitions using “import” statements.
Logic can be encapsulated as user-defined `predicates <https://help.semmle.com/QL/ql-handbook/predicates.html>`__ and `classes <https://help.semmle.com/QL/ql-handbook/types.html#classes>`__, and organized into `modules <https://help.semmle.com/QL/ql-handbook/modules.html>`__. Each QLL file implicitly defines a module, but QL and QLL files can also contain explicit module definitions, as we will see later.
Predicates
==========
A predicate allows you to pull out and name parts of a query.
.. container:: column-left
.. literalinclude:: ../query-examples/cpp/empty-if-cpp.ql
:language: ql
:emphasize-lines: 6
.. container:: column-right
.. literalinclude:: ../query-examples/cpp/empty-if-cpp-predicate.ql
:language: ql
:emphasize-lines: 3-5
.. note::
A `predicate <https://help.semmle.com/QL/ql-handbook/predicates.html>`__ takes zero or more parameters, and its body is a condition on those parameters. The predicate may (or may not) hold. Predicates may also be `recursive <https://help.semmle.com/QL/ql-handbook/predicates.html#recursive-predicates>`__, simply by referring to themselves (directly or indirectly).
You can imagine a predicate to be a self-contained from-where-select statement, that produces an intermediate relation, or table. In this case, the ``isEmpty`` predicate will be the set of all blocks which are empty.
Classes in QL
=============
A QL class allows you to name a set of values and define (member) predicates on them.
A class has at least one supertype and optionally a **characteristic predicate**; it contains the values that belong to *all* supertypes *and* satisfy the characteristic predicate, if provided.
Member predicates are inherited and can be overridden.
.. code-block:: ql
class EmptyBlock extends Block {
EmptyBlock() {
this.getNumStmt() = 0
}
}
.. note::
`Classes <https://help.semmle.com/QL/ql-handbook/types.html#classes>`__ model sets of values from the database. A class has one or more supertypes, and inherits `member predicates <https://help.semmle.com/QL/ql-handbook/types.html#member-predicates>`__ (methods) from each of them. Each value in a class must be in every supertype, but additional conditions can be stated in a so-called **characteristic predicate**, which looks a bit like a zero-argument constructor.
In the example, declaring a variable “EmptyBlock e” will allow it to range over only those blocks that have zero statements.
Classes in QL continued
=======================
.. container:: column-left
.. literalinclude:: ../query-examples/cpp/empty-if-cpp-predicate.ql
:language: ql
:emphasize-lines: 3-5
.. container:: column-right
.. literalinclude:: ../query-examples/cpp/empty-if-cpp-class.ql
:language: ql
:emphasize-lines: 3-7
.. note::
As shown in this example, classes behave much like unary predicates, but with ``instanceof`` instead of predicate calls to check membership. Later on, we will see how to define member predicates on classes.
Iterative query refinement
==========================
- **Common workflow**: Start with a simple query, inspect a few results, refine, repeat.
- For example, empty then branches are not a problem if there is an else.
- **Exercise**: How can we refine the query to take this into account?
**Hints**:
- Use member predicate ``IfStmt.getElse()``
- Use ``not exists(...)``
.. note::
CodeQL makes it very easy to experiment with analysis ideas. A common workflow is to start with a simple query (like our “redundant if-statement” example), examine a few results, refine the query based on any patterns that emerge and repeat.
As an exercise, refine the redundant-if query based on the observation that if the if-statement has an “else” clause, then even if the body of the “then” clause is empty, its not actually redundant.
Model answer: redundant if-statement
=====================================
.. literalinclude:: ../query-examples/cpp/empty-if-cpp-model.ql
.. note::
You can explore the results generated when this query is run on exiv2 in LGTM `here <https://lgtm.com/query/4641433299746527262/>`__.

View File

@@ -0,0 +1,120 @@
======================
Program representation
======================
CodeQL for C/C++
.. rst-class:: agenda
Agenda
======
- Abstract syntax trees
- Database representation
- Symbol tables
- Variables
- Functions
.. insert abstract-syntax-tree.rst
.. include:: ../slide-snippets/abstract-syntax-tree.rst
.. resume slides
AST CodeQL classes
==================
Important AST CodeQL classes include:
- ``Expr``: expressions such as assignments, variable references, function calls, ...
- ``Stmt``: statements such as conditionals, loops, try statements, ...
- ``DeclarationEntry``: places where functions, variables or types are declared and/or defined
These three (and all other AST CodeQL classes) are subclasses of ``Element``.
Symbol table
============
The database also includes information about the symbol table associated with a program:
- ``Variable``: all variables, including local variables, global variables, static variables and member variables
- ``Function``: all functions, including member function
- ``Type``: built-in and user-defined types
Working with variables
======================
``Variable`` represents program variables, including locally scoped variables (``LocalScopeVariable``), global variables (``GlobalVariable``), and others:
- ``string Variable.getName()``
- ``Type Variable.getType()``
``Access`` represents references to declared entities such as functions (``FunctionAccess``) and variables (``VariableAccess``), including fields (``FieldAccess``).
- ``Declaration Access.getTarget()``
``VariableDeclarationEntry`` represents declarations or definitions of a variable.
- ``Variable VariableDeclarationEntry.getVariable()``
Working with functions
======================
Functions are represented by the Function class. Each declaration or definition of a function is represented by a ``FunctionDeclarationEntry``.
Calls to functions are modeled by the CodeQL class ``Call`` and its subclasses:
- ``Call.getTarget()`` gets the declared target of the call; undefined for calls through function pointers
- ``Function.getACallToThisFunction()`` gets a call to this function
Typically, functions are identified by name:
- ``string Function.getName()``
- ``string Function.getQualifiedName()``
Working with preprocessor logic
===============================
Macros and other preprocessor directives can easily cause confusion when analyzing programs:
- AST structure reflects the program *after* preprocessing.
- Locations refer to the original source text *before* preprocessing.
For example, in:
.. code-block:: cpp
#define square(x) x*x
y = square(y0), z = square(z0)
there are no AST nodes corresponding to ``square(y0)`` or ``square(z0)``, but there are AST nodes corresponding to ``y0*y0`` and ``z0*z0``.
.. note::
The C preprocessor poses a dilemma: un-preprocessed code cannot, in general, be parsed and analyzed meaningfully, but showing results in preprocessed code is not useful to developers. Our solution is to base the AST representation on preprocessed source (in the same way as compilers do), but associate AST nodes with locations in the original source text.
Working with macros
===================
.. code-block:: cpp
#define square(x) x*x
y = square(y0), z = square(z0)
is represented in the CodeQL database as:
- A Macro entity representing the text of the *head* and *body* of the macro
- Assignment nodes, representing the two assignments after preprocessing
- Left-hand sides are ``VariableAccess`` nodes of y and z
- Right-hand sides are ``MulExpr`` nodes representing ``y0*y0`` and ``z0*z0``
- A ``MacroAccess`` entity, which associates the Macro with the ``MulExprs``
Useful predicates on ``Element``: ``isInMacroExpansion()``, ``isAffectedByMacro()``
.. note::
The CodeQL database also contains information about macro definitions, which are represented by class ``Macro``. These macro definitions are related to the AST nodes resulting from their uses by the class ``MacroAccess``.

View File

@@ -0,0 +1,101 @@
===============================
Exercise: ``snprintf`` overflow
===============================
CodeQL for C/C++
.. rst-class:: setup
Setup
=====
For this example you should download:
- `CodeQL for Visual Studio Code <https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html>`__
- `rsyslog database <https://downloads.lgtm.com/snapshots/cpp/rsyslog/rsyslog/rsyslog-all-revision-2018-April-27--14-12-31.zip>`__
.. note::
For this example, we will be analyzing `rsyslog <https://github.com/rsyslog/rsyslog>`__.
You can also query the project in `the query console <https://lgtm.com/query/project:1506087977050/lang:cpp/>`__ on LGTM.com.
.. insert database-note.rst to explain differences between database available to download and the version available in the query console.
.. include:: ../slide-snippets/database-note.rst
.. resume slides
``snprintf``
============
.. rst-class:: build
- ``printf``: Returns number of characters printed.
.. code-block:: cpp
printf("Hello %s!", name)
- ``sprintf``: Returns number of characters written to ``buf``.
.. code-block:: cpp
sprintf(buf, "Hello %s!", name)
- ``snprintf``: Returns number of characters it **would have written** to ``buf`` had ``n`` been sufficiently large, **not** the number of characters actually written.
.. code-block:: cpp
snprintf(buf, n, "Hello %s!", name)
- In pre-C99 versions of glibc ``snprintf`` would return -1 if ``n`` was too small!
RCE in rsyslog
==============
- Vulnerable code looked similar to this (`original <https://github.com/rsyslog/librelp/blob/532aa362f0f7a8d037505b0a27a1df452f9bac9e/src/tcp.c#L1195-L1211>`__):
.. code-block:: cpp
char buf[1024];
int pos = 0;
for (int i = 0; i < n; i++) {
pos += snprintf(buf + pos, sizeof(buf) - pos, "%s", strs[i]);
}
- Disclosed as `CVE-2018-1000140 <https://nvd.nist.gov/vuln/detail/CVE-2018-1000140>`__.
- Blog post: https://securitylab.github.com/research/librelp-buffer-overflow-cve-2018-1000140
Finding the RCE yourself
========================
#. Write a query to find calls to ``snprintf``
**Hint**: Use class ``FunctionCall``
#. Restrict to calls whose result is used
**Hint**: Use class ``ExprInVoidContext``
#. Restrict to calls where the format string contains “%s”
**Hint**: Use predicates ``Expr.getValue`` and ``string.regexpMatch``
#. Restrict to calls where the result flows back to the size argument
**Hint**: Import library ``semmle.code.cpp.dataflow.TaintTracking`` and use predicate ``TaintTracking::localTaint``
Model answer
============
.. literalinclude:: ../query-examples/cpp/snprintf-1.ql
:language: ql
.. rst-class:: build
- More full-featured version: `https://lgtm.com/rules/1505913226124 <https://lgtm.com/rules/1505913226124>`__.
.. note::
The regular expression for matching the format string uses the “(?s)” directive to ensure that “.” also matches any newline characters embedded in the string.

View File

@@ -0,0 +1,10 @@
CodeQL training and variant analysis examples
=============================================
.. toctree::
:glob:
:maxdepth: 1
:hidden:
*
*/**

View File

@@ -0,0 +1,137 @@
=======================
Exercise: Apache Struts
=======================
.. container:: subheading
Unsafe deserialization leading to an RCE
CVE-2017-9805
.. rst-class:: setup
Setup
=====
For this example you should download:
- `CodeQL for Visual Studio Code <https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html>`__
- `Apache Struts database <https://downloads.lgtm.com/snapshots/java/apache/struts/apache-struts-7fd1622-CVE-2018-11776.zip>`__
.. note::
For this example, we will be analyzing `Apache Struts <https://github.com/apache/struts>`__.
You can also query the project in `the query console <https://lgtm.com/query/project:1878521151/lang:java/>`__ on LGTM.com.
.. insert database-note.rst to explain differences between database available to download and the version available in the query console.
.. include:: ../slide-snippets/database-note.rst
.. resume slides
Unsafe deserialization in Struts
================================
Apache Struts provides a ``ContentTypeHandler`` interface, which can be implemented for specific content types. It defines the following interface method:
.. code-block:: java
void toObject(Reader in, Object target);
which is intended to populate the ``target`` object with data from the reader, usually through deserialization. However, the ``in`` parameter should be considered untrusted, and should not be deserialized without sanitization.
RCE in Apache Struts
====================
- Vulnerable code looked like this (`original <https://lgtm.com/projects/g/apache/struts/snapshot/b434c23f95e0f9d5bde789bfa07f8fc1d5a8951d/files/plugins/rest/src/main/java/org/apache/struts2/rest/handler/XStreamHandler.java?sort=name&dir=ASC&mode=heatmap#L45>`__):
.. code-block:: java
public void toObject(Reader in, Object target) {
XStream xstream = createXStream();
xstream.fromXML(in, target);
}
- Xstream allows deserialization of **dynamic proxies**, which permit remote code execution.
- Disclosed as `CVE-2017-9805 <http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-9805>`__
- Blog post: https://securitylab.github.com/research/apache-struts-vulnerability-cve-2017-9805
Finding the RCE yourself
========================
#. Create a class to find the interface ``org.apache.struts2.rest.handler.ContentTypeHandler``
**Hint**: Use predicate ``hasQualifiedName(...)``
#. Identify methods called ``toObject``, which are defined on direct subtypes of ``ContentTypeHandler``
**Hint**: Use ``Method.getDeclaringType()`` and ``Type.getASupertype()``
#. Implement a ``DataFlow::Configuration``, defining the source as the first parameter of a ``toObject`` method, and the sink as an instance of ``UnsafeDeserializationSink``.
**Hint**: Use ``Node::asParameter()``
#. Construct the query as a path-problem query, and verify you find one result.
Model answer, step 1
====================
.. code-block:: ql
import java
/** The interface `org.apache.struts2.rest.handler.ContentTypeHandler`. */
class ContentTypeHandler extends RefType {
ContentTypeHandler() {
this.hasQualifiedName("org.apache.struts2.rest.handler", "ContentTypeHandler")
}
}
Model answer, step 2
====================
.. code-block:: ql
/** A `toObject` method on a subtype of `org.apache.struts2.rest.handler.ContentTypeHandler`. */
class ContentTypeHandlerDeserialization extends Method {
ContentTypeHandlerDeserialization() {
this.getDeclaringType().getASupertype() instanceof ContentTypeHandler and
this.hasName("toObject")
Model answer, step 3
====================
.. code-block:: ql
import UnsafeDeserialization
import semmle.code.java.dataflow.DataFlow::DataFlow
/**
* Configuration that tracks the flow of taint from the first parameter of
* `ContentTypeHandler.toObject` to an instance of unsafe deserialization.
*/
class StrutsUnsafeDeserializationConfig extends Configuration {
StrutsUnsafeDeserializationConfig() { this = "StrutsUnsafeDeserializationConfig" }
override predicate isSource(Node source) {
source.asParameter() = any(ContentTypeHandlerDeserialization des).getParameter(0)
}
override predicate isSink(Node sink) { sink instanceof UnsafeDeserializationSink }
}
Model answer, step 4
====================
.. code-block:: ql
import PathGraph
...
from PathNode source, PathNode sink, StrutsUnsafeDeserializationConfig conf
where conf.hasFlowPath(source, sink)
and sink.getNode() instanceof UnsafeDeserializationSink
select sink.getNode().(UnsafeDeserializationSink).getMethodAccess(), source, sink, "Unsafe deserialization of $@.", source, "user input"
More full-featured version: https://github.com/github/security-lab/tree/main/CodeQL_Queries/java/Apache_Struts_CVE-2017-9805

View File

@@ -0,0 +1,142 @@
=========================
Introduction to data flow
=========================
Finding SPARQL injection vulnerabilities in Java
.. rst-class:: setup
Setup
=====
For this example you should download:
- `CodeQL for Visual Studio Code <https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html>`__
- `VIVO Vitro database <http://downloads.lgtm.com/snapshots/java/vivo-project/Vitro/vivo-project_Vitro_java-srcVersion_47ae42c01954432c3c3b92d5d163551ce367f510-dist_odasa-lgtm-2019-04-23-7ceff95-linux64.zip>`__
.. note::
For this example, we will be analyzing `VIVO Vitro <https://github.com/vivo-project/Vitro>`__.
You can also query the project in `the query console <https://lgtm.com/query/project:14040005/lang:java/>`__ on LGTM.com.
.. insert database-note.rst to explain differences between database available to download and the version available in the query console.
.. include:: ../slide-snippets/database-note.rst
.. resume slides
.. rst-class:: agenda
Agenda
======
- SPARQL injection
- Data flow
- Modules and libraries
- Local data flow
- Local taint tracking
Motivation
==========
`SPARQL <https://en.wikipedia.org/wiki/SPARQL>`__ is a language for querying key-value databases in RDF format, which can suffer from SQL injection-like vulnerabilities:
.. code-block:: none
sparqlAskQuery("ASK { <" + individualURI + "> ?p ?o }")
``individualURI`` is provided by a user, allowing an attacker to prematurely close the ``>``, and provide additional content.
**Goal**: Find query strings that are created by concatenation.
.. note::
If you have completed the “Example: Query injection” slide deck which was part of the previous course, this example will look familiar to you.
To understand the scope of this vulnerability, consider what would happen if a malicious user could provide the following as the content of the ``individualURI`` variable:
``“http://vivoweb.org/ontology/core#FacultyMember> ?p ?o . FILTER regex("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!", "(.*a){50}") } #``
Example: SPARQL injection
=========================
We can write a simple query that finds string concatenations that occur in calls to SPARQL query APIs.
.. rst-class:: build
.. literalinclude:: ../query-examples/java/data-flow-java-1.ql
:language: ql
.. note::
This is similar, but not identical, to the formulation we had in the previous training deck. It has been rewritten to make it easier for the next step.
Success! But also missing results...
====================================
Query finds a CVE reported by Semmle (CVE-2019-6986), plus one other result, but misses other opportunities where:
- String concatenation occurs on a different line in the same method.
- String concatenation occurs in a different method.
- String concatenation occurs through ``StringBuilders`` or similar.
- Entirety of user input is provided as the query.
We want to improve our query to catch more of these cases.
.. note::
For more details of the CVE, see: https://github.com/Semmle/SecurityExploits/tree/master/vivo-project/CVE-2019-6986
As an example, consider this SPARQL query call:
.. code-block:: none
String queryString = "ASK { <" + individualURI + "> ?p ?o }";
sparqlAskQuery(queryString);
Here the concatenation occurs before the call, so the existing query would miss this - the string concatenation does not occur *directly* as the first argument of the call.
.. include general data flow slides
.. include:: ../slide-snippets/local-data-flow.rst
.. resume language-specific slides
Exercise: revisiting SPARQL injection
=====================================
Refine the query to find string concatenation that occurs in the same method, but a different line.
**Hint**: Use ``DataFlow::localFlow`` to assert that the result flows to the SPARQL call argument, using ``DataFlow::exprNode`` to get the data flow nodes for the relevant expression nodes.
.. rst-class:: build
.. literalinclude:: ../query-examples/java/data-flow-java-2.ql
:language: ql
Refinements (take home exercise)
================================
In Java, strings are often created using ``StringBuilder`` and ``StringBuffer`` classes. For example:
.. code-block:: java
StringBuilder queryBuilder = new StringBuilder();
queryBuilder.add("ASK { <");
queryBuilder.add(individualURI);
queryBuilder.add("> ?p ?o }");
sparqlAskQuery(queryBuilder);
**Exercise**: Refine the query to consider strings created from ``StringBuilder`` and ``StringBuffer`` classes as sources of concatenation.
Beyond local data flow
======================
- We are still missing possible results.
- Concatenation that occurs outside the enclosing method.
- Instead, lets turn the problem around and find user-controlled data that flows into a ``printf`` format argument, potentially through calls.
- This needs :doc:`global data flow <global-data-flow-java>`.

View File

@@ -0,0 +1,186 @@
================================
Introduction to global data flow
================================
CodeQL for Java
.. rst-class:: setup
Setup
=====
For this example you should download:
- `CodeQL for Visual Studio Code <https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html>`__
- `Apache Struts database <https://downloads.lgtm.com/snapshots/java/apache/struts/apache-struts-7fd1622-CVE-2018-11776.zip>`__
.. note::
For this example, we will be analyzing `Apache Struts <https://github.com/apache/struts>`__.
You can also query the project in `the query console <https://lgtm.com/query/project:1878521151/lang:java/>`__ on LGTM.com.
.. insert database-note.rst to explain differences between database available to download and the version available in the query console.
.. include:: ../slide-snippets/database-note.rst
.. resume slides
.. rst-class:: agenda
Agenda
======
- Global taint tracking
- Sanitizers
- Path queries
- Data flow models
.. insert common global data flow slides
.. include:: ../slide-snippets/global-data-flow.rst
.. resume language-specific global data flow slides
Code injection in Apache struts
===============================
- In April 2018, Man Yue Mo, a security researcher at Semmle, reported 5 remote code execution (RCE) vulnerabilities (CVE-2018-11776) in Apache Struts.
- These vulnerabilities were caused by untrusted, unsanitized data being evaluated as an OGNL (Object Graph Navigation Library) expression, allowing malicious users to perform remote code execution.
- Conceptually, this is a global taint tracking problem - does untrusted remote input flow to a method call which evaluates OGNL?
.. note::
More details on the CVE can be found here: https://securitylab.github.com/research/apache-struts-CVE-2018-11776 and
https://github.com/github/security-lab/tree/main/CodeQL_Queries/java/Apache_Struts_CVE-2018-11776
More details on OGNL can be found here: https://commons.apache.org/proper/commons-ognl/
.. rst-class:: java-data-flow-code-example
Code example
============
Finding RCEs (outline)
======================
.. literalinclude:: ../query-examples/java/global-data-flow-java-1.ql
:language: ql
Defining sources
================
We want to look for method calls where the method name is ``getNamespace()``, and the declaring type of the method is a class called ``ActionProxy``.
.. code-block:: ql
import semmle.code.java.security.Security
class TaintedOGNLConfig extends TaintTracking::Configuration {
override predicate isSource(DataFlow::Node source) {
exists(Method m |
m.getName() = "getNamespace" and
m.getDeclaringType().getName() = "ActionProxy" and
source.asExpr() = m.getAReference()
)
}
...
}
.. note::
We first define what it means to be a *source* of tainted data for this particular problem. In this case, we are interested in the value returned by calls to ``getNamespace()``.
Exercise: Defining sinks
========================
Fill in the definition of ``isSink``.
**Hint**: We want to find the first argument of calls to the method ``compileAndExecute``.
.. code-block:: ql
import semmle.code.java.security.Security
class TaintedOGNLConfig extends TaintTracking::Configuration {
override predicate isSink(DataFlow::Node sink) {
/* Fill me in */
}
...
}
.. note::
The second part is to define what it means to be a sink for this particular problem. The queries from an :doc:`Introduction to data flow <data-flow-java>` will be useful for this exercise.
Solution: Defining sinks
========================
Find a method access to ``compileAndExecute``, and mark the first argument.
.. code-block:: ql
import semmle.code.java.security.Security
class TaintedOGNLConfig extends TaintTracking::Configuration {
override predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma |
ma.getMethod().getName() = "compileAndExecute" and
ma.getArgument(0) = sink.asExpr()
)
}
...
}
.. insert path queries slides
.. include:: ../slide-snippets/path-queries.rst
.. resume language-specific global data flow slides
Defining sanitizers
===================
A sanitizer allows us to *prevent* flow through a particular node in the graph. For example, flows that go via ``ValueStackShadowMap`` are not particularly interesting, because it is a class that is rarely used in practice. We can exclude them like so:
.. code-block:: ql
class TaintedOGNLConfig extends TaintTracking::Configuration {
override predicate isSanitizer(DataFlow::Node nd) {
nd.getEnclosingCallable()
.getDeclaringType()
.getName() = "ValueStackShadowMap"
}
...
}
Defining additional taint steps
===============================
Add an additional taint step that (heuristically) taints a local variable if it is a pointer, and it is passed to a function in a parameter position that taints it.
.. code-block:: ql
class TaintedOGNLConfig extends TaintTracking::Configuration {
override predicate isAdditionalTaintStep(DataFlow::Node node1,
DataFlow::Node node2) {
exists(Field f, RefType t |
node1.asExpr() = f.getAnAssignedValue() and
node2.asExpr() = f.getAnAccess() and
node1.asExpr().getEnclosingCallable().getDeclaringType() = t and
node2.asExpr().getEnclosingCallable().getDeclaringType() = t
)
}
...
}
.. rst-class:: end-slide
Extra slides
============
.. include:: ../slide-snippets/global-data-flow-extra-slides.rst

View File

@@ -0,0 +1,207 @@
================================
Introduction to variant analysis
================================
CodeQL for Java
.. rst-class:: setup
Setup
=====
For this example you should download:
- `CodeQL for Visual Studio Code <https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html>`__
- `Apache Struts database <https://downloads.lgtm.com/snapshots/java/apache/struts/apache-struts-7fd1622-CVE-2018-11776.zip>`__
.. note::
For this example, we will be analyzing `Apache Struts <https://github.com/apache/struts>`__.
You can also query the project in `the query console <https://lgtm.com/query/project:1878521151/lang:java/>`__ on LGTM.com.
.. insert database-note.rst to explain differences between database available to download and the version available in the query console.
.. include:: ../slide-snippets/database-note.rst
.. resume slides
.. Include language-agnostic section here
.. include:: ../slide-snippets/intro-ql-general.rst
Oops
====
.. code-block:: java
:emphasize-lines: 3
int write(int[] buf, int size, int loc, int val) {
if (loc >= size) {
// return -1;
}
buf[loc] = val;
return 0;
}
- The return statement has been commented out (during debugging?)
- The ``if`` statement is now dead code
- No explicit bounds checking, will throw ``ArrayIndexOutOfbounds``
.. note::
Heres a simple (artificial) bug, which well develop a query to catch.
This function writes a value to a given location in an array, first trying to do a bounds check to validate that the location is within bounds. However, the return statement has been commented out, leaving a redundant if statement and no bounds checking.
This case can act as our “patient zero” in the variant analysis game.
A simple CodeQL query
=====================
.. literalinclude:: ../query-examples/java/empty-if-java.ql
:language: ql
.. note::
We are going to write a simple query which finds “if statements” with empty “then” blocks, so we can highlight the results like those on the previous slide. The query can be run in the `query console on LGTM <https://lgtm.com/query>`__, or in your `IDE <https://lgtm.com/help/lgtm/running-queries-ide>`__.
A `query <https://help.semmle.com/QL/ql-handbook/queries.html>`__ consists of a “select” clause that indicates what results should be returned. Typically it will also provide a “from” clause to declare some variables, and a “where” clause to state conditions over those variables. For more information on the structure of query files (including links to useful topics in the `QL language reference <https://help.semmle.com/QL/ql-handbook/index.html>`__), see `About CodeQL queries <https://help.semmle.com/QL/learn-ql/ql/writing-queries/introduction-to-queries.html>`__.
In our example here, the first line of the query imports the `CodeQL library for Java <https://help.semmle.com/qldoc/java/>`__, which defines concepts like ``IfStmt`` and ``Block``.
The query proper starts by declaring two variablesifStmt and block. These variables represent sets of values in the database, according to the type of each of the variables. For example, ``ifStmt`` has the type ``IfStmt``, which means it represents the set of all if statements in the program.
If we simply selected these two variables::
from IfStmt ifStmt, Block block
select ifStmt, block
We would get a result row for every combination of blocks and if statements in the program. This is known as a cross-product, because there is no logical condition linking the two variables. We can use the where clause to specify the condition that we are only interested in rows where the “block” is the “then” part of the if statement. We do this by specifying::
block = ifStmt.getThen()
This states that the block is equal to (not assigned!) the “then” part of the ``ifStmt``. ``getThen()`` is an operation which is available on any IfStmt. One way to interpret this is as a filtering operation starting with every pair of block and if statements, check each one to whether the logical condition holds, and only keep the row if that is the case.
We can add a second condition that specifies the block must be empty::
and block.isEmpty()
The ``isEmpty()`` operation is available on any Block, and is only true if the “block” has no children.
Finally, we select a location, at which to report the problem, and a message, to explain what the problem is.
Structure of a query
=====================
A **query file** has the extension ``.ql`` and contains a **query clause**, and optionally **predicates**, **classes**, and **modules**.
A **query library** has the extension ``.qll`` and does not contain a query clause, but may contain modules, classes, and predicates.
Each query library also implicitly defines a module.
**Import** statements allow the classes and predicates defined in one module to be used in another.
.. note::
Queries are always contained in query files with the file extension ``.ql``.
Parts of queries can be lifted into `library files <https://help.semmle.com/QL/ql-handbook/modules.html#library-modules>`__ with the extension ``.qll``. Definitions within such libraries can be brought into scope using “import” statements, and similarly QLL files can import each others definitions using “import” statements.
Logic can be encapsulated as user-defined `predicates <https://help.semmle.com/QL/ql-handbook/predicates.html>`__ and `classes <https://help.semmle.com/QL/ql-handbook/types.html#classes>`__, and organized into `modules <https://help.semmle.com/QL/ql-handbook/modules.html>`__. Each QLL file implicitly defines a module, but QL and QLL files can also contain explicit module definitions, as we will see later.
Predicates
==========
A predicate allows you to pull out and name parts of a query.
.. container:: column-left
.. literalinclude:: ../query-examples/java/empty-if-java.ql
:language: ql
:emphasize-lines: 6
.. container:: column-right
.. literalinclude:: ../query-examples/java/empty-if-java-predicate.ql
:language: ql
:emphasize-lines: 3-5
.. note::
A `predicate <https://help.semmle.com/QL/ql-handbook/predicates.html>`__ takes zero or more parameters, and its body is a condition on those parameters. The predicate may (or may not) hold. Predicates may also be `recursive <https://help.semmle.com/QL/ql-handbook/predicates.html#recursive-predicates>`__, simply by referring to themselves (directly or indirectly).
You can imagine a predicate to be a self-contained from-where-select statement, that produces an intermediate relation, or table. In this case, the ``isEmpty`` predicate will be the set of all blocks which are empty.
Classes in QL
=============
A QL class allows you to name a set of values and define (member) predicates on them.
A class has at least one supertype and optionally a **characteristic predicate**; it contains the values that belong to *all* supertypes *and* satisfy the characteristic predicate, if provided.
Member predicates are inherited and can be overridden.
.. code-block:: ql
class EmptyBlock extends Block {
EmptyBlock() {
this.getNumStmt() = 0
}
}
.. note::
`Classes <https://help.semmle.com/QL/ql-handbook/types.html#classes>`__ model sets of values from the database. A class has one or more supertypes, and inherits `member predicates <https://help.semmle.com/QL/ql-handbook/types.html#member-predicates>`__ (methods) from each of them. Each value in a class must be in every supertype, but additional conditions can be stated in a so-called **characteristic predicate**, which looks a bit like a zero-argument constructor.
In the example, declaring a variable “EmptyBlock e” will allow it to range over only those blocks that have zero statements.
Classes in QL continued
=======================
.. container:: column-left
.. literalinclude:: ../query-examples/java/empty-if-java-predicate.ql
:language: ql
:emphasize-lines: 3-5
.. container:: column-right
.. literalinclude:: ../query-examples/java/empty-if-java-class.ql
:language: ql
:emphasize-lines: 3-7
.. note::
As shown in this example, classes behave much like unary predicates, but with ``instanceof`` instead of predicate calls to check membership. Later on, we will see how to define member predicates on classes.
Iterative query refinement
==========================
- **Common workflow**: Start with a simple query, inspect a few results, refine, repeat.
- For example, empty ``then`` branches are not a problem if there is an ``else``.
- **Exercise**: How can we refine the query to take this into account?
**Hints**:
- Use member predicate ``IfStmt.getElse()``
- Use ``not exists(...)``
.. note::
CodeQL makes it very easy to experiment with analysis ideas. A common workflow is to start with a simple query (like our “redundant if-statement” example), examine a few results, refine the query based on any patterns that emerge and repeat.
As an exercise, refine the redundant-if query based on the observation that if the if-statement has an “else” clause, then even if the body of the “then” clause is empty, its not actually redundant.
Model answer: redundant if-statement
====================================
.. literalinclude:: ../query-examples/java/empty-if-java-model.ql
.. note::
You can explore the results generated when this query is run on apache/struts in LGTM `here <https://lgtm.com/query/1269550358355690774/>`__.

View File

@@ -0,0 +1,94 @@
======================
Program representation
======================
CodeQL for Java
.. rst-class:: agenda
Agenda
======
- Abstract syntax trees
- Database representation
- Program elements
- AST CodeQL classes
.. insert abstract-syntax-tree.rst
.. include:: ../slide-snippets/abstract-syntax-tree.rst
.. resume slides
Program elements
================
- The CodeQL class ``Element`` represents program elements with a name.
- This includes: packages (``Package``), compilation units (``CompilationUnit``), types (``Type``), methods (``Method``), constructors (``Constructor``), and variables (``Variable``).
- It is often convenient to refer to an element that might either be a method or a constructor; the class ``Callable``, which is a common superclass of ``Method`` and ``Constructor``, can be used for this purpose.
AST
===
There are two primary AST CodeQL classes, used within ``Callables``:
- ``Expr``: expressions such as assignments, variable references, function calls, ...
- ``Stmt``: statements such as conditionals, loops, try statements, ...
Operations are provided for exploring the AST:
- ``Expr.getAChildExpr`` returns a sub-expression of a given expression.
- ``Stmt.getAChild`` returns a statement or expression that is nested directly inside a given statement.
- ``Expr.getParent`` and ``Stmt.getParent`` return the parent node of an AST node.
Types
=====
The database also includes information about the types used in a program:
- ``PrimitiveType`` represents a `primitive type <http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html>`__, that is, one of ``boolean``, ``byte``, ``char``, ``double``, ``float``, ``int``, ``long``, ``short``. CodeQL also classifies ``void`` and ``<nulltype>`` (the type of the ``null`` literal) as primitive types.
- ``RefType`` represents a reference type; it has several subclasses:
- ``Class`` represents a Java class.
- ``Interface`` represents a Java interface.
- ``EnumType`` represents a Java enum type.
- ``Array`` represents a Java array type.
Working with variables
======================
``Variable`` represents program variables, including locally scoped variables (``LocalScopeVariable``), fields (``Fields``), and parameters (``Parameters``):
- ``string Variable.getName()``
- ``Type Variable.getType()``
``Access`` represents references to declared entities such as methods (``MethodAccess``) and variables (``VariableAccess``), including fields (``FieldAccess``).
- ``Declaration Access.getTarget()``
``VariableDeclarationEntry`` represents declarations or definitions of a variable.
- ``Variable VariableDeclarationEntry.getVariable()``
Working with callables
======================
Callables are represented by the ``Callable`` CodeQL class.
Calls to callables are modeled by the CodeQL class ``Call`` and its subclasses:
- ``Call.getCallee()`` gets the declared target of the call
- ``Call.getAReference()`` gets a call to this function
Typically, callables are identified by name:
- ``string Callable.getName()``
- ``string Callable.getQualifiedName()``
.. rst-class:: java-expression-ast
Example: Java expression AST
============================
.. diagram copied from google slides

View File

@@ -0,0 +1,144 @@
========================
Example: Query injection
========================
CodeQL for Java
.. rst-class:: setup
Setup
=====
For this example you should download:
- `CodeQL for Visual Studio Code <https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html>`__
- `VIVO Vitro database <http://downloads.lgtm.com/snapshots/java/vivo-project/Vitro/vivo-project_Vitro_java-srcVersion_47ae42c01954432c3c3b92d5d163551ce367f510-dist_odasa-lgtm-2019-04-23-7ceff95-linux64.zip>`__
.. note::
For this example, we will be analyzing `VIVO Vitro <https://github.com/vivo-project/Vitro>`__.
You can also query the project in `the query console <https://lgtm.com/query/project:14040005/lang:java/>`__ on LGTM.com.
.. insert database-note.rst to explain differences between database available to download and the version available in the query console.
.. include:: ../slide-snippets/database-note.rst
.. resume slides
SQL injection
=============
- Occurs when user input is used to construct an SQL query without any sanitization or escaping.
- Classic example involves constructing a query using string concatenation:
.. code-block:: sql
runQuery("SELECT * FROM users WHERE id='" + userId + "'");
- If the ``userId`` can be provided by a user, and is not sanitized, then a malicious user can provide input that manipulates the intended query.
- For example, providing the input ``"' OR '1'='1"`` would allow the attacker to return all records in the users table.
.. note::
`SQL <https://en.wikipedia.org/wiki/SQL>`__ is a database query language, which is often used from within other programming languages to interact with a database. The typical case is that a query is to be executed to find some data, based on some input provided by the user - for example, the users ID. However, the interface between the host programming language and SQL is typically implemented by passing a string containing the query to some API.
SPARQL injection
================
- `SPARQL <https://en.wikipedia.org/wiki/SPARQL>`__ is a language for querying key-value databases in RDF format.
- The same type of vulnerability can occur for SPARQL as for SQL: if the SPARQL query is constructed through string concatenation, a malicious user can subvert the query:
.. code-block:: sql
sparqlAskQuery("ASK { <" + individualURI + "> ?p ?o }");
- SPARQL is used by many projects, but we will be looking at `VIVO Vitro <https://github.com/vivo-project/Vitro/>`__.
.. rst-class:: background2
Developing a query
===================
Finding a query concatenation
CodeQL query: find SPARQL methods
=================================
Lets start by looking for calls to methods with names of the form ``sparql*Query``, using the classes ``Method`` and ``MethodAccess`` from the Java library.
.. rst-class:: build
.. literalinclude:: ../query-examples/java/query-injection-java-1.ql
.. note::
- When performing variant analysis, it is usually helpful to write a simple query that finds the simple syntactic pattern, before trying to go on to describe the cases where it goes wrong.
- In this case, we start by looking for all the method calls that appear to run, before trying to refine the query to find cases which are vulnerable to query injection.
- The ``select`` clause defines what this query is looking for:
- a ``MethodAccess``: the call to a SPARQL query method
- a ``Method``: the SPARQL query method.
- The ``where`` part of the query ties these variables together using `predicates <https://help.semmle.com/QL/ql-handbook/predicates.html>`__ defined in the `standard CodeQL library for Java <https://help.semmle.com/qldoc/java/>`__.
CodeQL query: find string concatenation
=======================================
- We now need to define what would make these API calls unsafe.
- A simple heuristic would be to look for string concatenation used in the query argument.
- We may want to reuse this logic, so let us create a separate predicate.
Looking at autocomplete suggestions, we see that we can get the type of an expression using the ``getType()`` method.
.. rst-class:: build
.. code-block:: ql
predicate isStringConcat(AddExpr ae) {
ae.getType() instanceof TypeString
}
.. note::
- An important part of the query is to determine whether a given expression is string concatenation.
- We therefore write a helper predicate for finding string concatenation.
- This predicate effectively represents the set of all ``add`` expressions in the database where the type of the expression is ``TypeString`` - that is, the addition produces a ``String`` value.
CodeQL query: SPARQL injection
==============================
We can now combine our predicate with the existing query.
Note that we do not need to specify that the argument of the method access is an ``AddExpr`` - this is implied by the ``isStringConcat`` requirement.
Now our query becomes:
.. rst-class:: build
.. literalinclude:: ../query-examples/java/query-injection-java-2.ql
:language: ql
The final query
===============
.. literalinclude:: ../query-examples/java/query-injection-java-3.ql
:language: ql
There are two results, one of which was assigned **CVE-2019-6986**.
.. note::
Full write up and exploit can be found here: https://github.com/Semmle/SecurityExploits/tree/master/vivo-project/CVE-2019-6986
Follow up
=========
- Our query successfully finds cases where the concatenation occurs in the argument to the SPARQL API.
- However, in general, the concatenation could occur before the method call.
- For this, we would need to use :doc:`local data flow <data-flow-java>`, which is the topic of the next set of training slides.

View File

@@ -0,0 +1,8 @@
import cpp
from AddExpr a, Variable v, RelationalOperation cmp
where
a.getAnOperand() = v.getAnAccess() and
cmp.getAnOperand() = a and
cmp.getAnOperand() = v.getAnAccess()
select cmp, "Overflow check."

View File

@@ -0,0 +1,9 @@
import cpp
from AddExpr a, Variable v, RelationalOperation cmp
where
a.getAnOperand() = v.getAnAccess() and
cmp.getAnOperand() = a and
cmp.getAnOperand() = v.getAnAccess() and
forall(Expr op | op = a.getAnOperand() | isSmall(op))
select cmp, "Bad overflow check."

View File

@@ -0,0 +1,12 @@
import cpp
predicate isSmall(Expr e) { e.getType().getSize() < 4 }
from AddExpr a, Variable v, RelationalOperation cmp
where
a.getAnOperand() = v.getAnAccess() and
cmp.getAnOperand() = a and
cmp.getAnOperand() = v.getAnAccess() and
forall(Expr op | op = a.getAnOperand() | isSmall(op)) and
not isSmall(a.getExplicitlyConverted())
select cmp, "Bad overflow check"

View File

@@ -0,0 +1,8 @@
import cpp
from FunctionCall alloc, FunctionCall free, LocalScopeVariable v
where allocationCall(alloc)
and alloc = v.getAnAssignedValue()
and freeCall(free, v.getAnAccess())
and alloc.getASuccessor+() = free
select alloc, free

View File

@@ -0,0 +1,8 @@
import cpp
from FunctionCall free, LocalScopeVariable v, VariableAccess u
where freeCall(free, v.getAnAccess())
and u = v.getAnAccess()
and u.isRValue()
and free.getASuccessor+() = u
select free, u

View File

@@ -0,0 +1,10 @@
import cpp
from LocalVariable lv, ControlFlowNode def
where
def = lv.getAnAssignment() and
not exists(VariableAccess use |
use = lv.getAnAccess() and
use = def.getASuccessor+()
)
select lv, def

View File

@@ -0,0 +1,10 @@
import cpp
predicate isReachable(BasicBlock bb) {
bb instanceof EntryBasicBlock or
isReachable(bb.getAPredecessor())
}
from BasicBlock bb
where not isReachable(bb)
select bb

View File

@@ -0,0 +1,10 @@
import cpp
from ExprCall c, PointerDereferenceExpr deref, VariableAccess va,
Access fnacc
where c.getLocation().getFile().getBaseName() = "cjpeg.c" and
c.getLocation().getStartLine() = 640 and
deref = c.getExpr() and
va = deref.getOperand() and
fnacc = va.getTarget().getAnAssignedValue()
select c, fnacc.getTarget()

View File

@@ -0,0 +1,8 @@
import cpp
import semmle.code.cpp.commons.Printf
from Call c, FormattingFunction ff, Expr format
where c.getTarget() = ff and
format = c.getArgument(ff.getFormatParameterIndex()) and
not format instanceof StringLiteral
select format, "Non-constant format string."

View File

@@ -0,0 +1,12 @@
import cpp
import semmle.code.cpp.dataflow.DataFlow
import semmle.code.cpp.commons.Printf
class SourceNode extends DataFlow::Node { /* ... */ }
from FormattingFunction f, Call c, SourceNode src, DataFlow::Node arg
where c.getTarget() = f and
arg.asExpr() = c.getArgument(f.getFormatParameterIndex()) and
DataFlow::localFlow(src, arg) and
not src.asExpr() instanceof StringLiteral
select arg, "Non-constant format string."

View File

@@ -0,0 +1,11 @@
import cpp
class EmptyBlock extends Block {
EmptyBlock() {
this.isEmpty()
}
}
from IfStmt ifStmt
where ifstmt.getThen() instanceof EmptyBlock
select ifstmt

View File

@@ -0,0 +1,11 @@
import cpp
class EmptyBlock extends Block {
EmptyBlock() { this.isEmpty() }
}
from IfStmt ifstmt
where
ifstmt.getThen() instanceof EmptyBlock and
not exists(ifstmt.getElse())
select ifstmt, "This if-statement is redundant."

View File

@@ -0,0 +1,9 @@
import cpp
predicate isEmpty(Block block) {
block.isEmpty()
}
from IfStmt ifstmt
where isEmpty(ifstmt.getThen())
select ifstmt, "This if-statement is redundant."

View File

@@ -0,0 +1,7 @@
import cpp
from IfStmt ifstmt, Block block
where
block = ifstmt.getThen() and
block.isEmpty()
select ifstmt, "This if-statement is redundant."

View File

@@ -0,0 +1,13 @@
import cpp
import semmle.code.cpp.dataflow.TaintTracking
class TaintedFormatConfig extends TaintTracking::Configuration {
TaintedFormatConfig() { this = "TaintedFormatConfig" }
override predicate isSource(DataFlow::Node source) { /* TBD */ }
override predicate isSink(DataFlow::Node sink) { /* TBD */ }
}
from TaintedFormatConfig cfg, DataFlow::Node source, DataFlow::Node sink
where cfg.hasFlow(source, sink)
select sink, "This format string may be derived from a $@.",
source, "user-controlled value"

View File

@@ -0,0 +1,11 @@
import cpp
import semmle.code.cpp.dataflow.TaintTracking
from FunctionCall call, DataFlow::Node source, DataFlow::Node sink
where
call.getTarget().getName() = "snprintf" and
call.getArgument(2).getValue().regexpMatch("(?s).*%s.*") and
TaintTracking::localTaint(source, sink) and
source.asExpr() = call and
sink.asExpr() = call.getArgument(1)
select call

View File

@@ -0,0 +1,11 @@
import java
class StringConcat extends AddExpr {
StringConcat() { getType() instanceof TypeString }
}
from MethodAccess ma
where
ma.getMethod().getName().matches("sparql%Query") and
ma.getArgument(0) instanceof StringConcat
select ma, "SPARQL query vulnerable to injection."

View File

@@ -0,0 +1,8 @@
import java
import semmle.code.java.dataflow.DataFlow::DataFlow
from MethodAccess ma, StringConcat stringConcat
where
ma.getMethod().getName().matches("sparql%Query") and
localFlow(exprNode(stringConcat), exprNode(ma.getArgument(0)))
select ma, "SPARQL query vulnerable to injection."

View File

@@ -0,0 +1,12 @@
import java
class EmptyBlock extends Block {
EmptyBlock() {
this.getNumStmt() = 0
}
}
from IfStmt ifstmt
where ifstmt.getThen() instanceof
EmptyBlock
select ifstmt

View File

@@ -0,0 +1,11 @@
import java
class EmptyBlock extends Block {
EmptyBlock() { this.getNumStmt() = 0 }
}
from IfStmt ifstmt
where
ifstmt.getThen() instanceof EmptyBlock and
not exists(ifstmt.getElse())
select ifstmt, "This if-statement is redundant."

View File

@@ -0,0 +1,9 @@
import java
predicate isEmpty(Block block) {
block.getNumStmt() = 0
}
from IfStmt ifstmt
where isEmpty(ifstmt.getThen())
select ifstmt

View File

@@ -0,0 +1,7 @@
import java
from IfStmt ifstmt, Block block
where
block = ifstmt.getThen() and
block.getNumStmt() = 0
select ifstmt, "This if-statement is redundant."

View File

@@ -0,0 +1,14 @@
import java
import semmle.code.java.dataflow.TaintTracking
class TaintedOGNLConfig extends TaintTracking::Configuration {
TaintedOGNLConfig() { this = "TaintedOGNLConfig" }
override predicate isSource(DataFlow::Node source) { /* TBD */ }
override predicate isSink(DataFlow::Node sink) { /* TBD */ }
}
from TaintedOGNLConfig cfg, DataFlow::Node source, DataFlow::Node sink
where cfg.hasFlow(source, sink)
select source,
"This untrusted input is evaluated as an OGNL expression $@.",
sink, "here"

View File

@@ -0,0 +1,7 @@
import java
from Method m, MethodAccess ma
where
m.getName().matches("sparql%Query") and
ma.getMethod() = m
select ma, m

Some files were not shown because too many files have changed in this diff Show More