Progress towards refactoring

This commit is contained in:
Berkeley Martinez
2015-11-13 11:10:23 -08:00
parent 545e545f51
commit 748f7ab93f
18 changed files with 1291 additions and 925 deletions

View File

@ -25,7 +25,7 @@
"font-awesome": "~4.3.0",
"moment": "~2.10.2",
"angular-bootstrap": "~0.13.0",
"jshint": "~2.7.0",
"jshint": "~2.9.0",
"lightbox2": "~2.8.1",
"rxjs": "~4.0.6",
"CodeMirror": "~5.8.0",

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,82 @@
// depends on: codeUri
window.common = (function(global ) {
const {
$,
localStorage,
common = { init: [] }
} = global;
const {
codeUri
} = common;
var CodeStorageProps = {
version: 0.01,
keyVersion: 'saveVersion',
keyValue: null,
updateWait: 2000,
updateTimeoutId: null
};
var CodeStorage = {
hasSaved: function() {
return this.updateTimeoutId === null;
},
onSave: function(func) {
this.eventArray.push(func);
},
setSaveKey: function(key) {
this.keyValue = key + 'Val';
},
getStoredValue: function() {
return '' + localStorage.getItem(this.keyValue);
},
setEditor: function(editor) {
this.editor = editor;
},
isAlive: function() {
var val = this.getStoredValue();
return val !== 'null' &&
val !== 'undefined' &&
(val && val.length > 0);
},
updateStorage: function() {
if (typeof localStorage !== 'undefined') {
var value = this.editor.getValue();
// store in localStorage
localStorage.setItem(this.keyValue, value);
// also store code in URL
codeUri.querify(value);
} else {
console.log('no web storage');
}
this.updateTimeoutId = null;
}
};
function codeStorageFactory(editor, challengeName) {
var codeStorage = Object.create(CodeStorage);
$.extend(codeStorage, CodeStorageProps);
codeStorage.setEditor(editor);
codeStorage.setSaveKey(challengeName);
return codeStorage;
}
var savedVersion = localStorage.getItem(CodeStorageProps.keyVersion);
if (savedVersion === null) {
localStorage.setItem(
CodeStorageProps.keyVersion,
CodeStorageProps.version
);
}
common.codeStorageFactory = codeStorageFactory;
return common;
}(window, window.common));

View File

