// Copyright (c) IPython Development Team. // Distributed under the terms of the Modified BSD License. define([ 'base/js/namespace', 'jquery', 'codemirror/lib/codemirror', 'moment', // silently upgrades CodeMirror 'codemirror/mode/meta', ], function(IPython, $, CodeMirror, moment){ "use strict"; var load_extensions = function () { // load one or more IPython notebook extensions with requirejs var extensions = []; var extension_names = arguments; for (var i = 0; i < extension_names.length; i++) { extensions.push("nbextensions/" + arguments[i]); } require(extensions, function () { for (var i = 0; i < arguments.length; i++) { var ext = arguments[i]; var ext_name = extension_names[i]; // success callback console.log("Loaded extension: " + ext_name); if (ext && ext.load_ipython_extension !== undefined) { ext.load_ipython_extension(); } } }, function (err) { // failure callback console.log("Failed to load extension(s):", err.requireModules, err); } ); }; IPython.load_extensions = load_extensions; /** * Wait for a config section to load, and then load the extensions specified * in a 'load_extensions' key inside it. */ function load_extensions_from_config(section) { section.loaded.then(function() { if (section.data.load_extensions) { var nbextension_paths = Object.getOwnPropertyNames( section.data.load_extensions); load_extensions.apply(this, nbextension_paths); } }); } //============================================================================ // Cross-browser RegEx Split //============================================================================ // This code has been MODIFIED from the code licensed below to not replace the // default browser split. The license is reproduced here. // see http://blog.stevenlevithan.com/archives/cross-browser-split for more info: /*! * Cross-Browser Split 1.1.1 * Copyright 2007-2012 Steven Levithan * Available under the MIT License * ECMAScript compliant, uniform cross-browser split method */ /** * Splits a string into an array of strings using a regex or string * separator. Matches of the separator are not included in the result array. * However, if `separator` is a regex that contains capturing groups, * backreferences are spliced into the result each time `separator` is * matched. Fixes browser bugs compared to the native * `String.prototype.split` and can be used reliably cross-browser. * @param {String} str String to split. * @param {RegExp} separator Regex to use for separating * the string. * @param {Number} [limit] Maximum number of items to include in the result * array. * @returns {Array} Array of substrings. * @example * * // Basic use * regex_split('a b c d', ' '); * // -> ['a', 'b', 'c', 'd'] * * // With limit * regex_split('a b c d', ' ', 2); * // -> ['a', 'b'] * * // Backreferences in result array * regex_split('..word1 word2..', /([a-z]+)(\d+)/i); * // -> ['..', 'word', '1', ' ', 'word', '2', '..'] */ var regex_split = function (str, separator, limit) { var output = [], flags = (separator.ignoreCase ? "i" : "") + (separator.multiline ? "m" : "") + (separator.extended ? "x" : "") + // Proposed for ES6 (separator.sticky ? "y" : ""), // Firefox 3+ lastLastIndex = 0, separator2, match, lastIndex, lastLength; // Make `global` and avoid `lastIndex` issues by working with a copy separator = new RegExp(separator.source, flags + "g"); var compliantExecNpcg = typeof(/()??/.exec("")[1]) === "undefined"; if (!compliantExecNpcg) { // Doesn't need flags gy, but they don't hurt separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags); } /* Values for `limit`, per the spec: * If undefined: 4294967295 // Math.pow(2, 32) - 1 * If 0, Infinity, or NaN: 0 * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296; * If negative number: 4294967296 - Math.floor(Math.abs(limit)) * If other: Type-convert, then use the above rules */ limit = typeof(limit) === "undefined" ? -1 >>> 0 : // Math.pow(2, 32) - 1 limit >>> 0; // ToUint32(limit) for (match = separator.exec(str); match; match = separator.exec(str)) { // `separator.lastIndex` is not reliable cross-browser lastIndex = match.index + match[0].length; if (lastIndex > lastLastIndex) { output.push(str.slice(lastLastIndex, match.index)); // Fix browsers whose `exec` methods don't consistently return `undefined` for // nonparticipating capturing groups if (!compliantExecNpcg && match.length > 1) { match[0].replace(separator2, function () { for (var i = 1; i < arguments.length - 2; i++) { if (typeof(arguments[i]) === "undefined") { match[i] = undefined; } } }); } if (match.length > 1 && match.index < str.length) { Array.prototype.push.apply(output, match.slice(1)); } lastLength = match[0].length; lastLastIndex = lastIndex; if (output.length >= limit) { break; } } if (separator.lastIndex === match.index) { separator.lastIndex++; // Avoid an infinite loop } } if (lastLastIndex === str.length) { if (lastLength || !separator.test("")) { output.push(""); } } else { output.push(str.slice(lastLastIndex)); } return output.length > limit ? output.slice(0, limit) : output; }; //============================================================================ // End contributed Cross-browser RegEx Split //============================================================================ var uuid = function () { /** * http://www.ietf.org/rfc/rfc4122.txt */ var s = []; var hexDigits = "0123456789ABCDEF"; for (var i = 0; i < 32; i++) { s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); } s[12] = "4"; // bits 12-15 of the time_hi_and_version field to 0010 s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01 var uuid = s.join(""); return uuid; }; //Fix raw text to parse correctly in crazy XML function xmlencode(string) { return string.replace(/\&/g,'&'+'amp;') .replace(//g,'&'+'gt;') .replace(/\'/g,'&'+'apos;') .replace(/\"/g,'&'+'quot;') .replace(/`/g,'&'+'#96;'); } //Map from terminal commands to CSS classes var ansi_colormap = { "01":"ansibold", "30":"ansiblack", "31":"ansired", "32":"ansigreen", "33":"ansiyellow", "34":"ansiblue", "35":"ansipurple", "36":"ansicyan", "37":"ansigray", "40":"ansibgblack", "41":"ansibgred", "42":"ansibggreen", "43":"ansibgyellow", "44":"ansibgblue", "45":"ansibgpurple", "46":"ansibgcyan", "47":"ansibggray" }; function _process_numbers(attrs, numbers) { // process ansi escapes var n = numbers.shift(); if (ansi_colormap[n]) { if ( ! attrs["class"] ) { attrs["class"] = ansi_colormap[n]; } else { attrs["class"] += " " + ansi_colormap[n]; } } else if (n == "38" || n == "48") { // VT100 256 color or 24 bit RGB if (numbers.length < 2) { console.log("Not enough fields for VT100 color", numbers); return; } var index_or_rgb = numbers.shift(); var r,g,b; if (index_or_rgb == "5") { // 256 color var idx = parseInt(numbers.shift(), 10); if (idx < 16) { // indexed ANSI // ignore bright / non-bright distinction idx = idx % 8; var ansiclass = ansi_colormap[n[0] + (idx % 8).toString()]; if ( ! attrs["class"] ) { attrs["class"] = ansiclass; } else { attrs["class"] += " " + ansiclass; } return; } else if (idx < 232) { // 216 color 6x6x6 RGB idx = idx - 16; b = idx % 6; g = Math.floor(idx / 6) % 6; r = Math.floor(idx / 36) % 6; // convert to rgb r = (r * 51); g = (g * 51); b = (b * 51); } else { // grayscale idx = idx - 231; // it's 1-24 and should *not* include black or white, // so a 26 point scale r = g = b = Math.floor(idx * 256 / 26); } } else if (index_or_rgb == "2") { // Simple 24 bit RGB if (numbers.length > 3) { console.log("Not enough fields for RGB", numbers); return; } r = numbers.shift(); g = numbers.shift(); b = numbers.shift(); } else { console.log("unrecognized control", numbers); return; } if (r !== undefined) { // apply the rgb color var line; if (n == "38") { line = "color: "; } else { line = "background-color: "; } line = line + "rgb(" + r + "," + g + "," + b + ");"; if ( !attrs.style ) { attrs.style = line; } else { attrs.style += " " + line; } } } } function ansispan(str) { // ansispan function adapted from github.com/mmalecki/ansispan (MIT License) // regular ansi escapes (using the table above) var is_open = false; return str.replace(/\033\[(0?[01]|22|39)?([;\d]+)?m/g, function(match, prefix, pattern) { if (!pattern) { // [(01|22|39|)m close spans if (is_open) { is_open = false; return ""; } else { return ""; } } else { is_open = true; // consume sequence of color escapes var numbers = pattern.match(/\d+/g); var attrs = {}; while (numbers.length > 0) { _process_numbers(attrs, numbers); } var span = ""; } }); } // Transform ANSI color escape codes into HTML tags with css // classes listed in the above ansi_colormap object. The actual color used // are set in the css file. function fixConsole(txt) { txt = xmlencode(txt); // Strip all ANSI codes that are not color related. Matches // all ANSI codes that do not end with "m". var ignored_re = /(?=(\033\[[\d;=]*[a-ln-zA-Z]{1}))\1(?!m)/g; txt = txt.replace(ignored_re, ""); // color ansi codes txt = ansispan(txt); return txt; } // Remove chunks that should be overridden by the effect of // carriage return characters function fixCarriageReturn(txt) { var tmp = txt; do { txt = tmp; tmp = txt.replace(/\r+\n/gm, '\n'); // \r followed by \n --> newline tmp = tmp.replace(/^.*\r+/gm, ''); // Other \r --> clear line } while (tmp.length < txt.length); return txt; } // Locate any URLs and convert them to a anchor tag function autoLinkUrls(txt) { return txt.replace(/(^|\s)(https?|ftp)(:[^'">\s]+)/gi, "$1$2$3"); } var points_to_pixels = function (points) { /** * A reasonably good way of converting between points and pixels. */ var test = $('
'); $('body').append(test); var pixel_per_point = test.width()/10000; test.remove(); return Math.floor(points*pixel_per_point); }; var always_new = function (constructor) { /** * wrapper around contructor to avoid requiring `var a = new constructor()` * useful for passing constructors as callbacks, * not for programmer laziness. * from http://programmers.stackexchange.com/questions/118798 */ return function () { var obj = Object.create(constructor.prototype); constructor.apply(obj, arguments); return obj; }; }; var url_path_join = function () { /** * join a sequence of url components with '/' */ var url = ''; for (var i = 0; i < arguments.length; i++) { if (arguments[i] === '') { continue; } if (url.length > 0 && url[url.length-1] != '/') { url = url + '/' + arguments[i]; } else { url = url + arguments[i]; } } url = url.replace(/\/\/+/, '/'); return url; }; var url_path_split = function (path) { /** * Like os.path.split for URLs. * Always returns two strings, the directory path and the base filename */ var idx = path.lastIndexOf('/'); if (idx === -1) { return ['', path]; } else { return [ path.slice(0, idx), path.slice(idx + 1) ]; } }; var parse_url = function (url) { /** * an `a` element with an href allows attr-access to the parsed segments of a URL * a = parse_url("http://localhost:8888/path/name#hash") * a.protocol = "http:" * a.host = "localhost:8888" * a.hostname = "localhost" * a.port = 8888 * a.pathname = "/path/name" * a.hash = "#hash" */ var a = document.createElement("a"); a.href = url; return a; }; var encode_uri_components = function (uri) { /** * encode just the components of a multi-segment uri, * leaving '/' separators */ return uri.split('/').map(encodeURIComponent).join('/'); }; var url_join_encode = function () { /** * join a sequence of url components with '/', * encoding each component with encodeURIComponent */ return encode_uri_components(url_path_join.apply(null, arguments)); }; var splitext = function (filename) { /** * mimic Python os.path.splitext * Returns ['base', '.ext'] */ var idx = filename.lastIndexOf('.'); if (idx > 0) { return [filename.slice(0, idx), filename.slice(idx)]; } else { return [filename, '']; } }; var escape_html = function (text) { /** * escape text to HTML */ return $("
").text(text).html(); }; var get_body_data = function(key) { /** * get a url-encoded item from body.data and decode it * we should never have any encoded URLs anywhere else in code * until we are building an actual request */ var val = $('body').data(key); if (!val) return val; return decodeURIComponent(val); }; var to_absolute_cursor_pos = function (cm, cursor) { /** * get the absolute cursor position from CodeMirror's col, ch */ if (!cursor) { cursor = cm.getCursor(); } var cursor_pos = cursor.ch; for (var i = 0; i < cursor.line; i++) { cursor_pos += cm.getLine(i).length + 1; } return cursor_pos; }; var from_absolute_cursor_pos = function (cm, cursor_pos) { /** * turn absolute cursor postion into CodeMirror col, ch cursor */ var i, line, next_line; var offset = 0; for (i = 0, next_line=cm.getLine(i); next_line !== undefined; i++, next_line=cm.getLine(i)) { line = next_line; if (offset + next_line.length < cursor_pos) { offset += next_line.length + 1; } else { return { line : i, ch : cursor_pos - offset, }; } } // reached end, return endpoint return { line : i - 1, ch : line.length - 1, }; }; // http://stackoverflow.com/questions/2400935/browser-detection-in-javascript var browser = (function() { if (typeof navigator === 'undefined') { // navigator undefined in node return 'None'; } var N= navigator.appName, ua= navigator.userAgent, tem; var M= ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i); if (M && (tem= ua.match(/version\/([\.\d]+)/i)) !== null) M[2]= tem[1]; M= M? [M[1], M[2]]: [N, navigator.appVersion,'-?']; return M; })(); // http://stackoverflow.com/questions/11219582/how-to-detect-my-browser-version-and-operating-system-using-javascript var platform = (function () { if (typeof navigator === 'undefined') { // navigator undefined in node return 'None'; } var OSName="None"; if (navigator.appVersion.indexOf("Win")!=-1) OSName="Windows"; if (navigator.appVersion.indexOf("Mac")!=-1) OSName="MacOS"; if (navigator.appVersion.indexOf("X11")!=-1) OSName="UNIX"; if (navigator.appVersion.indexOf("Linux")!=-1) OSName="Linux"; return OSName; })(); var get_url_param = function (name) { // get a URL parameter. I cannot believe we actually need this. // Based on http://stackoverflow.com/a/25359264/938949 var match = new RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search); if (match){ return decodeURIComponent(match[1] || ''); } }; var is_or_has = function (a, b) { /** * Is b a child of a or a itself? */ return a.has(b).length !==0 || a.is(b); }; var is_focused = function (e) { /** * Is element e, or one of its children focused? */ e = $(e); var target = $(document.activeElement); if (target.length > 0) { if (is_or_has(e, target)) { return true; } else { return false; } } else { return false; } }; var mergeopt = function(_class, options, overwrite){ options = options || {}; overwrite = overwrite || {}; return $.extend(true, {}, _class.options_default, options, overwrite); }; var ajax_error_msg = function (jqXHR) { /** * Return a JSON error message if there is one, * otherwise the basic HTTP status text. */ if (jqXHR.responseJSON && jqXHR.responseJSON.traceback) { return jqXHR.responseJSON.traceback; } else if (jqXHR.responseJSON && jqXHR.responseJSON.message) { return jqXHR.responseJSON.message; } else { return jqXHR.statusText; } }; var log_ajax_error = function (jqXHR, status, error) { /** * log ajax failures with informative messages */ var msg = "API request failed (" + jqXHR.status + "): "; console.log(jqXHR); msg += ajax_error_msg(jqXHR); console.log(msg); }; var requireCodeMirrorMode = function (mode, callback, errback) { /** * find a predefined mode or detect from CM metadata then * require and callback with the resolveable mode string: mime or * custom name */ var modename = (typeof mode == "string") ? mode : mode.mode || mode.name; // simplest, cheapest check by mode name: mode may also have config if (CodeMirror.modes.hasOwnProperty(modename)) { // return the full mode object, if it has a name callback(mode.name ? mode : modename); return; } // *somehow* get back a CM.modeInfo-like object that has .mode and // .mime var info = (mode && mode.mode && mode.mime && mode) || CodeMirror.findModeByName(modename) || CodeMirror.findModeByExtension(modename.split(".").slice(-1)) || CodeMirror.findModeByMIME(modename) || {mode: modename, mime: modename}; require([ // might want to use CodeMirror.modeURL here ['codemirror/mode', info.mode, info.mode].join('/'), ], function() { // return the original mode, as from a kernelspec on first load // or the mimetype, as for most highlighting callback(mode.name ? mode : info.mime); }, errback ); }; /** Error type for wrapped XHR errors. */ var XHR_ERROR = 'XhrError'; /** * Wraps an AJAX error as an Error object. */ var wrap_ajax_error = function (jqXHR, status, error) { var wrapped_error = new Error(ajax_error_msg(jqXHR)); wrapped_error.name = XHR_ERROR; // provide xhr response wrapped_error.xhr = jqXHR; wrapped_error.xhr_status = status; wrapped_error.xhr_error = error; return wrapped_error; }; var promising_ajax = function(url, settings) { /** * Like $.ajax, but returning an ES6 promise. success and error settings * will be ignored. */ settings = settings || {}; return new Promise(function(resolve, reject) { settings.success = function(data, status, jqXHR) { resolve(data); }; settings.error = function(jqXHR, status, error) { log_ajax_error(jqXHR, status, error); reject(wrap_ajax_error(jqXHR, status, error)); }; $.ajax(url, settings); }); }; var WrappedError = function(message, error){ /** * Wrappable Error class * * The Error class doesn't actually act on `this`. Instead it always * returns a new instance of Error. Here we capture that instance so we * can apply it's properties to `this`. */ var tmp = Error.apply(this, [message]); // Copy the properties of the error over to this. var properties = Object.getOwnPropertyNames(tmp); for (var i = 0; i < properties.length; i++) { this[properties[i]] = tmp[properties[i]]; } // Keep a stack of the original error messages. if (error instanceof WrappedError) { this.error_stack = error.error_stack; } else { this.error_stack = [error]; } this.error_stack.push(tmp); return this; }; WrappedError.prototype = Object.create(Error.prototype, {}); var load_class = function(class_name, module_name, registry) { /** * Tries to load a class * * Tries to load a class from a module using require.js, if a module * is specified, otherwise tries to load a class from the global * registry, if the global registry is provided. */ return new Promise(function(resolve, reject) { // Try loading the view module using require.js if (module_name) { require([module_name], function(module) { if (module[class_name] === undefined) { reject(new Error('Class '+class_name+' not found in module '+module_name)); } else { resolve(module[class_name]); } }, reject); } else { if (registry && registry[class_name]) { resolve(registry[class_name]); } else { reject(new Error('Class '+class_name+' not found in registry ')); } } }); }; var resolve_promises_dict = function(d) { /** * Resolve a promiseful dictionary. * Returns a single Promise. */ var keys = Object.keys(d); var values = []; keys.forEach(function(key) { values.push(d[key]); }); return Promise.all(values).then(function(v) { d = {}; for(var i=0; i 1){ $el.text(text); } if(!window.MathJax){ return; } return $el.map(function(){ // MathJax takes a DOM node: $.map makes `this` the context return MathJax.Hub.Queue(["Typeset", MathJax.Hub, this]); }); }; var time = {}; time.milliseconds = {}; time.milliseconds.s = 1000; time.milliseconds.m = 60 * time.milliseconds.s; time.milliseconds.h = 60 * time.milliseconds.m; time.milliseconds.d = 24 * time.milliseconds.h; time.thresholds = { // moment.js thresholds in milliseconds s: moment.relativeTimeThreshold('s') * time.milliseconds.s, m: moment.relativeTimeThreshold('m') * time.milliseconds.m, h: moment.relativeTimeThreshold('h') * time.milliseconds.h, d: moment.relativeTimeThreshold('d') * time.milliseconds.d, }; time.timeout_from_dt = function (dt) { /** compute a timeout based on dt input and output both in milliseconds use moment's relative time thresholds: - 10 seconds if in 'seconds ago' territory - 1 minute if in 'minutes ago' - 1 hour otherwise */ if (dt < time.thresholds.s) { return 10 * time.milliseconds.s; } else if (dt < time.thresholds.m) { return time.milliseconds.m; } else { return time.milliseconds.h; } }; var utils = { load_extensions: load_extensions, load_extensions_from_config: load_extensions_from_config, regex_split : regex_split, uuid : uuid, fixConsole : fixConsole, fixCarriageReturn : fixCarriageReturn, autoLinkUrls : autoLinkUrls, points_to_pixels : points_to_pixels, get_body_data : get_body_data, parse_url : parse_url, url_path_split : url_path_split, url_path_join : url_path_join, url_join_encode : url_join_encode, encode_uri_components : encode_uri_components, splitext : splitext, escape_html : escape_html, always_new : always_new, to_absolute_cursor_pos : to_absolute_cursor_pos, from_absolute_cursor_pos : from_absolute_cursor_pos, browser : browser, platform: platform, get_url_param: get_url_param, is_or_has : is_or_has, is_focused : is_focused, mergeopt: mergeopt, ajax_error_msg : ajax_error_msg, log_ajax_error : log_ajax_error, requireCodeMirrorMode : requireCodeMirrorMode, XHR_ERROR : XHR_ERROR, wrap_ajax_error : wrap_ajax_error, promising_ajax : promising_ajax, WrappedError: WrappedError, load_class: load_class, resolve_promises_dict: resolve_promises_dict, reject: reject, typeset: typeset, time: time, }; // Backwards compatability. IPython.utils = utils; return utils; });