@ -0,0 +1,118 @@
// store code in the URL
window.common = (function(global) {
const {
encodeURIComponent: encode,
decodeURIComponent: decode,
location,
history,
common = { init: [] }
} = global;
const {
replaceScriptTags,
replaceSafeTags,
replaceFormActionAttr,
replaceFccfaaAttr
} = common;
function encodeFcc(val) {
return replaceScriptTags(replaceFormActionAttr(val));
}
function decodeFcc(val) {
return replaceSafeTags(replaceFccfaaAttr(val));
}
var codeUri = {
encode: function(code) {
return encode(code);
},
decode: function(code) {
try {
return decode(code);
} catch (ignore) {
return null;
}
},
isInQuery: function(query) {
var decoded = codeUri.decode(query);
if (!decoded || typeof decoded.split !== 'function') {
return false;
}
return decoded
.split('?')
.splice(1)
.reduce(function(found, param) {
var key = param.split('=')[0];
if (key === 'solution') {
return true;
}
return found;
}, false);
},
isAlive: function() {
return codeUri.enabled &&
codeUri.isInQuery(location.search) ||
codeUri.isInQuery(location.hash);
},
parse: function() {
if (!codeUri.enabled) {
return null;
}
var query;
if (location.search && codeUri.isInQuery(location.search)) {
query = location.search.replace(/^\?/, '');
if (history && typeof history.replaceState === 'function') {
history.replaceState(
history.state,
null,
location.href.split('?')[0]
);
location.hash = '#?' + encodeFcc(query);
}
} else {
query = location.hash.replace(/^\#\?/, '');
}
if (!query) {
return null;
}
return query
.split('&')
.reduce(function(solution, param) {
var key = param.split('=')[0];
var value = param.split('=')[1];
if (key === 'solution') {
return decodeFcc(codeUri.decode(value || ''));
}
return solution;
}, null);
},
querify: function(solution) {
if (!codeUri.enabled) {
return null;
}
if (history && typeof history.replaceState === 'function') {
history.replaceState(
history.state,
null,
'?solution=' + codeUri.encode(encodeFcc(solution))
);
} else {
location.hash = '?solution=' +
codeUri.encode(encodeFcc(solution));
}
return solution;
},
enabled: true
};
common.init.push(function() {
codeUri.parse();
});
common.codeUri = codeUri;
return common;
}(window));

View File

@ -0,0 +1,113 @@
window.common = (function(global) {
const {
CodeMirror,
emmetCodeMirror,
common = { init: [] }
} = global;
if (!CodeMirror) {
return {};
}
var delay;
var codeStorageFactory = common.codeStorageFactory;
var editor = CodeMirror.fromTextArea(document.getElementById('codeEditor'), {
lint: true,
lineNumbers: true,
mode: 'javascript',
theme: 'monokai',
runnable: true,
matchBrackets: true,
autoCloseBrackets: true,
scrollbarStyle: 'null',
lineWrapping: true,
gutters: ['CodeMirror-lint-markers']
});
editor.setSize('100%', 'auto');
var codeStorage = common.codeStorage =
codeStorageFactory(editor, common.challengeName);
editor.on('keyup', function() {
clearTimeout(codeStorage.updateTimeoutId);
codeStorage.updateTimeoutId = setTimeout(
codeStorage.updateStorage.bind(codeStorage),
codeStorage.updateWait
);
});
// Initialize CodeMirror editor with a nice html5 canvas demo.
editor.on('keyup', function() {
clearTimeout(delay);
delay = setTimeout(common.updatePreview, 300);
});
editor.setOption('extraKeys', {
Tab: function(cm) {
if (cm.somethingSelected()) {
cm.indentSelection('add');
} else {
var spaces = Array(cm.getOption('indentUnit') + 1).join(' ');
cm.replaceSelection(spaces);
}
},
'Shift-Tab': function(cm) {
if (cm.somethingSelected()) {
cm.indentSelection('subtract');
} else {
var spaces = Array(cm.getOption('indentUnit') + 1).join(' ');
cm.replaceSelection(spaces);
}
},
'Ctrl-Enter': function() {
common.executeChallenge(true);
return false;
},
'Cmd-Enter': function() {
common.executeChallenge(true);
return false;
}
});
var info = editor.getScrollInfo();
var after = editor.charCoords({
line: editor.getCursor().line + 1,
ch: 0
}, 'local').top;
if (info.top + info.clientHeight < after) {
editor.scrollTo(null, after - info.clientHeight + 3);
}
if (emmetCodeMirror) {
emmetCodeMirror(
editor,
{
'Cmd-E': 'emmet.expand_abbreviation',
Tab: 'emmet.expand_abbreviation_with_tab',
Enter: 'emmet.insert_formatted_line_break_only'
}
);
}
common.init.push(function() {
var editorValue;
if (common.codeUri.isAlive()) {
editorValue = common.codeUri.parse();
} else {
editorValue = codeStorage.isAlive() ?
codeStorage.getStoredValue() :
common.seed;
}
editor.setValue(common.replaceSafeTags(editorValue));
editor.refresh();
});
common.editor = editor;
return common;
}(window));

View File

@ -0,0 +1,57 @@
window.common = (function(global) {
const {
jailed,
document: doc,
common = { init: [] }
} = global;
if (!jailed) {
return (code, cb) => cb(new Error('Could not load jailed plugin'));
}
// obtaining absolute path of this script
var scripts = doc.getElementsByTagName('script');
var path = scripts[scripts.length - 1].src
.split('?')[0]
.split('/')
.slice(0, -1)
.join('/') + '/';
var sandbox = {
timeoutId: null,
startTimeout() {
this.timeoutId = setTimeout(() => {
this.disconnect();
}, 3000);
},
endTimeout() {
if (this.timeoutId) {
clearTimeout(this.timeoutId);
this.timeoutId = null;
}
},
createPlugin() {
this.plugin = new jailed.Plugin(path + 'plugin.js');
this.plugin.whenDisconnected(() => {
this.endTimeout();
});
},
destroyPlugin() {
this.plugin.disconnect();
}
};
// sends the input to the plugin for evaluation
common.detectLoops = function detectLoops(code, callback) {
sandbox.createPlugin();
sandbox.plugin.whenConnected(() => {
this.endTimeout();
sandbox.plugin.remote.run(code, callback);
});
};
return common;
}(window));

View File

@ -0,0 +1,28 @@
window.common = (function({ $, common = { init: [] }}) {
common.displayTestResults = function displayTestResults(data = []) {
data.forEach(({ err = false, text = '' }) => {
var iconClass = err ?
'"ion-checkmark-circled big-success-icon"' :
'"ion-close-circled big-error-icon"';
$('#testSuite').children().remove();
$('<div></div>').html(`
<div class='row'>
<div class='col-xs-2 text-center'>
<i class=${iconClass}></i>
</div>
<div class='col-xs-10 test-output wrappable'>
${text.split('message: ').pop().replace(/\'\);/g, '')}
</div>
<div class='ten-pixel-break'/>
</div>
`)
.appendTo($('#testSuite'));
});
return data;
};
return common;
}(window));

View File

@ -0,0 +1,94 @@
window.common = (function(global) {
const {
ga,
common = { init: [] }
} = global;
let attempts = 0;
common.executeChallenge = function executeChallenge(shouldTest) {
const editorValue = common.editor.getValue();
const head = common.arrayToNewLineString(common.head);
const tail = common.arrayToNewLineString(common.tail);
const codeOutput = common.codeOutput;
attempts++;
ga('send', 'event', 'Challenge', 'ran-code', common.challengeName);
$('#testSuite').empty();
const openingComments = editorValue.match(/\/\*/gi);
// checks if the number of opening comments(/*) matches the number of
// closing comments(*/)
if (
editorValue.match(/\$\s*?\(\s*?\$\s*?\)/gi) &&
openingComments &&
openingComments.length > editorValue.match(/\*\//gi).length
) {
common.editor.setValue(common.editor.getValue() + '*/');
codeOutput.setValue('Unfinished multi-line comment');
return null;
}
if (common.challengeType !== '0') {
let userJavaScript = head + common.editor.getValue() + tail;
userJavaScript = common.removeComments(userJavaScript);
userJavaScript = common.addTests(userJavaScript);
// simple fix in case the user forgets to invoke their function
if (userJavaScript.match(/function/gi)) {
if (userJavaScript.match(/function\s*?\(|function\s+\w+\s*?\(/gi)) {
common.runInSand(userJavaScript, function(err, message) {
if (err) {
codeOutput.setValue(err);
if (shouldTest) {
common.runTests('Error', null);
}
} else {
codeOutput.setValue(message.output);
codeOutput.setValue(codeOutput.getValue().replace(/\\\"/gi, ''));
message.input = common.removeLogs(message.input);
if (shouldTest) {
common.runTests(null, message);
}
}
});
} else {
codeOutput.setValue('Unsafe or unfinished function declaration');
}
} else {
common.runInSand(userJavaScript, function(cls, message) {
if (cls) {
codeOutput.setValue(message.error);
if (shouldTest) {
common.runTests('Error', null);
}
} else {
codeOutput.setValue(message.output);
codeOutput.setValue(codeOutput.getValue().replace(/\\\"/gi, ''));
message.input = common.removeLogs(message.input);
if (shouldTest) {
common.runTests(null, message);
}
}
});
}
} else if (
!editorValue.match(/\$\s*?\(\s*?\$\s*?\)/gi) &&
common.challengeType === '0'
) {
common.safeHTMLRun(shouldTest);
} else {
common.workerError('Unsafe $($)');
}
setTimeout(function() {
var $marginFix = $('.innerMarginFix');
$marginFix.css('min-height', $marginFix.height());
}, 1000);
};
return common;
}(window));

View File

@ -0,0 +1,44 @@
window.common = (function(global) {
const {
CodeMirror,
document: doc,
common = { init: [] }
} = global;
const { challengeType = '0' } = common;
if (!CodeMirror) {
return {};
}
if (
challengeType === '0' ||
challengeType === '7'
) {
return {};
}
common.codeOutput = CodeMirror.fromTextArea(
doc.getElementById('codeOutput'),
{
lineNumbers: false,
mode: 'text',
theme: 'monokai',
readOnly: 'nocursor',
lineWrapping: true
}
);
common.codeOutput.setValue(`
/**
* Your output will go here.
* Console.log() -type statements
* will appear in your browser\'s
* DevTools JavaScript console.
*/'
`);
common.codeOutput.setSize('100%', '100%');
return common;
}(window));

View File

@ -0,0 +1,43 @@
window.common = (function({ common = { init: [] }}) {
common.runTests = function runTests(err, data) {
var head = common.arrayToNewLineString(common.head);
var tail = common.arrayToNewLineString(common.tail);
var userTests = Array.isArray(userTests) ? userTests.slice() : [];
var editorValue = head + common.editor.getValue() + tail;
if (err) {
userTests = [{
text: 'Program Execution Failure',
err
}];
return userTests;
}
// Add blocks to test exploits here!
if (editorValue.match(/if\s\(null\)\sconsole\.log\(1\);/gi)) {
userTests = [{
text: 'Program Execution Failure',
err: 'Invalid if (null) console.log(1); detected'
}];
return userTests;
}
return userTests.map(function(test) {
try {
if (test) {
/* eslint-disable no-eval, no-unused-vars */
var output = eval(common.reassembleTest(test, data));
/* eslint-enable no-eval, no-unused-vars */
}
} catch (e) {
test.err = e.message;
}
return test;
});
};
return common;
}(window));

View File

@ -0,0 +1,202 @@
window.common = (function({ $, common = { init: [] }}) {
const stepClass = '.challenge-step';
const prevBtnClass = '.challenge-step-btn-prev';
const nextBtnClass = '.challenge-step-btn-next';
const actionBtnClass = '.challenge-step-btn-action';
const finishBtnClass = '.challenge-step-btn-finish';
const submitBtnId = '#challenge-step-btn-submit';
const submitModalId = '#challenge-step-modal';
function getPreviousStep($challengeSteps) {
var length = $challengeSteps.length;
var $prevStep = false;
var prevStepIndex = 0;
$challengeSteps.each(function(index) {
var $step = $(this);
if (
!$step.hasClass('hidden') &&
index + 1 !== length
) {
prevStepIndex = index - 1;
}
});
$prevStep = $challengeSteps[prevStepIndex];
return $prevStep;
}
function getNextStep($challengeSteps) {
var length = $challengeSteps.length;
var $nextStep = false;
var nextStepIndex = 0;
$challengeSteps.each(function(index) {
var $step = $(this);
if (
!$step.hasClass('hidden') &&
index + 1 !== length
) {
nextStepIndex = index + 1;
}
});
$nextStep = $challengeSteps[nextStepIndex];
return $nextStep;
}
function handlePrevStepClick(e) {
e.preventDefault();
var prevStep = getPreviousStep($(stepClass));
$(this)
.parent()
.removeClass('fadeOutLeft')
.addClass('animated fadeOutRight fast-animation')
.delay(250)
.queue(function(prev) {
$(this).addClass('hidden');
if (prevStep) {
$(prevStep)
.removeClass('hidden')
.removeClass('slideInRight')
.addClass('animated slideInLeft fast-animation')
.delay(500)
.queue(function(prev) {
prev();
});
}
prev();
});
}
function handleNextStepClick(e) {
e.preventDefault();
var nextStep = getNextStep($(stepClass));
$(this)
.parent()
.removeClass('fadeOutRight')
.addClass('animated fadeOutLeft fast-animation')
.delay(250)
.queue(function(next) {
$(this).addClass('hidden');
if (nextStep) {
$(nextStep)
.removeClass('hidden')
.removeClass('slideInLeft')
.addClass('animated slideInRight fast-animation')
.delay(500)
.queue(function(next) {
next();
});
}
next();
});
}
function handleActionClick(e) {
var props = common.challengeSeed[0] ||
{ stepIndex: [] };
var $el = $(this);
var index = +$el.attr('id');
var propIndex = props.stepIndex.indexOf(index);
if (propIndex === -1) {
return $el
.parent()
.find('.disabled')
.removeClass('disabled');
}
// an API action
// prevent link from opening
e.preventDefault();
var prop = props.properties[propIndex];
var api = props.apis[propIndex];
if (common[prop]) {
return $el
.parent()
.find('.disabled')
.removeClass('disabled');
}
$
.post(api)
.done(function(data) {
// assume a boolean indicates passing
if (typeof data === 'boolean') {
return $el
.parent()
.find('.disabled')
.removeClass('disabled');
}
// assume api returns string when fails
$el
.parent()
.find('.disabled')
.replaceWith('<p>' + data + '</p>');
})
.fail(function() {
console.log('failed');
});
}
function handleFinishClick(e) {
e.preventDefault();
$(submitModalId).modal('show');
$(submitModalId + '.modal-header').click();
$(submitBtnId).click(handleSubmitClick);
}
function handleSubmitClick(e) {
e.preventDefault();
$('#submit-challenge')
.attr('disabled', 'true')
.removeClass('btn-primary')
.addClass('btn-warning disabled');
var $checkmarkContainer = $('#checkmark-container');
$checkmarkContainer.css({ height: $checkmarkContainer.innerHeight() });
$('#challenge-checkmark')
.addClass('zoomOutUp')
.delay(1000)
.queue(function(next) {
$(this).replaceWith(
'<div id="challenge-spinner" ' +
'class="animated zoomInUp inner-circles-loader">' +
'submitting...</div>'
);
next();
});
$.post(
'/completed-bonfire/', {
challengeInfo: {
challengeId: common.challengeId,
challengeName: common.challengeName,
challengeType: common.challengeType
}
},
function(res) {
if (res) {
window.location =
'/challenges/next-challenge?id=' + common.challengeId;
}
}
);
}
common.init.push(function($) {
if (common.challengeType === '7') {
return null;
}
$(prevBtnClass).click(handlePrevStepClick);
$(nextBtnClass).click(handleNextStepClick);
$(actionBtnClass).click(handleActionClick);
$(finishBtnClass).click(handleFinishClick);
});
return common;
}(window));

View File

@ -0,0 +1,79 @@
window.common = (function(global) {
// common namespace
// all classes should be stored here
// called at the beginning of dom ready
const {
common = { init: [] }
} = global;
common.head = common.head || [];
common.tail = common.tail || [];
common.salt = Math.random();
common.arrayToNewLineString = function arrayToNewLineString(seedData) {
seedData = Array.isArray(seedData) ? seedData : [seedData];
return seedData.reduce(function(seed, line) {
return '' + seed + line + '\n';
}, '');
};
common.seed = common.arrayToNewLineString(common.challengeSeed);
common.replaceScriptTags = function replaceScriptTags(value) {
return value
.replace(/<script>/gi, 'fccss')
.replace(/<\/script>/gi, 'fcces');
};
common.replaceSafeTags = function replaceSafeTags(value) {
return value
.replace(/fccss/gi, '<script>')
.replace(/fcces/gi, '</script>');
};
common.replaceFormActionAttr = function replaceFormAction(value) {
return value.replace(/<form[^>]*>/, function(val) {
return val.replace(/action(\s*?)=/, 'fccfaa$1=');
});
};
common.replaceFccfaaAttr = function replaceFccfaaAttr(value) {
return value.replace(/<form[^>]*>/, function(val) {
return val.replace(/fccfaa(\s*?)=/, 'action$1=');
});
};
common.scopejQuery = function scopejQuery(str) {
return str
.replace(/\$/gi, 'j$')
.replace(/document/gi, 'jdocument')
.replace(/jQuery/gi, 'jjQuery');
};
common.unScopeJQuery = function unScopeJQuery(str) {
return str
.replace(/j\$/gi, '$')
.replace(/jdocument/gi, 'document')
.replace(/jjQuery/gi, 'jQuery');
};
const commentRegex = /(\/\*[^(\*\/)]*\*\/)|([ \n]\/\/[^\n]*)/g;
common.removeLogs = function removeComments(str) {
return str.replace(commentRegex, '');
};
const logRegex = /(console\.[\w]+\s*\(.*\;)/g;
common.removeLogs = function removeLogs(str) {
return str.replace(logRegex, '');
};
common.reassembleTest = function reassembleTest(test, data) {
var lineNum = test.line;
var regexp = new RegExp('\/\/' + lineNum + common.salt);
return data.input.replace(regexp, test.text);
};
return common;
})();

View File

@ -1,26 +1,26 @@
/* eslint-disable no-undef, no-unused-vars, no-native-reassign */
(function() {
window.$ = parent.$;
window.$(function() {
var _ = parent._;
var chai = parent.chai;
var expect = chai.expect;
var tests = parent.tests;
var editor = parent.editorValueForIFrame;
var common = parent.common;
var editorValue = common.editor.getValue();
setTimeout(function() {
for (var i = 0; i < tests.length; i++) {
var thisTest = true;
try {
/* eslint-disable no-eval */
eval(parent.tests[i]);
/* eslint-enable no-eval */
} catch (err) {
allTestsGood = false;
thisTest = false;
parent.postError(JSON.stringify(err.message.split(':').shift()));
} finally {
if (thisTest) {
parent.postSuccess(JSON.stringify(tests[i].split(',').pop().replace(
/\'/g, '').replace(/\)/, '')));
}
}
common.tests.forEach(test => {
try {
/* eslint-disable no-eval */
eval(test);
/* eslint-enable no-eval */
} catch (e) {
parent.postError(JSON.stringify(e.message.split(':').shift()));
} finally {
parent.postSuccess(
JSON.stringify(
test.split(',').pop().replace(/\'/g, '').replace(/\)/, '')
)
);
}
}, 10);
})();
});
});

View File

@ -11,11 +11,11 @@ function importScript(url, error) {
return error;
}
function run(code) {
function run(code, cb) {
var err = null;
var result = {
input: code,
output: null,
error: null,
type: null
};
@ -24,10 +24,15 @@ function run(code) {
result.type = typeof codeExec;
result.output = stringify(codeExec);
} catch (e) {
result.error = e.message;
err = e;
}
if (err) {
cb(err.message, null);
} else {
cb(null, result);
}
application.remote.output(result);
self.close();
}

View File

@ -17,6 +17,7 @@ var Rx = require('rx'),
concat = require('gulp-concat'),
uglify = require('gulp-uglify'),
merge = require('merge-stream'),
babel = require('gulp-babel'),
// react app
webpack = require('webpack-stream'),
@ -375,6 +376,7 @@ gulp.task('js', function() {
gulp.src(paths.js)
.pipe(plumber({ errorHandler: errorHandler }))
.pipe(babel())
.pipe(__DEV__ ? gutil.noop() : uglify())
);
@ -395,7 +397,6 @@ gulp.task('js', function() {
});
// commonFramework depend on iFrameScripts
// sandbox depends on plugin
gulp.task('dependents', ['js'], function() {
var manifestName = 'dependents-manifest.json';
var dest = paths.publicJs;
@ -406,6 +407,7 @@ gulp.task('dependents', ['js'], function() {
return gulp.src(paths.dependents)
.pipe(plumber({ errorHandler: errorHandler }))
.pipe(babel())
.pipe(__DEV__ ? gutil.noop() : uglify())
.pipe(revReplace({ manifest: manifest }))
.pipe(gulp.dest(dest))

View File

@ -57,6 +57,7 @@
"forever": "~0.15.1",
"frameguard": "~0.2.2",
"gulp": "^3.9.0",
"gulp-babel": "^5.3.0",
"gulp-concat": "^2.6.0",
"gulp-eslint": "^1.1.0",
"gulp-inject": "^3.0.0",

263
public/js/fauxJQuery.js Normal file
View File

@ -0,0 +1,263 @@
function $() {
if (!(this instanceof $)) {
return new $();
}
}
function returnThis() { return this; }
function return$() { return $; }
var methods = [
'add',
'addBack',
'addClass',
'after',
'ajaxComplete',
'ajaxError',
'ajaxSend',
'ajaxStart',
'ajaxStop',
'ajaxSuccess',
'andSelf',
'animate',
'append',
'appendTo',
'attr',
'before',
'bind',
'blur',
'callbacksadd',
'callbacksdisable',
'callbacksdisabled',
'callbacksempty',
'callbacksfire',
'callbacksfired',
'callbacksfireWith',
'callbackshas',
'callbackslock',
'callbackslocked',
'callbacksremove',
'change',
'children',
'clearQueue',
'click',
'clone',
'closest',
'contents',
'context',
'css',
'data',
'dblclick',
'delay',
'delegate',
'dequeue',
'detach',
'die',
'each',
'empty',
'end',
'eq',
'error',
'fadeIn',
'fadeOut',
'fadeTo',
'fadeToggle',
'filter',
'find',
'finish',
'first',
'focus',
'focusin',
'focusout',
'get',
'has',
'hasClass',
'height',
'hide',
'hover',
'html',
'index',
'innerHeight',
'innerWidth',
'insertAfter',
'insertBefore',
'is',
'jQuery',
'jquery',
'keydown',
'keypress',
'keyup',
'last',
'length',
'live',
'load',
'load',
'map',
'mousedown',
'mouseenter',
'mouseleave',
'mousemove',
'mouseout',
'mouseover',
'mouseup',
'next',
'nextAll',
'nextUntil',
'not',
'off',
'offset',
'offsetParent',
'on',
'one',
'outerHeight',
'outerWidth',
'parent',
'parents',
'parentsUntil',
'position',
'prepend',
'prependTo',
'prev',
'prevAll',
'prevUntil',
'promise',
'prop',
'pushStack',
'queue',
'ready',
'remove',
'removeAttr',
'removeClass',
'removeData',
'removeProp',
'replaceAll',
'replaceWith',
'resize',
'scroll',
'scrollLeft',
'scrollTop',
'select',
'selector',
'serialize',
'serializeArray',
'show',
'siblings',
'size',
'slice',
'slideDown',
'slideToggle',
'slideUp',
'stop',
'submit',
'text',
'toArray',
'toggle',
'toggle',
'toggleClass',
'trigger',
'triggerHandler',
'unbind',
'undelegate',
'unload',
'unwrap',
'val',
'width',
'wrap',
'wrapAll',
'wrapInner'
];
var statics = [
'ajax',
'ajaxPrefilter',
'ajaxSetup',
'ajaxTransport',
'boxModel',
'browser',
'Callbacks',
'contains',
'cssHooks',
'cssNumber',
'data',
'Deferred',
'dequeue',
'each',
'error',
'extend',
'fnextend',
'fxinterval',
'fxoff',
'get',
'getJSON',
'getScript',
'globalEval',
'grep',
'hasData',
'holdReady',
'inArray',
'isArray',
'isEmptyObject',
'isFunction',
'isNumeric',
'isPlainObject',
'isWindow',
'isXMLDoc',
'makeArray',
'map',
'merge',
'noConflict',
'noop',
'now',
'param',
'parseHTML',
'parseJSON',
'parseXML',
'post',
'proxy',
'queue',
'removeData',
'sub',
'support',
'trim',
'type',
'unique',
'when',
'always',
'done',
'fail',
'isRejected',
'isResolved',
'notify',
'notifyWith',
'pipe',
'progress',
'promise',
'reject',
'rejectWith',
'resolve',
'resolveWith',
'state',
'then',
'currentTarget',
'data',
'delegateTarget',
'isDefaultPrevented',
'isImmediatePropagationStopped',
'isPropagationStopped',
'metaKey',
'namespace',
'pageX',
'pageY',
'preventDefault',
'relatedTarget',
'result',
'stopImmediatePropagation',
'stopPropagation',
'target',
'timeStamp',
'type',
'which'
];
var $Proto = {};
methods.forEach(method => $Proto[method] = returnThis);
statics.forEach(staticMeth => $[staticMeth] = return$);
$.prototype = Object.create($);

View File

@ -1,8 +1,8 @@
extends ../layout-wide
block content
link(rel='stylesheet', href='/js/lib/codemirror/lib/codemirror.css')
link(rel='stylesheet', href='/js/lib/codemirror/addon/lint/lint.css')
link(rel='stylesheet', href='/js/lib/codemirror/theme/monokai.css')
link(rel='stylesheet', href='/bower_components/CodeMirror/lib/codemirror.css')
link(rel='stylesheet', href='/bower_components/CodeMirror/addon/lint/lint.css')
link(rel='stylesheet', href='/bower_components/CodeMirror/theme/monokai.css')
link(rel='stylesheet', href='/css/ubuntu.css')
.row(ng-controller="pairedWithController")