incremental
diff --git a/static/js/bmcApp.js b/static/js/bmcApp.js
index 7392c47..1c91e8f 100644
--- a/static/js/bmcApp.js
+++ b/static/js/bmcApp.js
@@ -1,17 +1,46 @@
'use strict';
angular.module('Authentication', []);
var app = angular.module('bmcApp', [
- 'Authentication', 'ngCookies', 'ui.bootstrap', 'ui.router', 'restangular',
- 'ngSanitize', 'ngWebSocket'
+ 'Authentication', 'ngCookies', 'ui.bootstrap', 'ui.router',
+ 'ngSanitize', 'ngWebSocket', 'ngResource'
]);
-app.controller('MainCtrl', function($scope, Restangular) {
+app.controller('MainCtrl', function($scope) {
});
-app.run(['$rootScope', '$cookieStore', '$state', 'Restangular', 'AuthenticationService',
- function($rootScope, $cookieStore, $state, Restangular, AuthenticationService) {
+app.service('loginInterceptor', function($q, $state) {
+ var service = this;
+
+ service.responseError = function(response) {
+ if (response.status == 401){
+ console.log("Login required... ");
+
+ var invalidate_reason = "Your user was logged out.";
+ var continue_promise_chain = false;
+
+ // if we're attempting to log in, we need to
+ // continue the promise chain to make sure the user is informed
+ if ($state.current.name === "login") {
+ invalidate_reason = "Your username and password was incorrect";
+ continue_promise_chain = true
+ } else {
+ $state.after_login_state = $state.current.name;
+ $state.go('login');
+ }
+ AuthenticationService.ClearCredentials(invalidate_reason);
+ }
+ //return $q.reject(response);
+ };
+})
+
+app.config(['$httpProvider', function ($httpProvider) {
+ $httpProvider.interceptors.push('loginInterceptor');
+}]);
+
+app.run(['$rootScope', '$cookieStore', '$state', '$resource', 'AuthenticationService',
+ function($rootScope, $cookieStore, $state, $resource, AuthenticationService) {
if ($rootScope.globals == undefined){
$rootScope.globals = {};
}
@@ -29,49 +58,9 @@
$state.go('login');
}
});
-
- // RestangularProvider.setDefaultHttpFields({cache: true});
- Restangular.setErrorInterceptor(function(response) {
- if (response.status == 401) {
- console.log("Login required... ");
-
- var invalidate_reason = "Your user was logged out.";
- var continue_promise_chain = false;
-
- // if we're attempting to log in, we need to
- // continue the promise chain to make sure the user is informed
- if ($state.current.name === "login") {
- invalidate_reason = "Your username and password was incorrect";
- continue_promise_chain = true
- } else {
- $state.after_login_state = $state.current.name;
- $state.go('login');
- }
- AuthenticationService.ClearCredentials(invalidate_reason);
-
- return continue_promise_chain; // stop the promise chain
- } else if (response.status == 404) {
- console.log("Resource not available...");
- } else {
- console.log(
- "Response received with HTTP error code: " + response.status);
- }
-
- });
-
}
]);
-app.config(function(RestangularProvider) {
- // set the base url for api calls on our RESTful services
- var newBaseUrl = "";
-
- var deployedAt = window.location.href.substring(0, window.location.href);
- newBaseUrl = deployedAt + "/restui";
-
- RestangularProvider.setBaseUrl(newBaseUrl);
-});
-
app.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/systeminfo');
@@ -80,30 +69,30 @@
// nested list with just some random string data
.state('login', {
url: '/login',
- templateUrl: 'login.html',
+ templateUrl: 'static/login.html',
controller: 'LoginController',
})
// systeminfo view ========================================
.state(
'systeminfo',
- {url: '/systeminfo', templateUrl: 'partial-systeminfo.html'})
+ {url: '/systeminfo', templateUrl: 'static/partial-systeminfo.html'})
// HOME STATES AND NESTED VIEWS ========================================
.state(
- 'eventlog', {url: '/eventlog', templateUrl: 'partial-eventlog.html'})
+ 'eventlog', {url: '/eventlog', templateUrl: 'static/partial-eventlog.html'})
.state(
- 'kvm', {url: '/kvm', templateUrl: 'partial-kvm.html'})
+ 'kvm', {url: '/kvm', templateUrl: 'static/partial-kvm.html'})
// ABOUT PAGE AND MULTIPLE NAMED VIEWS =================================
- .state('about', {url: '/about', templateUrl: 'partial-fruinfo.html'})
+ .state('about', {url: '/about', templateUrl: 'static/partial-fruinfo.html'})
// nested list with custom controller
.state('about.list', {
url: '/list',
- templateUrl: 'partial-home-list.html',
+ templateUrl: 'static/partial-home-list.html',
controller: function($scope) {
$scope.dogs = ['Bernese', 'Husky', 'Goldendoodle'];
}
@@ -127,22 +116,22 @@
$scope.bigCurrentPage = 1;
});
-angular
- .module('Authentication')
+angular.module('Authentication')
.factory(
'AuthenticationService',
- [
- 'Restangular', '$cookieStore', '$rootScope', '$timeout',
- function(Restangular, $cookieStore, $rootScope, $timeout) {
+ ['$cookieStore', '$rootScope', '$timeout', '$resource', '$log',
+ function($cookieStore, $rootScope, $timeout, $resource, $log) {
var service = {};
- service.Login = function(
- username, password, success_callback, fail_callback) {
+ service.Login = function(username, password, success_callback, fail_callback) {
var user = {"username": username, "password": password};
- Restangular.all("login").post(user).then(
- success_callback, fail_callback);
+ var UserLogin = $resource("/login");
+ var this_login = new UserLogin();
+ this_login.data = {"username": username, "password": password};
+ UserLogin.save(user, success_callback, fail_callback);
+
};
service.SetCredentials = function(username, token) {
diff --git a/static/js/logincontroller.js b/static/js/logincontroller.js
index d0b7a7f..e83d8bc 100644
--- a/static/js/logincontroller.js
+++ b/static/js/logincontroller.js
@@ -29,4 +29,4 @@
});
};
}
-]);
\ No newline at end of file
+]);
diff --git a/static/js/restangular.js b/static/js/restangular.js
deleted file mode 100644
index b59b25f..0000000
--- a/static/js/restangular.js
+++ /dev/null
@@ -1,1452 +0,0 @@
-/**
- * Restful Resources service for AngularJS apps
- * @version v1.6.1 - 2017-01-06 * @link https://github.com/mgonto/restangular
- * @author Martin Gontovnikas <martin@gon.to>
- * @license MIT License, http://www.opensource.org/licenses/MIT
- */(function(root, factory) {
- /* global define, require */
- // https://github.com/umdjs/umd/blob/master/templates/returnExports.js
- if (typeof define === 'function' && define.amd) {
- define(['lodash', 'angular'], factory);
- } else if (typeof module === 'object' && module.exports) {
- module.exports = factory(require('lodash'), require('angular'));
- } else {
- // No global export, Restangular will register itself as Angular.js module
- factory(root._, root.angular);
- }
-}(this, function(_, angular) {
-
- var restangular = angular.module('restangular', []);
-
- restangular.provider('Restangular', function() {
- // Configuration
- var Configurer = {};
- Configurer.init = function(object, config) {
- object.configuration = config;
-
- /**
- * Those are HTTP safe methods for which there is no need to pass any data with the request.
- */
- var safeMethods = ['get', 'head', 'options', 'trace', 'getlist'];
- config.isSafe = function(operation) {
- return _.includes(safeMethods, operation.toLowerCase());
- };
-
- var absolutePattern = /^https?:\/\//i;
- config.isAbsoluteUrl = function(string) {
- return _.isUndefined(config.absoluteUrl) || _.isNull(config.absoluteUrl) ?
- string && absolutePattern.test(string) :
- config.absoluteUrl;
- };
-
- config.absoluteUrl = _.isUndefined(config.absoluteUrl) ? true : config.absoluteUrl;
- object.setSelfLinkAbsoluteUrl = function(value) {
- config.absoluteUrl = value;
- };
- /**
- * This is the BaseURL to be used with Restangular
- */
- config.baseUrl = _.isUndefined(config.baseUrl) ? '' : config.baseUrl;
- object.setBaseUrl = function(newBaseUrl) {
- config.baseUrl = /\/$/.test(newBaseUrl) ?
- newBaseUrl.substring(0, newBaseUrl.length - 1) :
- newBaseUrl;
- return this;
- };
-
- /**
- * Sets the extra fields to keep from the parents
- */
- config.extraFields = config.extraFields || [];
- object.setExtraFields = function(newExtraFields) {
- config.extraFields = newExtraFields;
- return this;
- };
-
- /**
- * Some default $http parameter to be used in EVERY call
- **/
- config.defaultHttpFields = config.defaultHttpFields || {};
- object.setDefaultHttpFields = function(values) {
- config.defaultHttpFields = values;
- return this;
- };
-
- /**
- * Always return plain data, no restangularized object
- **/
- config.plainByDefault = config.plainByDefault || false;
- object.setPlainByDefault = function(value) {
- config.plainByDefault = value === true ? true : false;
- return this;
- };
-
- config.withHttpValues = function(httpLocalConfig, obj) {
- return _.defaults(obj, httpLocalConfig, config.defaultHttpFields);
- };
-
- config.encodeIds = _.isUndefined(config.encodeIds) ? true : config.encodeIds;
- object.setEncodeIds = function(encode) {
- config.encodeIds = encode;
- };
-
- config.defaultRequestParams = config.defaultRequestParams || {
- get: {},
- post: {},
- put: {},
- remove: {},
- common: {}
- };
-
- object.setDefaultRequestParams = function(param1, param2) {
- var methods = [],
- params = param2 || param1;
- if (!_.isUndefined(param2)) {
- if (_.isArray(param1)) {
- methods = param1;
- } else {
- methods.push(param1);
- }
- } else {
- methods.push('common');
- }
-
- _.each(methods, function(method) {
- config.defaultRequestParams[method] = params;
- });
- return this;
- };
-
- object.requestParams = config.defaultRequestParams;
-
- config.defaultHeaders = config.defaultHeaders || {};
- object.setDefaultHeaders = function(headers) {
- config.defaultHeaders = headers;
- object.defaultHeaders = config.defaultHeaders;
- return this;
- };
-
- object.defaultHeaders = config.defaultHeaders;
-
- /**
- * Method overriders will set which methods are sent via POST with an X-HTTP-Method-Override
- **/
- config.methodOverriders = config.methodOverriders || [];
- object.setMethodOverriders = function(values) {
- var overriders = _.extend([], values);
- if (config.isOverridenMethod('delete', overriders)) {
- overriders.push('remove');
- }
- config.methodOverriders = overriders;
- return this;
- };
-
- config.jsonp = _.isUndefined(config.jsonp) ? false : config.jsonp;
- object.setJsonp = function(active) {
- config.jsonp = active;
- };
-
- config.isOverridenMethod = function(method, values) {
- var search = values || config.methodOverriders;
- return !_.isUndefined(_.find(search, function(one) {
- return one.toLowerCase() === method.toLowerCase();
- }));
- };
-
- /**
- * Sets the URL creator type. For now, only Path is created. In the future we'll have queryParams
- **/
- config.urlCreator = config.urlCreator || 'path';
- object.setUrlCreator = function(name) {
- if (!_.has(config.urlCreatorFactory, name)) {
- throw new Error('URL Path selected isn\'t valid');
- }
-
- config.urlCreator = name;
- return this;
- };
-
- /**
- * You can set the restangular fields here. The 3 required fields for Restangular are:
- *
- * id: Id of the element
- * route: name of the route of this element
- * parentResource: the reference to the parent resource
- *
- * All of this fields except for id, are handled (and created) by Restangular. By default,
- * the field values will be id, route and parentResource respectively
- */
- config.restangularFields = config.restangularFields || {
- id: 'id',
- route: 'route',
- parentResource: 'parentResource',
- restangularCollection: 'restangularCollection',
- cannonicalId: '__cannonicalId',
- etag: 'restangularEtag',
- selfLink: 'href',
- get: 'get',
- getList: 'getList',
- put: 'put',
- post: 'post',
- remove: 'remove',
- head: 'head',
- trace: 'trace',
- options: 'options',
- patch: 'patch',
- getRestangularUrl: 'getRestangularUrl',
- getRequestedUrl: 'getRequestedUrl',
- putElement: 'putElement',
- addRestangularMethod: 'addRestangularMethod',
- getParentList: 'getParentList',
- clone: 'clone',
- ids: 'ids',
- httpConfig: '_$httpConfig',
- reqParams: 'reqParams',
- one: 'one',
- all: 'all',
- several: 'several',
- oneUrl: 'oneUrl',
- allUrl: 'allUrl',
- customPUT: 'customPUT',
- customPATCH: 'customPATCH',
- customPOST: 'customPOST',
- customDELETE: 'customDELETE',
- customGET: 'customGET',
- customGETLIST: 'customGETLIST',
- customOperation: 'customOperation',
- doPUT: 'doPUT',
- doPATCH: 'doPATCH',
- doPOST: 'doPOST',
- doDELETE: 'doDELETE',
- doGET: 'doGET',
- doGETLIST: 'doGETLIST',
- fromServer: 'fromServer',
- withConfig: 'withConfig',
- withHttpConfig: 'withHttpConfig',
- singleOne: 'singleOne',
- plain: 'plain',
- save: 'save',
- restangularized: 'restangularized'
- };
- object.setRestangularFields = function(resFields) {
- config.restangularFields =
- _.extend(config.restangularFields, resFields);
- return this;
- };
-
- config.isRestangularized = function(obj) {
- return !!obj[config.restangularFields.restangularized];
- };
-
- config.setFieldToElem = function(field, elem, value) {
- var properties = field.split('.');
- var idValue = elem;
- _.each(_.initial(properties), function(prop) {
- idValue[prop] = {};
- idValue = idValue[prop];
- });
- idValue[_.last(properties)] = value;
- return this;
- };
-
- config.getFieldFromElem = function(field, elem) {
- var properties = field.split('.');
- var idValue = elem;
- _.each(properties, function(prop) {
- if (idValue) {
- idValue = idValue[prop];
- }
- });
- return angular.copy(idValue);
- };
-
- config.setIdToElem = function(elem, id /*, route */ ) {
- config.setFieldToElem(config.restangularFields.id, elem, id);
- return this;
- };
-
- config.getIdFromElem = function(elem) {
- return config.getFieldFromElem(config.restangularFields.id, elem);
- };
-
- config.isValidId = function(elemId) {
- return '' !== elemId && !_.isUndefined(elemId) && !_.isNull(elemId);
- };
-
- config.setUrlToElem = function(elem, url /*, route */ ) {
- config.setFieldToElem(config.restangularFields.selfLink, elem, url);
- return this;
- };
-
- config.getUrlFromElem = function(elem) {
- return config.getFieldFromElem(config.restangularFields.selfLink, elem);
- };
-
- config.useCannonicalId = _.isUndefined(config.useCannonicalId) ? false : config.useCannonicalId;
- object.setUseCannonicalId = function(value) {
- config.useCannonicalId = value;
- return this;
- };
-
- config.getCannonicalIdFromElem = function(elem) {
- var cannonicalId = elem[config.restangularFields.cannonicalId];
- var actualId = config.isValidId(cannonicalId) ? cannonicalId : config.getIdFromElem(elem);
- return actualId;
- };
-
- /**
- * Sets the Response parser. This is used in case your response isn't directly the data.
- * For example if you have a response like {meta: {'meta'}, data: {name: 'Gonto'}}
- * you can extract this data which is the one that needs wrapping
- *
- * The ResponseExtractor is a function that receives the response and the method executed.
- */
-
- config.responseInterceptors = config.responseInterceptors || [];
-
- config.defaultResponseInterceptor = function(data /*, operation, what, url, response, deferred */ ) {
- return data;
- };
-
- config.responseExtractor = function(data, operation, what, url, response, deferred) {
- var interceptors = angular.copy(config.responseInterceptors);
- interceptors.push(config.defaultResponseInterceptor);
- var theData = data;
- _.each(interceptors, function(interceptor) {
- theData = interceptor(theData, operation,
- what, url, response, deferred);
- });
- return theData;
- };
-
- object.addResponseInterceptor = function(extractor) {
- config.responseInterceptors.push(extractor);
- return this;
- };
-
- config.errorInterceptors = config.errorInterceptors || [];
- object.addErrorInterceptor = function(interceptor) {
- config.errorInterceptors.push(interceptor);
- return this;
- };
-
- object.setResponseInterceptor = object.addResponseInterceptor;
- object.setResponseExtractor = object.addResponseInterceptor;
- object.setErrorInterceptor = object.addErrorInterceptor;
-
- /**
- * Response interceptor is called just before resolving promises.
- */
-
-
- /**
- * Request interceptor is called before sending an object to the server.
- */
- config.requestInterceptors = config.requestInterceptors || [];
-
- config.defaultInterceptor = function(element, operation, path, url, headers, params, httpConfig) {
- return {
- element: element,
- headers: headers,
- params: params,
- httpConfig: httpConfig
- };
- };
-
- config.fullRequestInterceptor = function(element, operation, path, url, headers, params, httpConfig) {
- var interceptors = angular.copy(config.requestInterceptors);
- var defaultRequest = config.defaultInterceptor(element, operation, path, url, headers, params, httpConfig);
- return _.reduce(interceptors, function(request, interceptor) {
- return _.extend(request, interceptor(request.element, operation,
- path, url, request.headers, request.params, request.httpConfig));
- }, defaultRequest);
- };
-
- object.addRequestInterceptor = function(interceptor) {
- config.requestInterceptors.push(function(elem, operation, path, url, headers, params, httpConfig) {
- return {
- headers: headers,
- params: params,
- element: interceptor(elem, operation, path, url),
- httpConfig: httpConfig
- };
- });
- return this;
- };
-
- object.setRequestInterceptor = object.addRequestInterceptor;
-
- object.addFullRequestInterceptor = function(interceptor) {
- config.requestInterceptors.push(interceptor);
- return this;
- };
-
- object.setFullRequestInterceptor = object.addFullRequestInterceptor;
-
- config.onBeforeElemRestangularized = config.onBeforeElemRestangularized || function(elem) {
- return elem;
- };
- object.setOnBeforeElemRestangularized = function(post) {
- config.onBeforeElemRestangularized = post;
- return this;
- };
-
- object.setRestangularizePromiseInterceptor = function(interceptor) {
- config.restangularizePromiseInterceptor = interceptor;
- return this;
- };
-
- /**
- * This method is called after an element has been "Restangularized".
- *
- * It receives the element, a boolean indicating if it's an element or a collection
- * and the name of the model
- *
- */
- config.onElemRestangularized = config.onElemRestangularized || function(elem) {
- return elem;
- };
- object.setOnElemRestangularized = function(post) {
- config.onElemRestangularized = post;
- return this;
- };
-
- config.shouldSaveParent = config.shouldSaveParent || function() {
- return true;
- };
- object.setParentless = function(values) {
- if (_.isArray(values)) {
- config.shouldSaveParent = function(route) {
- return !_.includes(values, route);
- };
- } else if (_.isBoolean(values)) {
- config.shouldSaveParent = function() {
- return !values;
- };
- }
- return this;
- };
-
- /**
- * This lets you set a suffix to every request.
- *
- * For example, if your api requires that for JSon requests you do /users/123.json, you can set that
- * in here.
- *
- *
- * By default, the suffix is null
- */
- config.suffix = _.isUndefined(config.suffix) ? null : config.suffix;
- object.setRequestSuffix = function(newSuffix) {
- config.suffix = newSuffix;
- return this;
- };
-
- /**
- * Add element transformers for certain routes.
- */
- config.transformers = config.transformers || {};
- config.matchTransformers = config.matchTransformers || [];
- object.addElementTransformer = function(type, secondArg, thirdArg) {
- var isCollection = null;
- var transformer = null;
- if (arguments.length === 2) {
- transformer = secondArg;
- } else {
- transformer = thirdArg;
- isCollection = secondArg;
- }
-
- var transformerFn = function(coll, elem) {
- if (_.isNull(isCollection) || (coll === isCollection)) {
- return transformer(elem);
- }
- return elem;
- };
-
- if (_.isRegExp(type)) {
- config.matchTransformers.push({
- regexp: type,
- transformer: transformerFn
- });
- } else {
- if (!config.transformers[type]) {
- config.transformers[type] = [];
- }
- config.transformers[type].push(transformerFn);
- }
-
- return object;
- };
-
- object.extendCollection = function(route, fn) {
- return object.addElementTransformer(route, true, fn);
- };
-
- object.extendModel = function(route, fn) {
- return object.addElementTransformer(route, false, fn);
- };
-
- config.transformElem = function(elem, isCollection, route, Restangular, force) {
- if (!force && !config.transformLocalElements && !elem[config.restangularFields.fromServer]) {
- return elem;
- }
-
- var changedElem = elem;
-
- var matchTransformers = config.matchTransformers;
- if (matchTransformers) {
- _.each(matchTransformers, function(transformer) {
- if (transformer.regexp.test(route)) {
- changedElem = transformer.transformer(isCollection, changedElem);
- }
- });
- }
-
- var typeTransformers = config.transformers[route];
- if (typeTransformers) {
- _.each(typeTransformers, function(transformer) {
- changedElem = transformer(isCollection, changedElem);
- });
- }
- return config.onElemRestangularized(changedElem, isCollection, route, Restangular);
- };
-
- config.transformLocalElements = _.isUndefined(config.transformLocalElements) ?
- false :
- config.transformLocalElements;
-
- object.setTransformOnlyServerElements = function(active) {
- config.transformLocalElements = !active;
- };
-
- config.fullResponse = _.isUndefined(config.fullResponse) ? false : config.fullResponse;
- object.setFullResponse = function(full) {
- config.fullResponse = full;
- return this;
- };
-
-
- //Internal values and functions
- config.urlCreatorFactory = {};
-
- /**
- * Base URL Creator. Base prototype for everything related to it
- **/
-
- var BaseCreator = function() {};
-
- BaseCreator.prototype.setConfig = function(config) {
- this.config = config;
- return this;
- };
-
- BaseCreator.prototype.parentsArray = function(current) {
- var parents = [];
- while (current) {
- parents.push(current);
- current = current[this.config.restangularFields.parentResource];
- }
- return parents.reverse();
- };
-
- function RestangularResource(config, $http, url, configurer) {
- var resource = {};
- _.each(_.keys(configurer), function(key) {
- var value = configurer[key];
-
- // Add default parameters
- value.params = _.extend({}, value.params, config.defaultRequestParams[value.method.toLowerCase()]);
- // We don't want the ? if no params are there
- if (_.isEmpty(value.params)) {
- delete value.params;
- }
-
- if (config.isSafe(value.method)) {
-
- resource[key] = function() {
- return $http(_.extend(value, {
- url: url
- }));
- };
-
- } else {
-
- resource[key] = function(data) {
- return $http(_.extend(value, {
- url: url,
- data: data
- }));
- };
-
- }
- });
-
- return resource;
- }
-
- BaseCreator.prototype.resource = function(current, $http, localHttpConfig, callHeaders, callParams, what, etag, operation) {
-
- var params = _.defaults(callParams || {}, this.config.defaultRequestParams.common);
- var headers = _.defaults(callHeaders || {}, this.config.defaultHeaders);
-
- if (etag) {
- if (!config.isSafe(operation)) {
- headers['If-Match'] = etag;
- } else {
- headers['If-None-Match'] = etag;
- }
- }
-
- var url = this.base(current);
-
- if (what || what === 0) {
- var add = '';
- if (!/\/$/.test(url)) {
- add += '/';
- }
- add += what;
- url += add;
- }
-
- if (this.config.suffix &&
- url.indexOf(this.config.suffix, url.length - this.config.suffix.length) === -1 &&
- !this.config.getUrlFromElem(current)) {
- url += this.config.suffix;
- }
-
- current[this.config.restangularFields.httpConfig] = undefined;
-
- return RestangularResource(this.config, $http, url, {
- getList: this.config.withHttpValues(localHttpConfig, {
- method: 'GET',
- params: params,
- headers: headers
- }),
-
- get: this.config.withHttpValues(localHttpConfig, {
- method: 'GET',
- params: params,
- headers: headers
- }),
-
- jsonp: this.config.withHttpValues(localHttpConfig, {
- method: 'jsonp',
- params: params,
- headers: headers
- }),
-
- put: this.config.withHttpValues(localHttpConfig, {
- method: 'PUT',
- params: params,
- headers: headers
- }),
-
- post: this.config.withHttpValues(localHttpConfig, {
- method: 'POST',
- params: params,
- headers: headers
- }),
-
- remove: this.config.withHttpValues(localHttpConfig, {
- method: 'DELETE',
- params: params,
- headers: headers
- }),
-
- head: this.config.withHttpValues(localHttpConfig, {
- method: 'HEAD',
- params: params,
- headers: headers
- }),
-
- trace: this.config.withHttpValues(localHttpConfig, {
- method: 'TRACE',
- params: params,
- headers: headers
- }),
-
- options: this.config.withHttpValues(localHttpConfig, {
- method: 'OPTIONS',
- params: params,
- headers: headers
- }),
-
- patch: this.config.withHttpValues(localHttpConfig, {
- method: 'PATCH',
- params: params,
- headers: headers
- })
- });
- };
-
- /**
- * This is the Path URL creator. It uses Path to show Hierarchy in the Rest API.
- * This means that if you have an Account that then has a set of Buildings, a URL to a building
- * would be /accounts/123/buildings/456
- **/
- var Path = function() {};
-
- Path.prototype = new BaseCreator();
-
- Path.prototype.normalizeUrl = function(url) {
- var parts = /((?:http[s]?:)?\/\/)?(.*)?/.exec(url);
- parts[2] = parts[2].replace(/[\\\/]+/g, '/');
- return (typeof parts[1] !== 'undefined') ? parts[1] + parts[2] : parts[2];
- };
-
- Path.prototype.base = function(current) {
- var __this = this;
- return _.reduce(this.parentsArray(current), function(acum, elem) {
- var elemUrl;
- var elemSelfLink = __this.config.getUrlFromElem(elem);
- if (elemSelfLink) {
- if (__this.config.isAbsoluteUrl(elemSelfLink)) {
- return elemSelfLink;
- } else {
- elemUrl = elemSelfLink;
- }
- } else {
- elemUrl = elem[__this.config.restangularFields.route];
-
- if (elem[__this.config.restangularFields.restangularCollection]) {
- var ids = elem[__this.config.restangularFields.ids];
- if (ids) {
- elemUrl += '/' + ids.join(',');
- }
- } else {
- var elemId;
- if (__this.config.useCannonicalId) {
- elemId = __this.config.getCannonicalIdFromElem(elem);
- } else {
- elemId = __this.config.getIdFromElem(elem);
- }
-
- if (config.isValidId(elemId) && !elem.singleOne) {
- elemUrl += '/' + (__this.config.encodeIds ? encodeURIComponent(elemId) : elemId);
- }
- }
- }
- acum = acum.replace(/\/$/, '') + '/' + elemUrl;
- return __this.normalizeUrl(acum);
-
- }, this.config.baseUrl);
- };
-
-
-
- Path.prototype.fetchUrl = function(current, what) {
- var baseUrl = this.base(current);
- if (what) {
- baseUrl += '/' + what;
- }
- return baseUrl;
- };
-
- Path.prototype.fetchRequestedUrl = function(current, what) {
- var url = this.fetchUrl(current, what);
- var params = current[config.restangularFields.reqParams];
-
- // From here on and until the end of fetchRequestedUrl,
- // the code has been kindly borrowed from angular.js
- // The reason for such code bloating is coherence:
- // If the user were to use this for cache management, the
- // serialization of parameters would need to be identical
- // to the one done by angular for cache keys to match.
- function sortedKeys(obj) {
- var keys = [];
- for (var key in obj) {
- if (obj.hasOwnProperty(key)) {
- keys.push(key);
- }
- }
- return keys.sort();
- }
-
- function forEachSorted(obj, iterator, context) {
- var keys = sortedKeys(obj);
- for (var i = 0; i < keys.length; i++) {
- iterator.call(context, obj[keys[i]], keys[i]);
- }
- return keys;
- }
-
- function encodeUriQuery(val, pctEncodeSpaces) {
- return encodeURIComponent(val).
- replace(/%40/gi, '@').
- replace(/%3A/gi, ':').
- replace(/%24/g, '$').
- replace(/%2C/gi, ',').
- replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
- }
-
- if (!params) {
- return url + (this.config.suffix || '');
- }
-
- var parts = [];
- forEachSorted(params, function(value, key) {
- if (value === null || value === undefined) {
- return;
- }
- if (!angular.isArray(value)) {
- value = [value];
- }
-
- angular.forEach(value, function(v) {
- if (angular.isObject(v)) {
- v = angular.toJson(v);
- }
- parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(v));
- });
- });
-
- return url + (this.config.suffix || '') + ((url.indexOf('?') === -1) ? '?' : '&') + parts.join('&');
- };
-
- config.urlCreatorFactory.path = Path;
- };
-
- var globalConfiguration = {};
-
- Configurer.init(this, globalConfiguration);
-
-
-
- this.$get = ['$http', '$q', function($http, $q) {
-
- function createServiceForConfiguration(config) {
- var service = {};
-
- var urlHandler = new config.urlCreatorFactory[config.urlCreator]();
- urlHandler.setConfig(config);
-
- function restangularizeBase(parent, elem, route, reqParams, fromServer) {
- elem[config.restangularFields.route] = route;
- elem[config.restangularFields.getRestangularUrl] = _.bind(urlHandler.fetchUrl, urlHandler, elem);
- elem[config.restangularFields.getRequestedUrl] = _.bind(urlHandler.fetchRequestedUrl, urlHandler, elem);
- elem[config.restangularFields.addRestangularMethod] = _.bind(addRestangularMethodFunction, elem);
- elem[config.restangularFields.clone] = _.bind(copyRestangularizedElement, elem, elem);
- elem[config.restangularFields.reqParams] = _.isEmpty(reqParams) ? null : reqParams;
- elem[config.restangularFields.withHttpConfig] = _.bind(withHttpConfig, elem);
- elem[config.restangularFields.plain] = _.bind(stripRestangular, elem, elem);
-
- // Tag element as restangularized
- elem[config.restangularFields.restangularized] = true;
-
- // RequestLess connection
- elem[config.restangularFields.one] = _.bind(one, elem, elem);
- elem[config.restangularFields.all] = _.bind(all, elem, elem);
- elem[config.restangularFields.several] = _.bind(several, elem, elem);
- elem[config.restangularFields.oneUrl] = _.bind(oneUrl, elem, elem);
- elem[config.restangularFields.allUrl] = _.bind(allUrl, elem, elem);
-
- elem[config.restangularFields.fromServer] = !!fromServer;
-
- if (parent && config.shouldSaveParent(route)) {
- var parentId = config.getIdFromElem(parent);
- var parentUrl = config.getUrlFromElem(parent);
-
- var restangularFieldsForParent = _.union(
- _.values(_.pick(config.restangularFields, ['route', 'singleOne', 'parentResource'])),
- config.extraFields
- );
- var parentResource = _.pick(parent, restangularFieldsForParent);
-
- if (config.isValidId(parentId)) {
- config.setIdToElem(parentResource, parentId, route);
- }
- if (config.isValidId(parentUrl)) {
- config.setUrlToElem(parentResource, parentUrl, route);
- }
-
- elem[config.restangularFields.parentResource] = parentResource;
- } else {
- elem[config.restangularFields.parentResource] = null;
- }
- return elem;
- }
-
- function one(parent, route, id, singleOne) {
- var error;
- if (_.isNumber(route) || _.isNumber(parent)) {
- error = 'You\'re creating a Restangular entity with the number ';
- error += 'instead of the route or the parent. For example, you can\'t call .one(12).';
- throw new Error(error);
- }
- if (_.isUndefined(route)) {
- error = 'You\'re creating a Restangular entity either without the path. ';
- error += 'For example you can\'t call .one(). Please check if your arguments are valid.';
- throw new Error(error);
- }
- var elem = {};
- config.setIdToElem(elem, id, route);
- config.setFieldToElem(config.restangularFields.singleOne, elem, singleOne);
- return restangularizeElem(parent, elem, route, false);
- }
-
-
- function all(parent, route) {
- return restangularizeCollection(parent, [], route, false);
- }
-
- function several(parent, route /*, ids */ ) {
- var collection = [];
- collection[config.restangularFields.ids] = Array.prototype.splice.call(arguments, 2);
- return restangularizeCollection(parent, collection, route, false);
- }
-
- function oneUrl(parent, route, url) {
- if (!route) {
- throw new Error('Route is mandatory when creating new Restangular objects.');
- }
- var elem = {};
- config.setUrlToElem(elem, url, route);
- return restangularizeElem(parent, elem, route, false);
- }
-
-
- function allUrl(parent, route, url) {
- if (!route) {
- throw new Error('Route is mandatory when creating new Restangular objects.');
- }
- var elem = {};
- config.setUrlToElem(elem, url, route);
- return restangularizeCollection(parent, elem, route, false);
- }
- // Promises
- function restangularizePromise(promise, isCollection, valueToFill) {
- promise.call = _.bind(promiseCall, promise);
- promise.get = _.bind(promiseGet, promise);
- promise[config.restangularFields.restangularCollection] = isCollection;
- if (isCollection) {
- promise.push = _.bind(promiseCall, promise, 'push');
- }
- promise.$object = valueToFill;
- if (config.restangularizePromiseInterceptor) {
- config.restangularizePromiseInterceptor(promise);
- }
- return promise;
- }
-
- function promiseCall(method) {
- var deferred = $q.defer();
- var callArgs = arguments;
- var filledValue = {};
- this.then(function(val) {
- var params = Array.prototype.slice.call(callArgs, 1);
- var func = val[method];
- func.apply(val, params);
- filledValue = val;
- deferred.resolve(val);
- });
- return restangularizePromise(deferred.promise, this[config.restangularFields.restangularCollection], filledValue);
- }
-
- function promiseGet(what) {
- var deferred = $q.defer();
- var filledValue = {};
- this.then(function(val) {
- filledValue = val[what];
- deferred.resolve(filledValue);
- });
- return restangularizePromise(deferred.promise, this[config.restangularFields.restangularCollection], filledValue);
- }
-
- function resolvePromise(deferred, response, data, filledValue) {
- _.extend(filledValue, data);
-
- // Trigger the full response interceptor.
- if (config.fullResponse) {
- return deferred.resolve(_.extend(response, {
- data: data
- }));
- } else {
- deferred.resolve(data);
- }
- }
-
-
- // Elements
- function stripRestangular(elem) {
- if (_.isArray(elem)) {
- var array = [];
- _.each(elem, function(value) {
- array.push(config.isRestangularized(value) ? stripRestangular(value) : value);
- });
- return array;
- } else {
- return _.omit(elem, _.values(_.omit(config.restangularFields, 'id')));
- }
- }
-
- function addCustomOperation(elem) {
- elem[config.restangularFields.customOperation] = _.bind(customFunction, elem);
- var requestMethods = {
- get: customFunction,
- delete: customFunction
- };
- _.each(['put', 'patch', 'post'], function(name) {
- requestMethods[name] = function(operation, elem, path, params, headers) {
- return _.bind(customFunction, this)(operation, path, params, headers, elem);
- };
- });
- _.each(requestMethods, function(requestFunc, name) {
- var callOperation = name === 'delete' ? 'remove' : name;
- _.each(['do', 'custom'], function(alias) {
- elem[alias + name.toUpperCase()] = _.bind(requestFunc, elem, callOperation);
- });
- });
- elem[config.restangularFields.customGETLIST] = _.bind(fetchFunction, elem);
- elem[config.restangularFields.doGETLIST] = elem[config.restangularFields.customGETLIST];
- }
-
- function copyRestangularizedElement(element) {
- var copiedElement = angular.copy(element);
-
- // check if we're dealing with a collection (i.e. an array)
- // and restangularize the element using the proper restangularizer,
- // element / collection
- if (_.isArray(element)) {
- return restangularizeCollection(
- element[config.restangularFields.parentResource],
- copiedElement,
- element[config.restangularFields.route],
- element[config.restangularFields.fromServer],
- element[config.restangularFields.reqParams]
- );
- }
-
- // not a collection, restangularize it as an element
- return restangularizeElem(
- element[config.restangularFields.parentResource],
- copiedElement,
- element[config.restangularFields.route],
- element[config.restangularFields.fromServer],
- element[config.restangularFields.restangularCollection],
- element[config.restangularFields.reqParams]
- );
- }
-
- function restangularizeElem(parent, element, route, fromServer, collection, reqParams) {
- var elem = config.onBeforeElemRestangularized(element, false, route);
-
- var localElem = restangularizeBase(parent, elem, route, reqParams, fromServer);
-
- if (config.useCannonicalId) {
- localElem[config.restangularFields.cannonicalId] = config.getIdFromElem(localElem);
- }
-
- if (collection) {
- localElem[config.restangularFields.getParentList] = function() {
- return collection;
- };
- }
-
- localElem[config.restangularFields.restangularCollection] = false;
- localElem[config.restangularFields.get] = _.bind(getFunction, localElem);
- localElem[config.restangularFields.getList] = _.bind(fetchFunction, localElem);
- localElem[config.restangularFields.put] = _.bind(putFunction, localElem);
- localElem[config.restangularFields.post] = _.bind(postFunction, localElem);
- localElem[config.restangularFields.remove] = _.bind(deleteFunction, localElem);
- localElem[config.restangularFields.head] = _.bind(headFunction, localElem);
- localElem[config.restangularFields.trace] = _.bind(traceFunction, localElem);
- localElem[config.restangularFields.options] = _.bind(optionsFunction, localElem);
- localElem[config.restangularFields.patch] = _.bind(patchFunction, localElem);
- localElem[config.restangularFields.save] = _.bind(save, localElem);
-
- addCustomOperation(localElem);
- return config.transformElem(localElem, false, route, service, true);
- }
-
- function restangularizeCollection(parent, element, route, fromServer, reqParams) {
- var elem = config.onBeforeElemRestangularized(element, true, route);
-
- var localElem = restangularizeBase(parent, elem, route, reqParams, fromServer);
- localElem[config.restangularFields.restangularCollection] = true;
- localElem[config.restangularFields.post] = _.bind(postFunction, localElem, null);
- localElem[config.restangularFields.remove] = _.bind(deleteFunction, localElem);
- localElem[config.restangularFields.head] = _.bind(headFunction, localElem);
- localElem[config.restangularFields.trace] = _.bind(traceFunction, localElem);
- localElem[config.restangularFields.putElement] = _.bind(putElementFunction, localElem);
- localElem[config.restangularFields.options] = _.bind(optionsFunction, localElem);
- localElem[config.restangularFields.patch] = _.bind(patchFunction, localElem);
- localElem[config.restangularFields.get] = _.bind(getById, localElem);
- localElem[config.restangularFields.getList] = _.bind(fetchFunction, localElem, null);
-
- addCustomOperation(localElem);
- return config.transformElem(localElem, true, route, service, true);
- }
-
- function restangularizeCollectionAndElements(parent, element, route, fromServer) {
- var collection = restangularizeCollection(parent, element, route, fromServer);
- _.each(collection, function(elem) {
- if (elem) {
- restangularizeElem(parent, elem, route, fromServer);
- }
- });
- return collection;
- }
-
- function getById(id, reqParams, headers) {
- return this.customGET(id.toString(), reqParams, headers);
- }
-
- function putElementFunction(idx, params, headers) {
- var __this = this;
- var elemToPut = this[idx];
- var deferred = $q.defer();
- var filledArray = [];
- filledArray = config.transformElem(filledArray, true, elemToPut[config.restangularFields.route], service);
- elemToPut.put(params, headers).then(function(serverElem) {
- var newArray = copyRestangularizedElement(__this);
- newArray[idx] = serverElem;
- filledArray = newArray;
- deferred.resolve(newArray);
- }, function(response) {
- deferred.reject(response);
- });
-
- return restangularizePromise(deferred.promise, true, filledArray);
- }
-
- function parseResponse(resData, operation, route, fetchUrl, response, deferred) {
- var data = config.responseExtractor(resData, operation, route, fetchUrl, response, deferred);
- var etag = response.headers('ETag');
- if (data && etag) {
- data[config.restangularFields.etag] = etag;
- }
- return data;
- }
-
-
- function fetchFunction(what, reqParams, headers) {
- var __this = this;
- var deferred = $q.defer();
- var operation = 'getList';
- var url = urlHandler.fetchUrl(this, what);
- var whatFetched = what || __this[config.restangularFields.route];
-
- var request = config.fullRequestInterceptor(null, operation,
- whatFetched, url, headers || {}, reqParams || {}, this[config.restangularFields.httpConfig] || {});
-
- var filledArray = [];
- filledArray = config.transformElem(filledArray, true, whatFetched, service);
-
- var method = 'getList';
-
- if (config.jsonp) {
- method = 'jsonp';
- }
-
- var okCallback = function(response) {
- var resData = response.data;
- var fullParams = response.config.params;
- var data = parseResponse(resData, operation, whatFetched, url, response, deferred);
-
- // support empty response for getList() calls (some APIs respond with 204 and empty body)
- if (_.isUndefined(data) || '' === data) {
- data = [];
- }
- if (!_.isArray(data)) {
- throw new Error('Response for getList SHOULD be an array and not an object or something else');
- }
-
- if (true === config.plainByDefault) {
- return resolvePromise(deferred, response, data, filledArray);
- }
-
- var processedData = _.map(data, function(elem) {
- if (!__this[config.restangularFields.restangularCollection]) {
- return restangularizeElem(__this, elem, what, true, data);
- } else {
- return restangularizeElem(__this[config.restangularFields.parentResource],
- elem, __this[config.restangularFields.route], true, data);
- }
- });
-
- processedData = _.extend(data, processedData);
-
- if (!__this[config.restangularFields.restangularCollection]) {
- resolvePromise(
- deferred,
- response,
- restangularizeCollection(
- __this,
- processedData,
- what,
- true,
- fullParams
- ),
- filledArray
- );
- } else {
- resolvePromise(
- deferred,
- response,
- restangularizeCollection(
- __this[config.restangularFields.parentResource],
- processedData,
- __this[config.restangularFields.route],
- true,
- fullParams
- ),
- filledArray
- );
- }
- };
-
- urlHandler.resource(this, $http, request.httpConfig, request.headers, request.params, what,
- this[config.restangularFields.etag], operation)[method]().then(okCallback, function error(response) {
- if (response.status === 304 && __this[config.restangularFields.restangularCollection]) {
- resolvePromise(deferred, response, __this, filledArray);
- } else if (_.every(config.errorInterceptors, function(cb) {
- return cb(response, deferred, okCallback) !== false;
- })) {
- // triggered if no callback returns false
- deferred.reject(response);
- }
- });
-
- return restangularizePromise(deferred.promise, true, filledArray);
- }
-
- function withHttpConfig(httpConfig) {
- this[config.restangularFields.httpConfig] = httpConfig;
- return this;
- }
-
- function save(params, headers) {
- if (this[config.restangularFields.fromServer]) {
- return this[config.restangularFields.put](params, headers);
- } else {
- return _.bind(elemFunction, this)('post', undefined, params, undefined, headers);
- }
- }
-
- function elemFunction(operation, what, params, obj, headers) {
- var __this = this;
- var deferred = $q.defer();
- var resParams = params || {};
- var route = what || this[config.restangularFields.route];
- var fetchUrl = urlHandler.fetchUrl(this, what);
-
- var callObj = obj || this;
- // fallback to etag on restangular object (since for custom methods we probably don't explicitly specify the etag field)
- var etag = callObj[config.restangularFields.etag] || (operation !== 'post' ? this[config.restangularFields.etag] : null);
-
- if (_.isObject(callObj) && config.isRestangularized(callObj)) {
- callObj = stripRestangular(callObj);
- }
- var request = config.fullRequestInterceptor(callObj, operation, route, fetchUrl,
- headers || {}, resParams || {}, this[config.restangularFields.httpConfig] || {});
-
- var filledObject = {};
- filledObject = config.transformElem(filledObject, false, route, service);
-
- var okCallback = function(response) {
- var resData = response.data;
- var fullParams = response.config.params;
- var elem = parseResponse(resData, operation, route, fetchUrl, response, deferred);
-
- // accept 0 as response
- if (elem !== null && elem !== undefined && elem !== '') {
- var data;
-
- if (true === config.plainByDefault) {
- return resolvePromise(deferred, response, elem, filledObject);
- }
-
- if (operation === 'post' && !__this[config.restangularFields.restangularCollection]) {
- data = restangularizeElem(
- __this[config.restangularFields.parentResource],
- elem,
- route,
- true,
- null,
- fullParams
- );
- resolvePromise(deferred, response, data, filledObject);
- } else {
- data = restangularizeElem(
- __this[config.restangularFields.parentResource],
- elem,
- __this[config.restangularFields.route],
- true,
- null,
- fullParams
- );
-
- data[config.restangularFields.singleOne] = __this[config.restangularFields.singleOne];
- resolvePromise(deferred, response, data, filledObject);
- }
-
- } else {
- resolvePromise(deferred, response, undefined, filledObject);
- }
- };
-
- var errorCallback = function(response) {
- if (response.status === 304 && config.isSafe(operation)) {
- resolvePromise(deferred, response, __this, filledObject);
- } else if (_.every(config.errorInterceptors, function(cb) {
- return cb(response, deferred, okCallback) !== false;
- })) {
- // triggered if no callback returns false
- deferred.reject(response);
- }
- };
- // Overriding HTTP Method
- var callOperation = operation;
- var callHeaders = _.extend({}, request.headers);
- var isOverrideOperation = config.isOverridenMethod(operation);
- if (isOverrideOperation) {
- callOperation = 'post';
- callHeaders = _.extend(callHeaders, {
- 'X-HTTP-Method-Override': operation === 'remove' ? 'DELETE' : operation.toUpperCase()
- });
- } else if (config.jsonp && callOperation === 'get') {
- callOperation = 'jsonp';
- }
-
- if (config.isSafe(operation)) {
- if (isOverrideOperation) {
- urlHandler.resource(this, $http, request.httpConfig, callHeaders, request.params,
- what, etag, callOperation)[callOperation]({}).then(okCallback, errorCallback);
- } else {
- urlHandler.resource(this, $http, request.httpConfig, callHeaders, request.params,
- what, etag, callOperation)[callOperation]().then(okCallback, errorCallback);
- }
- } else {
- urlHandler.resource(this, $http, request.httpConfig, callHeaders, request.params,
- what, etag, callOperation)[callOperation](request.element).then(okCallback, errorCallback);
- }
-
- return restangularizePromise(deferred.promise, false, filledObject);
- }
-
- function getFunction(params, headers) {
- return _.bind(elemFunction, this)('get', undefined, params, undefined, headers);
- }
-
- function deleteFunction(params, headers) {
- return _.bind(elemFunction, this)('remove', undefined, params, undefined, headers);
- }
-
- function putFunction(params, headers) {
- return _.bind(elemFunction, this)('put', undefined, params, undefined, headers);
- }
-
- function postFunction(what, elem, params, headers) {
- return _.bind(elemFunction, this)('post', what, params, elem, headers);
- }
-
- function headFunction(params, headers) {
- return _.bind(elemFunction, this)('head', undefined, params, undefined, headers);
- }
-
- function traceFunction(params, headers) {
- return _.bind(elemFunction, this)('trace', undefined, params, undefined, headers);
- }
-
- function optionsFunction(params, headers) {
- return _.bind(elemFunction, this)('options', undefined, params, undefined, headers);
- }
-
- function patchFunction(elem, params, headers) {
- return _.bind(elemFunction, this)('patch', undefined, params, elem, headers);
- }
-
- function customFunction(operation, path, params, headers, elem) {
- return _.bind(elemFunction, this)(operation, path, params, elem, headers);
- }
-
- function addRestangularMethodFunction(name, operation, path, defaultParams, defaultHeaders, defaultElem) {
- var bindedFunction;
- if (operation === 'getList') {
- bindedFunction = _.bind(fetchFunction, this, path);
- } else {
- bindedFunction = _.bind(customFunction, this, operation, path);
- }
-
- var createdFunction = function(params, headers, elem) {
- var callParams = _.defaults({
- params: params,
- headers: headers,
- elem: elem
- }, {
- params: defaultParams,
- headers: defaultHeaders,
- elem: defaultElem
- });
- return bindedFunction(callParams.params, callParams.headers, callParams.elem);
- };
-
- if (config.isSafe(operation)) {
- this[name] = createdFunction;
- } else {
- this[name] = function(elem, params, headers) {
- return createdFunction(params, headers, elem);
- };
- }
- }
-
- function withConfigurationFunction(configurer) {
- var newConfig = angular.copy(_.omit(config, 'configuration'));
- Configurer.init(newConfig, newConfig);
- configurer(newConfig);
- return createServiceForConfiguration(newConfig);
- }
-
- function toService(route, parent) {
- var knownCollectionMethods = _.values(config.restangularFields);
- var serv = {};
- var collection = (parent || service).all(route);
- serv.one = _.bind(one, (parent || service), parent, route);
- serv.post = _.bind(collection.post, collection);
- serv.getList = _.bind(collection.getList, collection);
- serv.withHttpConfig = _.bind(collection.withHttpConfig, collection);
- serv.get = _.bind(collection.get, collection);
-
- for (var prop in collection) {
- if (collection.hasOwnProperty(prop) && _.isFunction(collection[prop]) && !_.includes(knownCollectionMethods, prop)) {
- serv[prop] = _.bind(collection[prop], collection);
- }
- }
-
- return serv;
- }
-
-
- Configurer.init(service, config);
-
- service.copy = _.bind(copyRestangularizedElement, service);
-
- service.service = _.bind(toService, service);
-
- service.withConfig = _.bind(withConfigurationFunction, service);
-
- service.one = _.bind(one, service, null);
-
- service.all = _.bind(all, service, null);
-
- service.several = _.bind(several, service, null);
-
- service.oneUrl = _.bind(oneUrl, service, null);
-
- service.allUrl = _.bind(allUrl, service, null);
-
- service.stripRestangular = _.bind(stripRestangular, service);
-
- service.restangularizeElement = _.bind(restangularizeElem, service);
-
- service.restangularizeCollection = _.bind(restangularizeCollectionAndElements, service);
-
- return service;
- }
-
- return createServiceForConfiguration(globalConfiguration);
- }];
- });
- return restangular.name;
-}));
diff --git a/static/js/run_prettify.js b/static/js/run_prettify.js
index 8204930..427074a 100644
--- a/static/js/run_prettify.js
+++ b/static/js/run_prettify.js
@@ -1,63 +1,1998 @@
-!function(){/*
+/**
+ * @license
+ * Copyright (C) 2013 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.
+ */
- Copyright (C) 2013 Google Inc.
+/**
+ * @fileoverview
+ * <div style="white-space: pre">
+ * Looks at query parameters to decide which language handlers and style-sheets
+ * to load.
+ *
+ * Query Parameter Format Effect Default
+ * +------------------+---------------+------------------------------+--------+
+ * | autorun= | true | false | If true then prettyPrint() | "true" |
+ * | | | is called on page load. | |
+ * +------------------+---------------+------------------------------+--------+
+ * | lang= | language name | Loads the language handler | Can |
+ * | | | named "lang-<NAME>.js". | appear |
+ * | | | See available handlers at | many |
+ * | | | https://github.com/google/ | times. |
+ * | | | code-prettify/tree/master/ | |
+ * | | | src | |
+ * +------------------+---------------+------------------------------+--------+
+ * | skin= | skin name | Loads the skin stylesheet | none. |
+ * | | | named "<NAME>.css". | |
+ * | | | https://cdn.rawgit.com/ | |
+ * | | | google/code-prettify/master/ | |
+ * | | | styles/index.html | |
+ * +------------------+---------------+------------------------------+--------+
+ * | callback= | JS identifier | When "prettyPrint" finishes | none |
+ * | | | window.exports[js_ident] is | |
+ * | | | called. | |
+ * | | | The callback must be under | |
+ * | | | exports to reduce the risk | |
+ * | | | of XSS via query parameter | |
+ * | | | injection. | |
+ * +------------------+---------------+------------------------------+--------+
+ *
+ * Exmaples
+ * .../run_prettify.js?lang=css&skin=sunburst
+ * 1. Loads the CSS language handler which can be used to prettify CSS
+ * stylesheets, HTML <style> element bodies and style="..." attributes
+ * values.
+ * 2. Loads the sunburst.css stylesheet instead of the default prettify.css
+ * stylesheet.
+ * A gallery of stylesheets is available at
+ * https://cdn.rawgit.com/google/code-prettify/master/styles/index.html
+ * 3. Since autorun=false is not specified, calls prettyPrint() on page load.
+ * </div>
+ */
- 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.
-
- Copyright (C) 2006 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.
+/**
+* @typedef {!Array.<number|string>}
+* Alternating indices and the decorations that should be inserted there.
+* The indices are monotonically increasing.
*/
-(function(){function ba(g){function k(){try{M.doScroll("left")}catch(g){t.setTimeout(k,50);return}z("poll")}function z(k){if("readystatechange"!=k.type||"complete"==A.readyState)("load"==k.type?t:A)[B](p+k.type,z,!1),!q&&(q=!0)&&g.call(t,k.type||k)}var Y=A.addEventListener,q=!1,C=!0,x=Y?"addEventListener":"attachEvent",B=Y?"removeEventListener":"detachEvent",p=Y?"":"on";if("complete"==A.readyState)g.call(t,"lazy");else{if(A.createEventObject&&M.doScroll){try{C=!t.frameElement}catch(da){}C&&k()}A[x](p+
-"DOMContentLoaded",z,!1);A[x](p+"readystatechange",z,!1);t[x](p+"load",z,!1)}}function U(){V&&ba(function(){var g=N.length;ca(g?function(){for(var k=0;k<g;++k)(function(g){t.setTimeout(function(){t.exports[N[g]].apply(t,arguments)},0)})(k)}:void 0)})}for(var t=window,A=document,M=A.documentElement,O=A.head||A.getElementsByTagName("head")[0]||M,B="",F=A.getElementsByTagName("script"),q=F.length;0<=--q;){var P=F[q],Z=P.src.match(/^[^?#]*\/run_prettify\.js(\?[^#]*)?(?:#.*)?$/);if(Z){B=Z[1]||"";P.parentNode.removeChild(P);
-break}}var V=!0,H=[],Q=[],N=[];B.replace(/[?&]([^&=]+)=([^&]+)/g,function(g,k,z){z=decodeURIComponent(z);k=decodeURIComponent(k);"autorun"==k?V=!/^[0fn]/i.test(z):"lang"==k?H.push(z):"skin"==k?Q.push(z):"callback"==k&&N.push(z)});q=0;for(B=H.length;q<B;++q)(function(){var g=A.createElement("script");g.onload=g.onerror=g.onreadystatechange=function(){!g||g.readyState&&!/loaded|complete/.test(g.readyState)||(g.onerror=g.onload=g.onreadystatechange=null,--T,T||t.setTimeout(U,0),g.parentNode&&g.parentNode.removeChild(g),
-g=null)};g.type="text/javascript";g.src="../css/loader/lang-"+encodeURIComponent(H[q])+".js";O.insertBefore(g,O.firstChild)})(H[q]);for(var T=H.length,F=[],q=0,B=Q.length;q<B;++q)F.push("https://cdn.rawgit.com/google/code-prettify/master/loader/skins/"+encodeURIComponent(Q[q])+".css");F.push("../css/prettify.css");(function(g){function k(q){if(q!==z){var t=A.createElement("link");t.rel="stylesheet";t.type=
-"text/css";q+1<z&&(t.error=t.onerror=function(){k(q+1)});t.href=g[q];O.appendChild(t)}}var z=g.length;k(0)})(F);var ca=function(){window.PR_SHOULD_USE_CONTINUATION=!0;var g;(function(){function k(a){function d(e){var b=e.charCodeAt(0);if(92!==b)return b;var a=e.charAt(1);return(b=W[a])?b:"0"<=a&&"7">=a?parseInt(e.substring(1),8):"u"===a||"x"===a?parseInt(e.substring(2),16):e.charCodeAt(1)}function f(e){if(32>e)return(16>e?"\\x0":"\\x")+e.toString(16);e=String.fromCharCode(e);return"\\"===e||"-"===
-e||"]"===e||"^"===e?"\\"+e:e}function b(e){var b=e.substring(1,e.length-1).match(/\\u[0-9A-Fa-f]{4}|\\x[0-9A-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\s\S]|-|[^-\\]/g);e=[];var a="^"===b[0],c=["["];a&&c.push("^");for(var a=a?1:0,h=b.length;a<h;++a){var l=b[a];if(/\\[bdsw]/i.test(l))c.push(l);else{var l=d(l),n;a+2<h&&"-"===b[a+1]?(n=d(b[a+2]),a+=2):n=l;e.push([l,n]);65>n||122<l||(65>n||90<l||e.push([Math.max(65,l)|32,Math.min(n,90)|32]),97>n||122<l||e.push([Math.max(97,l)&-33,Math.min(n,122)&-33]))}}e.sort(function(e,
-a){return e[0]-a[0]||a[1]-e[1]});b=[];h=[];for(a=0;a<e.length;++a)l=e[a],l[0]<=h[1]+1?h[1]=Math.max(h[1],l[1]):b.push(h=l);for(a=0;a<b.length;++a)l=b[a],c.push(f(l[0])),l[1]>l[0]&&(l[1]+1>l[0]&&c.push("-"),c.push(f(l[1])));c.push("]");return c.join("")}function g(e){for(var a=e.source.match(/(?:\[(?:[^\x5C\x5D]|\\[\s\S])*\]|\\u[A-Fa-f0-9]{4}|\\x[A-Fa-f0-9]{2}|\\[0-9]+|\\[^ux0-9]|\(\?[:!=]|[\(\)\^]|[^\x5B\x5C\(\)\^]+)/g),c=a.length,d=[],h=0,l=0;h<c;++h){var n=a[h];"("===n?++l:"\\"===n.charAt(0)&&(n=
-+n.substring(1))&&(n<=l?d[n]=-1:a[h]=f(n))}for(h=1;h<d.length;++h)-1===d[h]&&(d[h]=++k);for(l=h=0;h<c;++h)n=a[h],"("===n?(++l,d[l]||(a[h]="(?:")):"\\"===n.charAt(0)&&(n=+n.substring(1))&&n<=l&&(a[h]="\\"+d[n]);for(h=0;h<c;++h)"^"===a[h]&&"^"!==a[h+1]&&(a[h]="");if(e.ignoreCase&&I)for(h=0;h<c;++h)n=a[h],e=n.charAt(0),2<=n.length&&"["===e?a[h]=b(n):"\\"!==e&&(a[h]=n.replace(/[a-zA-Z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return a.join("")}for(var k=0,I=!1,
-m=!1,J=0,c=a.length;J<c;++J){var r=a[J];if(r.ignoreCase)m=!0;else if(/[a-z]/i.test(r.source.replace(/\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi,""))){I=!0;m=!1;break}}for(var W={b:8,t:9,n:10,v:11,f:12,r:13},u=[],J=0,c=a.length;J<c;++J){r=a[J];if(r.global||r.multiline)throw Error(""+r);u.push("(?:"+g(r)+")")}return new RegExp(u.join("|"),m?"gi":"g")}function q(a,d){function f(a){var c=a.nodeType;if(1==c){if(!b.test(a.className)){for(c=a.firstChild;c;c=c.nextSibling)f(c);c=a.nodeName.toLowerCase();if("br"===
-c||"li"===c)g[m]="\n",I[m<<1]=k++,I[m++<<1|1]=a}}else if(3==c||4==c)c=a.nodeValue,c.length&&(c=d?c.replace(/\r\n?/g,"\n"):c.replace(/[ \t\r\n]+/g," "),g[m]=c,I[m<<1]=k,k+=c.length,I[m++<<1|1]=a)}var b=/(?:^|\s)nocode(?:\s|$)/,g=[],k=0,I=[],m=0;f(a);return{a:g.join("").replace(/\n$/,""),c:I}}function t(a,d,f,b,g){f&&(a={h:a,l:1,j:null,m:null,a:f,c:null,i:d,g:null},b(a),g.push.apply(g,a.g))}function A(a){for(var d=void 0,f=a.firstChild;f;f=f.nextSibling)var b=f.nodeType,d=1===b?d?a:f:3===b?T.test(f.nodeValue)?
-a:d:d;return d===a?void 0:d}function C(a,d){function f(a){for(var m=a.i,k=a.h,c=[m,"pln"],r=0,W=a.a.match(g)||[],u={},e=0,q=W.length;e<q;++e){var D=W[e],w=u[D],h=void 0,l;if("string"===typeof w)l=!1;else{var n=b[D.charAt(0)];if(n)h=D.match(n[1]),w=n[0];else{for(l=0;l<p;++l)if(n=d[l],h=D.match(n[1])){w=n[0];break}h||(w="pln")}!(l=5<=w.length&&"lang-"===w.substring(0,5))||h&&"string"===typeof h[1]||(l=!1,w="src");l||(u[D]=w)}n=r;r+=D.length;if(l){l=h[1];var E=D.indexOf(l),G=E+l.length;h[2]&&(G=D.length-
-h[2].length,E=G-l.length);w=w.substring(5);t(k,m+n,D.substring(0,E),f,c);t(k,m+n+E,l,F(w,l),c);t(k,m+n+G,D.substring(G),f,c)}else c.push(m+n,w)}a.g=c}var b={},g;(function(){for(var f=a.concat(d),m=[],p={},c=0,r=f.length;c<r;++c){var q=f[c],u=q[3];if(u)for(var e=u.length;0<=--e;)b[u.charAt(e)]=q;q=q[1];u=""+q;p.hasOwnProperty(u)||(m.push(q),p[u]=null)}m.push(/[\0-\uffff]/);g=k(m)})();var p=d.length;return f}function x(a){var d=[],f=[];a.tripleQuotedStrings?d.push(["str",/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,
-null,"'\""]):a.multiLineStrings?d.push(["str",/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"]):d.push(["str",/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"]);a.verbatimStrings&&f.push(["str",/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null]);var b=a.hashComments;b&&(a.cStyleComments?(1<b?d.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"]):d.push(["com",/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\r\n]*)/,
-null,"#"]),f.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,null])):d.push(["com",/^#[^\r\n]*/,null,"#"]));a.cStyleComments&&(f.push(["com",/^\/\/[^\r\n]*/,null]),f.push(["com",/^\/\*[\s\S]*?(?:\*\/|$)/,null]));if(b=a.regexLiterals){var g=(b=1<b?"":"\n\r")?".":"[\\S\\s]";f.push(["lang-regex",RegExp("^(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<<?=?|>>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*("+
-("/(?=[^/*"+b+"])(?:[^/\\x5B\\x5C"+b+"]|\\x5C"+g+"|\\x5B(?:[^\\x5C\\x5D"+b+"]|\\x5C"+g+")*(?:\\x5D|$))+/")+")")])}(b=a.types)&&f.push(["typ",b]);b=(""+a.keywords).replace(/^ | $/g,"");b.length&&f.push(["kwd",new RegExp("^(?:"+b.replace(/[\s,]+/g,"|")+")\\b"),null]);d.push(["pln",/^\s+/,null," \r\n\t\u00a0"]);b="^.[^\\s\\w.$@'\"`/\\\\]*";a.regexLiterals&&(b+="(?!s*/)");f.push(["lit",/^@[a-z_$][a-z_$@0-9]*/i,null],["typ",/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],["pln",/^[a-z_$][a-z_$@0-9]*/i,
-null],["lit",/^(?:0x[a-f0-9]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+\-]?\d+)?)[a-z]*/i,null,"0123456789"],["pln",/^\\[\s\S]?/,null],["pun",new RegExp(b),null]);return C(d,f)}function B(a,d,f){function b(a){var c=a.nodeType;if(1==c&&!k.test(a.className))if("br"===a.nodeName)g(a),a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)b(a);else if((3==c||4==c)&&f){var d=a.nodeValue,p=d.match(q);p&&(c=d.substring(0,p.index),a.nodeValue=c,(d=d.substring(p.index+p[0].length))&&
-a.parentNode.insertBefore(m.createTextNode(d),a.nextSibling),g(a),c||a.parentNode.removeChild(a))}}function g(a){function b(a,c){var d=c?a.cloneNode(!1):a,n=a.parentNode;if(n){var n=b(n,1),e=a.nextSibling;n.appendChild(d);for(var f=e;f;f=e)e=f.nextSibling,n.appendChild(f)}return d}for(;!a.nextSibling;)if(a=a.parentNode,!a)return;a=b(a.nextSibling,0);for(var d;(d=a.parentNode)&&1===d.nodeType;)a=d;c.push(a)}for(var k=/(?:^|\s)nocode(?:\s|$)/,q=/\r\n?|\n/,m=a.ownerDocument,p=m.createElement("li");a.firstChild;)p.appendChild(a.firstChild);
-for(var c=[p],r=0;r<c.length;++r)b(c[r]);d===(d|0)&&c[0].setAttribute("value",d);var t=m.createElement("ol");t.className="linenums";d=Math.max(0,d-1|0)||0;for(var r=0,u=c.length;r<u;++r)p=c[r],p.className="L"+(r+d)%10,p.firstChild||p.appendChild(m.createTextNode("\u00a0")),t.appendChild(p);a.appendChild(t)}function p(a,d){for(var f=d.length;0<=--f;){var b=d[f];X.hasOwnProperty(b)?R.console&&console.warn("cannot override language handler %s",b):X[b]=a}}function F(a,d){a&&X.hasOwnProperty(a)||(a=/^\s*</.test(d)?
-"default-markup":"default-code");return X[a]}function H(a){var d=a.j;try{var f=q(a.h,a.l),b=f.a;a.a=b;a.c=f.c;a.i=0;F(d,b)(a);var g=/\bMSIE\s(\d+)/.exec(navigator.userAgent),g=g&&8>=+g[1],d=/\n/g,p=a.a,k=p.length,f=0,m=a.c,t=m.length,b=0,c=a.g,r=c.length,x=0;c[r]=k;var u,e;for(e=u=0;e<r;)c[e]!==c[e+2]?(c[u++]=c[e++],c[u++]=c[e++]):e+=2;r=u;for(e=u=0;e<r;){for(var A=c[e],D=c[e+1],w=e+2;w+2<=r&&c[w+1]===D;)w+=2;c[u++]=A;c[u++]=D;e=w}c.length=u;var h=a.h;a="";h&&(a=h.style.display,h.style.display="none");
-try{for(;b<t;){var l=m[b+2]||k,n=c[x+2]||k,w=Math.min(l,n),E=m[b+1],G;if(1!==E.nodeType&&(G=p.substring(f,w))){g&&(G=G.replace(d,"\r"));E.nodeValue=G;var aa=E.ownerDocument,v=aa.createElement("span");v.className=c[x+1];var B=E.parentNode;B.replaceChild(v,E);v.appendChild(E);f<l&&(m[b+1]=E=aa.createTextNode(p.substring(w,l)),B.insertBefore(E,v.nextSibling))}f=w;f>=l&&(b+=2);f>=n&&(x+=2)}}finally{h&&(h.style.display=a)}}catch(y){R.console&&console.log(y&&y.stack||y)}}var R=window,K=["break,continue,do,else,for,if,return,while"],
-L=[[K,"auto,case,char,const,default,double,enum,extern,float,goto,inline,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"],S=[L,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],
-M=[L,"abstract,assert,boolean,byte,extends,finally,final,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient"],N=[L,"abstract,as,base,bool,by,byte,checked,decimal,delegate,descending,dynamic,event,finally,fixed,foreach,from,group,implicit,in,interface,internal,into,is,let,lock,null,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where"],L=[L,"debugger,eval,export,function,get,instanceof,null,set,undefined,var,with,Infinity,NaN"],
-O=[K,"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"],P=[K,"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"],K=[K,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],Q=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/,
-T=/\S/,U=x({keywords:[S,N,M,L,"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",O,P,K],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),X={};p(U,["default-code"]);p(C([],[["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".split(" "));p(C([["pln",/^[\s]+/,null," \t\r\n"],["atv",/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[["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"]);p(C([],[["atv",/^[\s\S]+/]]),["uq.val"]);p(x({keywords:S,hashComments:!0,cStyleComments:!0,types:Q}),"c cc cpp cxx cyc m".split(" "));p(x({keywords:"null,true,false"}),["json"]);p(x({keywords:N,hashComments:!0,cStyleComments:!0,
-verbatimStrings:!0,types:Q}),["cs"]);p(x({keywords:M,cStyleComments:!0}),["java"]);p(x({keywords:K,hashComments:!0,multiLineStrings:!0}),["bash","bsh","csh","sh"]);p(x({keywords:O,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),["cv","py","python"]);p(x({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:2}),
-["perl","pl","pm"]);p(x({keywords:P,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb","ruby"]);p(x({keywords:L,cStyleComments:!0,regexLiterals:!0}),["javascript","js"]);p(x({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,throw,true,try,unless,until,when,while,yes",hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);p(C([],[["str",/^[\s\S]+/]]),["regex"]);
-var V=R.PR={createSimpleLexer:C,registerLangHandler:p,sourceDecorator:x,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",prettyPrintOne:function(a,d,f){f=f||!1;d=d||null;var b=document.createElement("div");b.innerHTML="<pre>"+a+"</pre>";b=b.firstChild;f&&B(b,f,!0);H({j:d,m:f,h:b,l:1,a:null,i:null,c:null,g:null});return b.innerHTML},
-prettyPrint:g=g=function(a,d){function f(){for(var b=R.PR_SHOULD_USE_CONTINUATION?c.now()+250:Infinity;r<p.length&&c.now()<b;r++){for(var d=p[r],k=h,q=d;q=q.previousSibling;){var m=q.nodeType,v=(7===m||8===m)&&q.nodeValue;if(v?!/^\??prettify\b/.test(v):3!==m||/\S/.test(q.nodeValue))break;if(v){k={};v.replace(/\b(\w+)=([\w:.%+-]+)/g,function(a,b,c){k[b]=c});break}}q=d.className;if((k!==h||u.test(q))&&!e.test(q)){m=!1;for(v=d.parentNode;v;v=v.parentNode)if(w.test(v.tagName)&&v.className&&u.test(v.className)){m=
-!0;break}if(!m){d.className+=" prettyprinted";m=k.lang;if(!m){var m=q.match(t),C;!m&&(C=A(d))&&z.test(C.tagName)&&(m=C.className.match(t));m&&(m=m[1])}if(x.test(d.tagName))v=1;else var v=d.currentStyle,y=g.defaultView,v=(v=v?v.whiteSpace:y&&y.getComputedStyle?y.getComputedStyle(d,null).getPropertyValue("white-space"):0)&&"pre"===v.substring(0,3);y=k.linenums;(y="true"===y||+y)||(y=(y=q.match(/\blinenums\b(?::(\d+))?/))?y[1]&&y[1].length?+y[1]:!0:!1);y&&B(d,y,v);H({j:m,h:d,m:y,l:v,a:null,i:null,c:null,
-g:null})}}}r<p.length?R.setTimeout(f,250):"function"===typeof a&&a()}for(var b=d||document.body,g=b.ownerDocument||document,b=[b.getElementsByTagName("pre"),b.getElementsByTagName("code"),b.getElementsByTagName("xmp")],p=[],k=0;k<b.length;++k)for(var m=0,q=b[k].length;m<q;++m)p.push(b[k][m]);var b=null,c=Date;c.now||(c={now:function(){return+new Date}});var r=0,t=/\blang(?:uage)?-([\w.]+)(?!\S)/,u=/\bprettyprint\b/,e=/\bprettyprinted\b/,x=/pre|xmp/i,z=/^code$/i,w=/^(?:pre|code|xmp)$/i,h={};f()}},
-S=R.define;"function"===typeof S&&S.amd&&S("google-code-prettify",[],function(){return V})})();return g}();T||t.setTimeout(U,0)})();}()
+var DecorationsT;
+
+/**
+* @typedef {!{
+* sourceNode: !Element,
+* pre: !(number|boolean),
+* langExtension: ?string,
+* numberLines: ?(number|boolean),
+* sourceCode: ?string,
+* spans: ?(Array.<number|Node>),
+* basePos: ?number,
+* decorations: ?DecorationsT
+* }}
+* <dl>
+* <dt>sourceNode<dd>the element containing the source
+* <dt>sourceCode<dd>source as plain text
+* <dt>pre<dd>truthy if white-space in text nodes
+* should be considered significant.
+* <dt>spans<dd> alternating span start indices into source
+* and the text node or element (e.g. {@code <BR>}) corresponding to that
+* span.
+* <dt>decorations<dd>an array of style classes preceded
+* by the position at which they start in job.sourceCode in order
+* <dt>basePos<dd>integer position of this.sourceCode in the larger chunk of
+* source.
+* </dl>
+*/
+var JobT;
+
+/**
+* @typedef {!{
+* sourceCode: string,
+* spans: !(Array.<number|Node>)
+* }}
+* <dl>
+* <dt>sourceCode<dd>source as plain text
+* <dt>spans<dd> alternating span start indices into source
+* and the text node or element (e.g. {@code <BR>}) corresponding to that
+* span.
+* </dl>
+*/
+var SourceSpansT;
+
+/** @define {boolean} */
+var IN_GLOBAL_SCOPE = false;
+
+(function () {
+ "use strict";
+
+ var win = window;
+ var doc = document;
+ var root = doc.documentElement;
+ var head = doc['head'] || doc.getElementsByTagName("head")[0] || root;
+
+ // From http://javascript.nwbox.com/ContentLoaded/contentloaded.js
+ // Author: Diego Perini (diego.perini at gmail.com)
+ // Summary: cross-browser wrapper for DOMContentLoaded
+ // Updated: 20101020
+ // License: MIT
+ // Version: 1.2
+ function contentLoaded(callback) {
+ var addEventListener = doc['addEventListener'];
+ var done = false, top = true,
+ add = addEventListener ? 'addEventListener' : 'attachEvent',
+ rem = addEventListener ? 'removeEventListener' : 'detachEvent',
+ pre = addEventListener ? '' : 'on',
+
+ init = function(e) {
+ if (e.type == 'readystatechange' && doc.readyState != 'complete') {
+ return;
+ }
+ (e.type == 'load' ? win : doc)[rem](pre + e.type, init, false);
+ if (!done && (done = true)) { callback.call(win, e.type || e); }
+ },
+
+ poll = function() {
+ try {
+ root.doScroll('left');
+ } catch(e) {
+ win.setTimeout(poll, 50);
+ return;
+ }
+ init('poll');
+ };
+
+ if (doc.readyState == 'complete') {
+ callback.call(win, 'lazy');
+ } else {
+ if (doc.createEventObject && root.doScroll) {
+ try { top = !win.frameElement; } catch(e) { }
+ if (top) { poll(); }
+ }
+ doc[add](pre + 'DOMContentLoaded', init, false);
+ doc[add](pre + 'readystatechange', init, false);
+ win[add](pre + 'load', init, false);
+ }
+ }
+
+ // Given a list of URLs to stylesheets, loads the first that loads without
+ // triggering an error event.
+ function loadStylesheetsFallingBack(stylesheets) {
+ var n = stylesheets.length;
+ function load(i) {
+ if (i === n) { return; }
+ var link = doc.createElement('link');
+ link.rel = 'stylesheet';
+ link.type = 'text/css';
+ if (i + 1 < n) {
+ // http://pieisgood.org/test/script-link-events/ indicates that many
+ // versions of IE do not support onerror on <link>s, though
+ // http://msdn.microsoft.com/en-us/library/ie/ms535848(v=vs.85).aspx
+ // indicates that recent IEs do support error.
+ link.error = link.onerror = function () { load(i + 1); };
+ }
+ link.href = stylesheets[i];
+ head.appendChild(link);
+ }
+ load(0);
+ }
+
+ var scriptQuery = '';
+ // Look for the <script> node that loads this script to get its parameters.
+ // This starts looking at the end instead of just considering the last
+ // because deferred and async scripts run out of order.
+ // If the script is loaded twice, then this will run in reverse order.
+ var scripts = doc.getElementsByTagName('script');
+ for (var i = scripts.length; --i >= 0;) {
+ var script = scripts[i];
+ var match = script.src.match(
+ /^[^?#]*\/run_prettify\.js(\?[^#]*)?(?:#.*)?$/);
+ if (match) {
+ scriptQuery = match[1] || '';
+ // Remove the script from the DOM so that multiple runs at least run
+ // multiple times even if parameter sets are interpreted in reverse
+ // order.
+ script.parentNode.removeChild(script);
+ break;
+ }
+ }
+
+ // Pull parameters into local variables.
+ var autorun = true;
+ var langs = [];
+ var skins = [];
+ var callbacks = [];
+ scriptQuery.replace(
+ /[?&]([^&=]+)=([^&]+)/g,
+ function (_, name, value) {
+ value = decodeURIComponent(value);
+ name = decodeURIComponent(name);
+ if (name == 'autorun') { autorun = !/^[0fn]/i.test(value); } else
+ if (name == 'lang') { langs.push(value); } else
+ if (name == 'skin') { skins.push(value); } else
+ if (name == 'callback') { callbacks.push(value); }
+ });
+
+ // Use https to avoid mixed content warnings in client pages and to
+ // prevent a MITM from rewrite prettify mid-flight.
+ // This only works if this script is loaded via https : something
+ // over which we exercise no control.
+ var LOADER_BASE_URL =
+ 'https://cdn.rawgit.com/google/code-prettify/master/loader';
+
+ for (var i = 0, n = langs.length; i < n; ++i) (function (lang) {
+ var script = doc.createElement("script");
+
+ // Excerpted from jQuery.ajaxTransport("script") to fire events when
+ // a script is finished loading.
+ // Attach handlers for each script
+ script.onload = script.onerror = script.onreadystatechange = function () {
+ if (script && (
+ !script.readyState || /loaded|complete/.test(script.readyState))) {
+ // Handle memory leak in IE
+ script.onerror = script.onload = script.onreadystatechange = null;
+
+ --pendingLanguages;
+ checkPendingLanguages();
+
+ // Remove the script
+ if (script.parentNode) {
+ script.parentNode.removeChild(script);
+ }
+
+ script = null;
+ }
+ };
+
+ script.type = 'text/javascript';
+ script.src = LOADER_BASE_URL
+ + '/lang-' + encodeURIComponent(langs[i]) + '.js';
+
+ // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
+ head.insertBefore(script, head.firstChild);
+ })(langs[i]);
+
+ var pendingLanguages = langs.length;
+ function checkPendingLanguages() {
+ if (!pendingLanguages) {
+ win.setTimeout(onLangsLoaded, 0);
+ }
+ }
+
+ var skinUrls = [];
+ for (var i = 0, n = skins.length; i < n; ++i) {
+ skinUrls.push(LOADER_BASE_URL
+ + '/skins/' + encodeURIComponent(skins[i]) + '.css');
+ }
+ skinUrls.push(LOADER_BASE_URL + '/prettify.css');
+ loadStylesheetsFallingBack(skinUrls);
+
+ var prettyPrint = (function () {
+ /**
+ * @license
+ * Copyright (C) 2006 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.
+ */
+
+ /**
+ * @fileoverview
+ * some functions for browser-side pretty printing of code contained in html.
+ *
+ * <p>
+ * For a fairly comprehensive set of languages see the
+ * <a href="https://github.com/google/code-prettify#for-which-languages-does-it-work">README</a>
+ * file that came with this source. At a minimum, the lexer should work on a
+ * number of languages including C and friends, Java, Python, Bash, SQL, HTML,
+ * XML, CSS, Javascript, and Makefiles. It works passably on Ruby, PHP and Awk
+ * and a subset of Perl, but, because of commenting conventions, doesn't work on
+ * Smalltalk, Lisp-like, or CAML-like languages without an explicit lang class.
+ * <p>
+ * Usage: <ol>
+ * <li> include this source file in an html page via
+ * {@code <script type="text/javascript" src="/path/to/prettify.js"></script>}
+ * <li> define style rules. See the example page for examples.
+ * <li> mark the {@code <pre>} and {@code <code>} tags in your source with
+ * {@code class=prettyprint.}
+ * You can also use the (html deprecated) {@code <xmp>} tag, but the pretty
+ * printer needs to do more substantial DOM manipulations to support that, so
+ * some css styles may not be preserved.
+ * </ol>
+ * That's it. I wanted to keep the API as simple as possible, so there's no
+ * need to specify which language the code is in, but if you wish, you can add
+ * another class to the {@code <pre>} or {@code <code>} element to specify the
+ * language, as in {@code <pre class="prettyprint lang-java">}. Any class that
+ * starts with "lang-" followed by a file extension, specifies the file type.
+ * See the "lang-*.js" files in this directory for code that implements
+ * per-language file handlers.
+ * <p>
+ * Change log:<br>
+ * cbeust, 2006/08/22
+ * <blockquote>
+ * Java annotations (start with "@") are now captured as literals ("lit")
+ * </blockquote>
+ * @requires console
+ */
+
+ // JSLint declarations
+ /*global console, document, navigator, setTimeout, window, define */
+
+
+ var HACK_TO_FIX_JS_INCLUDE_PL;
+
+ /**
+ * {@type !{
+ * 'createSimpleLexer': function (Array, Array): (function (JobT)),
+ * 'registerLangHandler': function (function (JobT), Array.<string>),
+ * 'PR_ATTRIB_NAME': string,
+ * 'PR_ATTRIB_NAME': string,
+ * 'PR_ATTRIB_VALUE': string,
+ * 'PR_COMMENT': string,
+ * 'PR_DECLARATION': string,
+ * 'PR_KEYWORD': string,
+ * 'PR_LITERAL': string,
+ * 'PR_NOCODE': string,
+ * 'PR_PLAIN': string,
+ * 'PR_PUNCTUATION': string,
+ * 'PR_SOURCE': string,
+ * 'PR_STRING': string,
+ * 'PR_TAG': string,
+ * 'PR_TYPE': string,
+ * 'prettyPrintOne': function (string, string, number|boolean),
+ * 'prettyPrint': function (?function, ?(HTMLElement|HTMLDocument))
+ * }}
+ * @const
+ */
+ var PR;
+
+ /**
+ * Split {@code prettyPrint} into multiple timeouts so as not to interfere with
+ * UI events.
+ * If set to {@code false}, {@code prettyPrint()} is synchronous.
+ */
+ window['PR_SHOULD_USE_CONTINUATION'] = true;
+
+ /**
+ * Pretty print a chunk of code.
+ * @param {string} sourceCodeHtml The HTML to pretty print.
+ * @param {string} opt_langExtension The language name to use.
+ * Typically, a filename extension like 'cpp' or 'java'.
+ * @param {number|boolean} opt_numberLines True to number lines,
+ * or the 1-indexed number of the first line in sourceCodeHtml.
+ * @return {string} code as html, but prettier
+ */
+ var prettyPrintOne;
+ /**
+ * Find all the {@code <pre>} and {@code <code>} tags in the DOM with
+ * {@code class=prettyprint} and prettify them.
+ *
+ * @param {Function} opt_whenDone called when prettifying is done.
+ * @param {HTMLElement|HTMLDocument} opt_root an element or document
+ * containing all the elements to pretty print.
+ * Defaults to {@code document.body}.
+ */
+ var prettyPrint;
+
+
+ (function () {
+ var win = window;
+ // Keyword lists for various languages.
+ // We use things that coerce to strings to make them compact when minified
+ // and to defeat aggressive optimizers that fold large string constants.
+ var FLOW_CONTROL_KEYWORDS = ["break,continue,do,else,for,if,return,while"];
+ var C_KEYWORDS = [FLOW_CONTROL_KEYWORDS,"auto,case,char,const,default," +
+ "double,enum,extern,float,goto,inline,int,long,register,restrict,short,signed," +
+ "sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];
+ var COMMON_KEYWORDS = [C_KEYWORDS,"catch,class,delete,false,import," +
+ "new,operator,private,protected,public,this,throw,true,try,typeof"];
+ var CPP_KEYWORDS = [COMMON_KEYWORDS,"alignas,alignof,align_union,asm,axiom,bool," +
+ "concept,concept_map,const_cast,constexpr,decltype,delegate," +
+ "dynamic_cast,explicit,export,friend,generic,late_check," +
+ "mutable,namespace,noexcept,noreturn,nullptr,property,reinterpret_cast,static_assert," +
+ "static_cast,template,typeid,typename,using,virtual,where"];
+ var JAVA_KEYWORDS = [COMMON_KEYWORDS,
+ "abstract,assert,boolean,byte,extends,finally,final,implements,import," +
+ "instanceof,interface,null,native,package,strictfp,super,synchronized," +
+ "throws,transient"];
+ var CSHARP_KEYWORDS = [COMMON_KEYWORDS,
+ "abstract,add,alias,as,ascending,async,await,base,bool,by,byte,checked,decimal,delegate,descending," +
+ "dynamic,event,finally,fixed,foreach,from,get,global,group,implicit,in,interface," +
+ "internal,into,is,join,let,lock,null,object,out,override,orderby,params," +
+ "partial,readonly,ref,remove,sbyte,sealed,select,set,stackalloc,string,select,uint,ulong," +
+ "unchecked,unsafe,ushort,value,var,virtual,where,yield"];
+ var COFFEE_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," +
+ "throw,true,try,unless,until,when,while,yes";
+ var JSCRIPT_KEYWORDS = [COMMON_KEYWORDS,
+ "abstract,async,await,constructor,debugger,enum,eval,export,function," +
+ "get,implements,instanceof,interface,let,null,set,undefined,var,with," +
+ "yield,Infinity,NaN"];
+ var PERL_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";
+ var PYTHON_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "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"];
+ var RUBY_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "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"];
+ var SH_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "case,done,elif,esac,eval,fi," +
+ "function,in,local,set,then,until"];
+ var ALL_KEYWORDS = [
+ CPP_KEYWORDS, CSHARP_KEYWORDS, JAVA_KEYWORDS, JSCRIPT_KEYWORDS,
+ PERL_KEYWORDS, PYTHON_KEYWORDS, RUBY_KEYWORDS, SH_KEYWORDS];
+ var C_TYPES = /^(DIR|FILE|array|vector|(de|priority_)?queue|(forward_)?list|stack|(const_)?(reverse_)?iterator|(unordered_)?(multi)?(set|map)|bitset|u?(int|float)\d*)\b/;
+
+ // token style names. correspond to css classes
+ /**
+ * token style for a string literal
+ * @const
+ */
+ var PR_STRING = 'str';
+ /**
+ * token style for a keyword
+ * @const
+ */
+ var PR_KEYWORD = 'kwd';
+ /**
+ * token style for a comment
+ * @const
+ */
+ var PR_COMMENT = 'com';
+ /**
+ * token style for a type
+ * @const
+ */
+ var PR_TYPE = 'typ';
+ /**
+ * token style for a literal value. e.g. 1, null, true.
+ * @const
+ */
+ var PR_LITERAL = 'lit';
+ /**
+ * token style for a punctuation string.
+ * @const
+ */
+ var PR_PUNCTUATION = 'pun';
+ /**
+ * token style for plain text.
+ * @const
+ */
+ var PR_PLAIN = 'pln';
+
+ /**
+ * token style for an sgml tag.
+ * @const
+ */
+ var PR_TAG = 'tag';
+ /**
+ * token style for a markup declaration such as a DOCTYPE.
+ * @const
+ */
+ var PR_DECLARATION = 'dec';
+ /**
+ * token style for embedded source.
+ * @const
+ */
+ var PR_SOURCE = 'src';
+ /**
+ * token style for an sgml attribute name.
+ * @const
+ */
+ var PR_ATTRIB_NAME = 'atn';
+ /**
+ * token style for an sgml attribute value.
+ * @const
+ */
+ var PR_ATTRIB_VALUE = 'atv';
+
+ /**
+ * A class that indicates a section of markup that is not code, e.g. to allow
+ * embedding of line numbers within code listings.
+ * @const
+ */
+ var PR_NOCODE = 'nocode';
+
+
+
+ /**
+ * A set of tokens that can precede a regular expression literal in
+ * javascript
+ * http://web.archive.org/web/20070717142515/http://www.mozilla.org/js/language/js20/rationale/syntax.html
+ * has the full list, but I've removed ones that might be problematic when
+ * seen in languages that don't support regular expression literals.
+ *
+ * <p>Specifically, I've removed any keywords that can't precede a regexp
+ * literal in a syntactically legal javascript program, and I've removed the
+ * "in" keyword since it's not a keyword in many languages, and might be used
+ * as a count of inches.
+ *
+ * <p>The link above does not accurately describe EcmaScript rules since
+ * it fails to distinguish between (a=++/b/i) and (a++/b/i) but it works
+ * very well in practice.
+ *
+ * @private
+ * @const
+ */
+ var REGEXP_PRECEDER_PATTERN = '(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<<?=?|>>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*';
+
+ // CAVEAT: this does not properly handle the case where a regular
+ // expression immediately follows another since a regular expression may
+ // have flags for case-sensitivity and the like. Having regexp tokens
+ // adjacent is not valid in any language I'm aware of, so I'm punting.
+ // TODO: maybe style special characters inside a regexp as punctuation.
+
+ /**
+ * Given a group of {@link RegExp}s, returns a {@code RegExp} that globally
+ * matches the union of the sets of strings matched by the input RegExp.
+ * Since it matches globally, if the input strings have a start-of-input
+ * anchor (/^.../), it is ignored for the purposes of unioning.
+ * @param {Array.<RegExp>} regexs non multiline, non-global regexs.
+ * @return {RegExp} a global regex.
+ */
+ function combinePrefixPatterns(regexs) {
+ var capturedGroupIndex = 0;
+
+ var needToFoldCase = false;
+ var ignoreCase = false;
+ for (var i = 0, n = regexs.length; i < n; ++i) {
+ var regex = regexs[i];
+ if (regex.ignoreCase) {
+ ignoreCase = true;
+ } else if (/[a-z]/i.test(regex.source.replace(
+ /\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi, ''))) {
+ needToFoldCase = true;
+ ignoreCase = false;
+ break;
+ }
+ }
+
+ var escapeCharToCodeUnit = {
+ 'b': 8,
+ 't': 9,
+ 'n': 0xa,
+ 'v': 0xb,
+ 'f': 0xc,
+ 'r': 0xd
+ };
+
+ function decodeEscape(charsetPart) {
+ var cc0 = charsetPart.charCodeAt(0);
+ if (cc0 !== 92 /* \\ */) {
+ return cc0;
+ }
+ var c1 = charsetPart.charAt(1);
+ cc0 = escapeCharToCodeUnit[c1];
+ if (cc0) {
+ return cc0;
+ } else if ('0' <= c1 && c1 <= '7') {
+ return parseInt(charsetPart.substring(1), 8);
+ } else if (c1 === 'u' || c1 === 'x') {
+ return parseInt(charsetPart.substring(2), 16);
+ } else {
+ return charsetPart.charCodeAt(1);
+ }
+ }
+
+ function encodeEscape(charCode) {
+ if (charCode < 0x20) {
+ return (charCode < 0x10 ? '\\x0' : '\\x') + charCode.toString(16);
+ }
+ var ch = String.fromCharCode(charCode);
+ return (ch === '\\' || ch === '-' || ch === ']' || ch === '^')
+ ? "\\" + ch : ch;
+ }
+
+ function caseFoldCharset(charSet) {
+ var charsetParts = charSet.substring(1, charSet.length - 1).match(
+ new RegExp(
+ '\\\\u[0-9A-Fa-f]{4}'
+ + '|\\\\x[0-9A-Fa-f]{2}'
+ + '|\\\\[0-3][0-7]{0,2}'
+ + '|\\\\[0-7]{1,2}'
+ + '|\\\\[\\s\\S]'
+ + '|-'
+ + '|[^-\\\\]',
+ 'g'));
+ var ranges = [];
+ var inverse = charsetParts[0] === '^';
+
+ var out = ['['];
+ if (inverse) { out.push('^'); }
+
+ for (var i = inverse ? 1 : 0, n = charsetParts.length; i < n; ++i) {
+ var p = charsetParts[i];
+ if (/\\[bdsw]/i.test(p)) { // Don't muck with named groups.
+ out.push(p);
+ } else {
+ var start = decodeEscape(p);
+ var end;
+ if (i + 2 < n && '-' === charsetParts[i + 1]) {
+ end = decodeEscape(charsetParts[i + 2]);
+ i += 2;
+ } else {
+ end = start;
+ }
+ ranges.push([start, end]);
+ // If the range might intersect letters, then expand it.
+ // This case handling is too simplistic.
+ // It does not deal with non-latin case folding.
+ // It works for latin source code identifiers though.
+ if (!(end < 65 || start > 122)) {
+ if (!(end < 65 || start > 90)) {
+ ranges.push([Math.max(65, start) | 32, Math.min(end, 90) | 32]);
+ }
+ if (!(end < 97 || start > 122)) {
+ ranges.push([Math.max(97, start) & ~32, Math.min(end, 122) & ~32]);
+ }
+ }
+ }
+ }
+
+ // [[1, 10], [3, 4], [8, 12], [14, 14], [16, 16], [17, 17]]
+ // -> [[1, 12], [14, 14], [16, 17]]
+ ranges.sort(function (a, b) { return (a[0] - b[0]) || (b[1] - a[1]); });
+ var consolidatedRanges = [];
+ var lastRange = [];
+ for (var i = 0; i < ranges.length; ++i) {
+ var range = ranges[i];
+ if (range[0] <= lastRange[1] + 1) {
+ lastRange[1] = Math.max(lastRange[1], range[1]);
+ } else {
+ consolidatedRanges.push(lastRange = range);
+ }
+ }
+
+ for (var i = 0; i < consolidatedRanges.length; ++i) {
+ var range = consolidatedRanges[i];
+ out.push(encodeEscape(range[0]));
+ if (range[1] > range[0]) {
+ if (range[1] + 1 > range[0]) { out.push('-'); }
+ out.push(encodeEscape(range[1]));
+ }
+ }
+ out.push(']');
+ return out.join('');
+ }
+
+ function allowAnywhereFoldCaseAndRenumberGroups(regex) {
+ // Split into character sets, escape sequences, punctuation strings
+ // like ('(', '(?:', ')', '^'), and runs of characters that do not
+ // include any of the above.
+ var parts = regex.source.match(
+ new RegExp(
+ '(?:'
+ + '\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]' // a character set
+ + '|\\\\u[A-Fa-f0-9]{4}' // a unicode escape
+ + '|\\\\x[A-Fa-f0-9]{2}' // a hex escape
+ + '|\\\\[0-9]+' // a back-reference or octal escape
+ + '|\\\\[^ux0-9]' // other escape sequence
+ + '|\\(\\?[:!=]' // start of a non-capturing group
+ + '|[\\(\\)\\^]' // start/end of a group, or line start
+ + '|[^\\x5B\\x5C\\(\\)\\^]+' // run of other characters
+ + ')',
+ 'g'));
+ var n = parts.length;
+
+ // Maps captured group numbers to the number they will occupy in
+ // the output or to -1 if that has not been determined, or to
+ // undefined if they need not be capturing in the output.
+ var capturedGroups = [];
+
+ // Walk over and identify back references to build the capturedGroups
+ // mapping.
+ for (var i = 0, groupIndex = 0; i < n; ++i) {
+ var p = parts[i];
+ if (p === '(') {
+ // groups are 1-indexed, so max group index is count of '('
+ ++groupIndex;
+ } else if ('\\' === p.charAt(0)) {
+ var decimalValue = +p.substring(1);
+ if (decimalValue) {
+ if (decimalValue <= groupIndex) {
+ capturedGroups[decimalValue] = -1;
+ } else {
+ // Replace with an unambiguous escape sequence so that
+ // an octal escape sequence does not turn into a backreference
+ // to a capturing group from an earlier regex.
+ parts[i] = encodeEscape(decimalValue);
+ }
+ }
+ }
+ }
+
+ // Renumber groups and reduce capturing groups to non-capturing groups
+ // where possible.
+ for (var i = 1; i < capturedGroups.length; ++i) {
+ if (-1 === capturedGroups[i]) {
+ capturedGroups[i] = ++capturedGroupIndex;
+ }
+ }
+ for (var i = 0, groupIndex = 0; i < n; ++i) {
+ var p = parts[i];
+ if (p === '(') {
+ ++groupIndex;
+ if (!capturedGroups[groupIndex]) {
+ parts[i] = '(?:';
+ }
+ } else if ('\\' === p.charAt(0)) {
+ var decimalValue = +p.substring(1);
+ if (decimalValue && decimalValue <= groupIndex) {
+ parts[i] = '\\' + capturedGroups[decimalValue];
+ }
+ }
+ }
+
+ // Remove any prefix anchors so that the output will match anywhere.
+ // ^^ really does mean an anchored match though.
+ for (var i = 0; i < n; ++i) {
+ if ('^' === parts[i] && '^' !== parts[i + 1]) { parts[i] = ''; }
+ }
+
+ // Expand letters to groups to handle mixing of case-sensitive and
+ // case-insensitive patterns if necessary.
+ if (regex.ignoreCase && needToFoldCase) {
+ for (var i = 0; i < n; ++i) {
+ var p = parts[i];
+ var ch0 = p.charAt(0);
+ if (p.length >= 2 && ch0 === '[') {
+ parts[i] = caseFoldCharset(p);
+ } else if (ch0 !== '\\') {
+ // TODO: handle letters in numeric escapes.
+ parts[i] = p.replace(
+ /[a-zA-Z]/g,
+ function (ch) {
+ var cc = ch.charCodeAt(0);
+ return '[' + String.fromCharCode(cc & ~32, cc | 32) + ']';
+ });
+ }
+ }
+ }
+
+ return parts.join('');
+ }
+
+ var rewritten = [];
+ for (var i = 0, n = regexs.length; i < n; ++i) {
+ var regex = regexs[i];
+ if (regex.global || regex.multiline) { throw new Error('' + regex); }
+ rewritten.push(
+ '(?:' + allowAnywhereFoldCaseAndRenumberGroups(regex) + ')');
+ }
+
+ return new RegExp(rewritten.join('|'), ignoreCase ? 'gi' : 'g');
+ }
+
+ /**
+ * Split markup into a string of source code and an array mapping ranges in
+ * that string to the text nodes in which they appear.
+ *
+ * <p>
+ * The HTML DOM structure:</p>
+ * <pre>
+ * (Element "p"
+ * (Element "b"
+ * (Text "print ")) ; #1
+ * (Text "'Hello '") ; #2
+ * (Element "br") ; #3
+ * (Text " + 'World';")) ; #4
+ * </pre>
+ * <p>
+ * corresponds to the HTML
+ * {@code <p><b>print </b>'Hello '<br> + 'World';</p>}.</p>
+ *
+ * <p>
+ * It will produce the output:</p>
+ * <pre>
+ * {
+ * sourceCode: "print 'Hello '\n + 'World';",
+ * // 1 2
+ * // 012345678901234 5678901234567
+ * spans: [0, #1, 6, #2, 14, #3, 15, #4]
+ * }
+ * </pre>
+ * <p>
+ * where #1 is a reference to the {@code "print "} text node above, and so
+ * on for the other text nodes.
+ * </p>
+ *
+ * <p>
+ * The {@code} spans array is an array of pairs. Even elements are the start
+ * indices of substrings, and odd elements are the text nodes (or BR elements)
+ * that contain the text for those substrings.
+ * Substrings continue until the next index or the end of the source.
+ * </p>
+ *
+ * @param {Node} node an HTML DOM subtree containing source-code.
+ * @param {boolean|number} isPreformatted truthy if white-space in
+ * text nodes should be considered significant.
+ * @return {SourceSpansT} source code and the nodes in which they occur.
+ */
+ function extractSourceSpans(node, isPreformatted) {
+ var nocode = /(?:^|\s)nocode(?:\s|$)/;
+
+ var chunks = [];
+ var length = 0;
+ var spans = [];
+ var k = 0;
+
+ function walk(node) {
+ var type = node.nodeType;
+ if (type == 1) { // Element
+ if (nocode.test(node.className)) { return; }
+ for (var child = node.firstChild; child; child = child.nextSibling) {
+ walk(child);
+ }
+ var nodeName = node.nodeName.toLowerCase();
+ if ('br' === nodeName || 'li' === nodeName) {
+ chunks[k] = '\n';
+ spans[k << 1] = length++;
+ spans[(k++ << 1) | 1] = node;
+ }
+ } else if (type == 3 || type == 4) { // Text
+ var text = node.nodeValue;
+ if (text.length) {
+ if (!isPreformatted) {
+ text = text.replace(/[ \t\r\n]+/g, ' ');
+ } else {
+ text = text.replace(/\r\n?/g, '\n'); // Normalize newlines.
+ }
+ // TODO: handle tabs here?
+ chunks[k] = text;
+ spans[k << 1] = length;
+ length += text.length;
+ spans[(k++ << 1) | 1] = node;
+ }
+ }
+ }
+
+ walk(node);
+
+ return {
+ sourceCode: chunks.join('').replace(/\n$/, ''),
+ spans: spans
+ };
+ }
+
+ /**
+ * Apply the given language handler to sourceCode and add the resulting
+ * decorations to out.
+ * @param {!Element} sourceNode
+ * @param {number} basePos the index of sourceCode within the chunk of source
+ * whose decorations are already present on out.
+ * @param {string} sourceCode
+ * @param {function(JobT)} langHandler
+ * @param {DecorationsT} out
+ */
+ function appendDecorations(
+ sourceNode, basePos, sourceCode, langHandler, out) {
+ if (!sourceCode) { return; }
+ /** @type {JobT} */
+ var job = {
+ sourceNode: sourceNode,
+ pre: 1,
+ langExtension: null,
+ numberLines: null,
+ sourceCode: sourceCode,
+ spans: null,
+ basePos: basePos,
+ decorations: null
+ };
+ langHandler(job);
+ out.push.apply(out, job.decorations);
+ }
+
+ var notWs = /\S/;
+
+ /**
+ * Given an element, if it contains only one child element and any text nodes
+ * it contains contain only space characters, return the sole child element.
+ * Otherwise returns undefined.
+ * <p>
+ * This is meant to return the CODE element in {@code <pre><code ...>} when
+ * there is a single child element that contains all the non-space textual
+ * content, but not to return anything where there are multiple child elements
+ * as in {@code <pre><code>...</code><code>...</code></pre>} or when there
+ * is textual content.
+ */
+ function childContentWrapper(element) {
+ var wrapper = undefined;
+ for (var c = element.firstChild; c; c = c.nextSibling) {
+ var type = c.nodeType;
+ wrapper = (type === 1) // Element Node
+ ? (wrapper ? element : c)
+ : (type === 3) // Text Node
+ ? (notWs.test(c.nodeValue) ? element : wrapper)
+ : wrapper;
+ }
+ return wrapper === element ? undefined : wrapper;
+ }
+
+ /** Given triples of [style, pattern, context] returns a lexing function,
+ * The lexing function interprets the patterns to find token boundaries and
+ * returns a decoration list of the form
+ * [index_0, style_0, index_1, style_1, ..., index_n, style_n]
+ * where index_n is an index into the sourceCode, and style_n is a style
+ * constant like PR_PLAIN. index_n-1 <= index_n, and style_n-1 applies to
+ * all characters in sourceCode[index_n-1:index_n].
+ *
+ * The stylePatterns is a list whose elements have the form
+ * [style : string, pattern : RegExp, DEPRECATED, shortcut : string].
+ *
+ * Style is a style constant like PR_PLAIN, or can be a string of the
+ * form 'lang-FOO', where FOO is a language extension describing the
+ * language of the portion of the token in $1 after pattern executes.
+ * E.g., if style is 'lang-lisp', and group 1 contains the text
+ * '(hello (world))', then that portion of the token will be passed to the
+ * registered lisp handler for formatting.
+ * The text before and after group 1 will be restyled using this decorator
+ * so decorators should take care that this doesn't result in infinite
+ * recursion. For example, the HTML lexer rule for SCRIPT elements looks
+ * something like ['lang-js', /<[s]cript>(.+?)<\/script>/]. This may match
+ * '<script>foo()<\/script>', which would cause the current decorator to
+ * be called with '<script>' which would not match the same rule since
+ * group 1 must not be empty, so it would be instead styled as PR_TAG by
+ * the generic tag rule. The handler registered for the 'js' extension would
+ * then be called with 'foo()', and finally, the current decorator would
+ * be called with '<\/script>' which would not match the original rule and
+ * so the generic tag rule would identify it as a tag.
+ *
+ * Pattern must only match prefixes, and if it matches a prefix, then that
+ * match is considered a token with the same style.
+ *
+ * Context is applied to the last non-whitespace, non-comment token
+ * recognized.
+ *
+ * Shortcut is an optional string of characters, any of which, if the first
+ * character, gurantee that this pattern and only this pattern matches.
+ *
+ * @param {Array} shortcutStylePatterns patterns that always start with
+ * a known character. Must have a shortcut string.
+ * @param {Array} fallthroughStylePatterns patterns that will be tried in
+ * order if the shortcut ones fail. May have shortcuts.
+ *
+ * @return {function (JobT)} a function that takes an undecorated job and
+ * attaches a list of decorations.
+ */
+ function createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns) {
+ var shortcuts = {};
+ var tokenizer;
+ (function () {
+ var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns);
+ var allRegexs = [];
+ var regexKeys = {};
+ for (var i = 0, n = allPatterns.length; i < n; ++i) {
+ var patternParts = allPatterns[i];
+ var shortcutChars = patternParts[3];
+ if (shortcutChars) {
+ for (var c = shortcutChars.length; --c >= 0;) {
+ shortcuts[shortcutChars.charAt(c)] = patternParts;
+ }
+ }
+ var regex = patternParts[1];
+ var k = '' + regex;
+ if (!regexKeys.hasOwnProperty(k)) {
+ allRegexs.push(regex);
+ regexKeys[k] = null;
+ }
+ }
+ allRegexs.push(/[\0-\uffff]/);
+ tokenizer = combinePrefixPatterns(allRegexs);
+ })();
+
+ var nPatterns = fallthroughStylePatterns.length;
+
+ /**
+ * Lexes job.sourceCode and attaches an output array job.decorations of
+ * style classes preceded by the position at which they start in
+ * job.sourceCode in order.
+ *
+ * @type{function (JobT)}
+ */
+ var decorate = function (job) {
+ var sourceCode = job.sourceCode, basePos = job.basePos;
+ var sourceNode = job.sourceNode;
+ /** Even entries are positions in source in ascending order. Odd enties
+ * are style markers (e.g., PR_COMMENT) that run from that position until
+ * the end.
+ * @type {DecorationsT}
+ */
+ var decorations = [basePos, PR_PLAIN];
+ var pos = 0; // index into sourceCode
+ var tokens = sourceCode.match(tokenizer) || [];
+ var styleCache = {};
+
+ for (var ti = 0, nTokens = tokens.length; ti < nTokens; ++ti) {
+ var token = tokens[ti];
+ var style = styleCache[token];
+ var match = void 0;
+
+ var isEmbedded;
+ if (typeof style === 'string') {
+ isEmbedded = false;
+ } else {
+ var patternParts = shortcuts[token.charAt(0)];
+ if (patternParts) {
+ match = token.match(patternParts[1]);
+ style = patternParts[0];
+ } else {
+ for (var i = 0; i < nPatterns; ++i) {
+ patternParts = fallthroughStylePatterns[i];
+ match = token.match(patternParts[1]);
+ if (match) {
+ style = patternParts[0];
+ break;
+ }
+ }
+
+ if (!match) { // make sure that we make progress
+ style = PR_PLAIN;
+ }
+ }
+
+ isEmbedded = style.length >= 5 && 'lang-' === style.substring(0, 5);
+ if (isEmbedded && !(match && typeof match[1] === 'string')) {
+ isEmbedded = false;
+ style = PR_SOURCE;
+ }
+
+ if (!isEmbedded) { styleCache[token] = style; }
+ }
+
+ var tokenStart = pos;
+ pos += token.length;
+
+ if (!isEmbedded) {
+ decorations.push(basePos + tokenStart, style);
+ } else { // Treat group 1 as an embedded block of source code.
+ var embeddedSource = match[1];
+ var embeddedSourceStart = token.indexOf(embeddedSource);
+ var embeddedSourceEnd = embeddedSourceStart + embeddedSource.length;
+ if (match[2]) {
+ // If embeddedSource can be blank, then it would match at the
+ // beginning which would cause us to infinitely recurse on the
+ // entire token, so we catch the right context in match[2].
+ embeddedSourceEnd = token.length - match[2].length;
+ embeddedSourceStart = embeddedSourceEnd - embeddedSource.length;
+ }
+ var lang = style.substring(5);
+ // Decorate the left of the embedded source
+ appendDecorations(
+ sourceNode,
+ basePos + tokenStart,
+ token.substring(0, embeddedSourceStart),
+ decorate, decorations);
+ // Decorate the embedded source
+ appendDecorations(
+ sourceNode,
+ basePos + tokenStart + embeddedSourceStart,
+ embeddedSource,
+ langHandlerForExtension(lang, embeddedSource),
+ decorations);
+ // Decorate the right of the embedded section
+ appendDecorations(
+ sourceNode,
+ basePos + tokenStart + embeddedSourceEnd,
+ token.substring(embeddedSourceEnd),
+ decorate, decorations);
+ }
+ }
+ job.decorations = decorations;
+ };
+ return decorate;
+ }
+
+ /** returns a function that produces a list of decorations from source text.
+ *
+ * This code treats ", ', and ` as string delimiters, and \ as a string
+ * escape. It does not recognize perl's qq() style strings.
+ * It has no special handling for double delimiter escapes as in basic, or
+ * the tripled delimiters used in python, but should work on those regardless
+ * although in those cases a single string literal may be broken up into
+ * multiple adjacent string literals.
+ *
+ * It recognizes C, C++, and shell style comments.
+ *
+ * @param {Object} options a set of optional parameters.
+ * @return {function (JobT)} a function that examines the source code
+ * in the input job and builds a decoration list which it attaches to
+ * the job.
+ */
+ function sourceDecorator(options) {
+ var shortcutStylePatterns = [], fallthroughStylePatterns = [];
+ if (options['tripleQuotedStrings']) {
+ // '''multi-line-string''', 'single-line-string', and double-quoted
+ shortcutStylePatterns.push(
+ [PR_STRING, /^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,
+ null, '\'"']);
+ } else if (options['multiLineStrings']) {
+ // 'multi-line-string', "multi-line-string"
+ shortcutStylePatterns.push(
+ [PR_STRING, /^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,
+ null, '\'"`']);
+ } else {
+ // 'single-line-string', "single-line-string"
+ shortcutStylePatterns.push(
+ [PR_STRING,
+ /^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,
+ null, '"\'']);
+ }
+ if (options['verbatimStrings']) {
+ // verbatim-string-literal production from the C# grammar. See issue 93.
+ fallthroughStylePatterns.push(
+ [PR_STRING, /^@\"(?:[^\"]|\"\")*(?:\"|$)/, null]);
+ }
+ var hc = options['hashComments'];
+ if (hc) {
+ if (options['cStyleComments']) {
+ if (hc > 1) { // multiline hash comments
+ shortcutStylePatterns.push(
+ [PR_COMMENT, /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, null, '#']);
+ } else {
+ // Stop C preprocessor declarations at an unclosed open comment
+ shortcutStylePatterns.push(
+ [PR_COMMENT, /^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\r\n]*)/,
+ null, '#']);
+ }
+ // #include <stdio.h>
+ fallthroughStylePatterns.push(
+ [PR_STRING,
+ /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,
+ null]);
+ } else {
+ shortcutStylePatterns.push([PR_COMMENT, /^#[^\r\n]*/, null, '#']);
+ }
+ }
+ if (options['cStyleComments']) {
+ fallthroughStylePatterns.push([PR_COMMENT, /^\/\/[^\r\n]*/, null]);
+ fallthroughStylePatterns.push(
+ [PR_COMMENT, /^\/\*[\s\S]*?(?:\*\/|$)/, null]);
+ }
+ var regexLiterals = options['regexLiterals'];
+ if (regexLiterals) {
+ /**
+ * @const
+ */
+ var regexExcls = regexLiterals > 1
+ ? '' // Multiline regex literals
+ : '\n\r';
+ /**
+ * @const
+ */
+ var regexAny = regexExcls ? '.' : '[\\S\\s]';
+ /**
+ * @const
+ */
+ var REGEX_LITERAL = (
+ // A regular expression literal starts with a slash that is
+ // not followed by * or / so that it is not confused with
+ // comments.
+ '/(?=[^/*' + regexExcls + '])'
+ // and then contains any number of raw characters,
+ + '(?:[^/\\x5B\\x5C' + regexExcls + ']'
+ // escape sequences (\x5C),
+ + '|\\x5C' + regexAny
+ // or non-nesting character sets (\x5B\x5D);
+ + '|\\x5B(?:[^\\x5C\\x5D' + regexExcls + ']'
+ + '|\\x5C' + regexAny + ')*(?:\\x5D|$))+'
+ // finally closed by a /.
+ + '/');
+ fallthroughStylePatterns.push(
+ ['lang-regex',
+ RegExp('^' + REGEXP_PRECEDER_PATTERN + '(' + REGEX_LITERAL + ')')
+ ]);
+ }
+
+ var types = options['types'];
+ if (types) {
+ fallthroughStylePatterns.push([PR_TYPE, types]);
+ }
+
+ var keywords = ("" + options['keywords']).replace(/^ | $/g, '');
+ if (keywords.length) {
+ fallthroughStylePatterns.push(
+ [PR_KEYWORD,
+ new RegExp('^(?:' + keywords.replace(/[\s,]+/g, '|') + ')\\b'),
+ null]);
+ }
+
+ shortcutStylePatterns.push([PR_PLAIN, /^\s+/, null, ' \r\n\t\xA0']);
+
+ var punctuation =
+ // The Bash man page says
+
+ // A word is a sequence of characters considered as a single
+ // unit by GRUB. Words are separated by metacharacters,
+ // which are the following plus space, tab, and newline: { }
+ // | & $ ; < >
+ // ...
+
+ // A word beginning with # causes that word and all remaining
+ // characters on that line to be ignored.
+
+ // which means that only a '#' after /(?:^|[{}|&$;<>\s])/ starts a
+ // comment but empirically
+ // $ echo {#}
+ // {#}
+ // $ echo \$#
+ // $#
+ // $ echo }#
+ // }#
+
+ // so /(?:^|[|&;<>\s])/ is more appropriate.
+
+ // http://gcc.gnu.org/onlinedocs/gcc-2.95.3/cpp_1.html#SEC3
+ // suggests that this definition is compatible with a
+ // default mode that tries to use a single token definition
+ // to recognize both bash/python style comments and C
+ // preprocessor directives.
+
+ // This definition of punctuation does not include # in the list of
+ // follow-on exclusions, so # will not be broken before if preceeded
+ // by a punctuation character. We could try to exclude # after
+ // [|&;<>] but that doesn't seem to cause many major problems.
+ // If that does turn out to be a problem, we should change the below
+ // when hc is truthy to include # in the run of punctuation characters
+ // only when not followint [|&;<>].
+ '^.[^\\s\\w.$@\'"`/\\\\]*';
+ if (options['regexLiterals']) {
+ punctuation += '(?!\s*\/)';
+ }
+
+ fallthroughStylePatterns.push(
+ // TODO(mikesamuel): recognize non-latin letters and numerals in idents
+ [PR_LITERAL, /^@[a-z_$][a-z_$@0-9]*/i, null],
+ [PR_TYPE, /^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/, null],
+ [PR_PLAIN, /^[a-z_$][a-z_$@0-9]*/i, null],
+ [PR_LITERAL,
+ new RegExp(
+ '^(?:'
+ // A hex number
+ + '0x[a-f0-9]+'
+ // or an octal or decimal number,
+ + '|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)'
+ // possibly in scientific notation
+ + '(?:e[+\\-]?\\d+)?'
+ + ')'
+ // with an optional modifier like UL for unsigned long
+ + '[a-z]*', 'i'),
+ null, '0123456789'],
+ // Don't treat escaped quotes in bash as starting strings.
+ // See issue 144.
+ [PR_PLAIN, /^\\[\s\S]?/, null],
+ [PR_PUNCTUATION, new RegExp(punctuation), null]);
+
+ return createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns);
+ }
+
+ var decorateSource = sourceDecorator({
+ 'keywords': ALL_KEYWORDS,
+ 'hashComments': true,
+ 'cStyleComments': true,
+ 'multiLineStrings': true,
+ 'regexLiterals': true
+ });
+
+ /**
+ * Given a DOM subtree, wraps it in a list, and puts each line into its own
+ * list item.
+ *
+ * @param {Node} node modified in place. Its content is pulled into an
+ * HTMLOListElement, and each line is moved into a separate list item.
+ * This requires cloning elements, so the input might not have unique
+ * IDs after numbering.
+ * @param {number|null|boolean} startLineNum
+ * If truthy, coerced to an integer which is the 1-indexed line number
+ * of the first line of code. The number of the first line will be
+ * attached to the list.
+ * @param {boolean} isPreformatted true iff white-space in text nodes should
+ * be treated as significant.
+ */
+ function numberLines(node, startLineNum, isPreformatted) {
+ var nocode = /(?:^|\s)nocode(?:\s|$)/;
+ var lineBreak = /\r\n?|\n/;
+
+ var document = node.ownerDocument;
+
+ var li = document.createElement('li');
+ while (node.firstChild) {
+ li.appendChild(node.firstChild);
+ }
+ // An array of lines. We split below, so this is initialized to one
+ // un-split line.
+ var listItems = [li];
+
+ function walk(node) {
+ var type = node.nodeType;
+ if (type == 1 && !nocode.test(node.className)) { // Element
+ if ('br' === node.nodeName) {
+ breakAfter(node);
+ // Discard the <BR> since it is now flush against a </LI>.
+ if (node.parentNode) {
+ node.parentNode.removeChild(node);
+ }
+ } else {
+ for (var child = node.firstChild; child; child = child.nextSibling) {
+ walk(child);
+ }
+ }
+ } else if ((type == 3 || type == 4) && isPreformatted) { // Text
+ var text = node.nodeValue;
+ var match = text.match(lineBreak);
+ if (match) {
+ var firstLine = text.substring(0, match.index);
+ node.nodeValue = firstLine;
+ var tail = text.substring(match.index + match[0].length);
+ if (tail) {
+ var parent = node.parentNode;
+ parent.insertBefore(
+ document.createTextNode(tail), node.nextSibling);
+ }
+ breakAfter(node);
+ if (!firstLine) {
+ // Don't leave blank text nodes in the DOM.
+ node.parentNode.removeChild(node);
+ }
+ }
+ }
+ }
+
+ // Split a line after the given node.
+ function breakAfter(lineEndNode) {
+ // If there's nothing to the right, then we can skip ending the line
+ // here, and move root-wards since splitting just before an end-tag
+ // would require us to create a bunch of empty copies.
+ while (!lineEndNode.nextSibling) {
+ lineEndNode = lineEndNode.parentNode;
+ if (!lineEndNode) { return; }
+ }
+
+ function breakLeftOf(limit, copy) {
+ // Clone shallowly if this node needs to be on both sides of the break.
+ var rightSide = copy ? limit.cloneNode(false) : limit;
+ var parent = limit.parentNode;
+ if (parent) {
+ // We clone the parent chain.
+ // This helps us resurrect important styling elements that cross lines.
+ // E.g. in <i>Foo<br>Bar</i>
+ // should be rewritten to <li><i>Foo</i></li><li><i>Bar</i></li>.
+ var parentClone = breakLeftOf(parent, 1);
+ // Move the clone and everything to the right of the original
+ // onto the cloned parent.
+ var next = limit.nextSibling;
+ parentClone.appendChild(rightSide);
+ for (var sibling = next; sibling; sibling = next) {
+ next = sibling.nextSibling;
+ parentClone.appendChild(sibling);
+ }
+ }
+ return rightSide;
+ }
+
+ var copiedListItem = breakLeftOf(lineEndNode.nextSibling, 0);
+
+ // Walk the parent chain until we reach an unattached LI.
+ for (var parent;
+ // Check nodeType since IE invents document fragments.
+ (parent = copiedListItem.parentNode) && parent.nodeType === 1;) {
+ copiedListItem = parent;
+ }
+ // Put it on the list of lines for later processing.
+ listItems.push(copiedListItem);
+ }
+
+ // Split lines while there are lines left to split.
+ for (var i = 0; // Number of lines that have been split so far.
+ i < listItems.length; // length updated by breakAfter calls.
+ ++i) {
+ walk(listItems[i]);
+ }
+
+ // Make sure numeric indices show correctly.
+ if (startLineNum === (startLineNum|0)) {
+ listItems[0].setAttribute('value', startLineNum);
+ }
+
+ var ol = document.createElement('ol');
+ ol.className = 'linenums';
+ var offset = Math.max(0, ((startLineNum - 1 /* zero index */)) | 0) || 0;
+ for (var i = 0, n = listItems.length; i < n; ++i) {
+ li = listItems[i];
+ // Stick a class on the LIs so that stylesheets can
+ // color odd/even rows, or any other row pattern that
+ // is co-prime with 10.
+ li.className = 'L' + ((i + offset) % 10);
+ if (!li.firstChild) {
+ li.appendChild(document.createTextNode('\xA0'));
+ }
+ ol.appendChild(li);
+ }
+
+ node.appendChild(ol);
+ }
+
+ /**
+ * Breaks {@code job.sourceCode} around style boundaries in
+ * {@code job.decorations} and modifies {@code job.sourceNode} in place.
+ * @param {JobT} job
+ * @private
+ */
+ function recombineTagsAndDecorations(job) {
+ var isIE8OrEarlier = /\bMSIE\s(\d+)/.exec(navigator.userAgent);
+ isIE8OrEarlier = isIE8OrEarlier && +isIE8OrEarlier[1] <= 8;
+ var newlineRe = /\n/g;
+
+ var source = job.sourceCode;
+ var sourceLength = source.length;
+ // Index into source after the last code-unit recombined.
+ var sourceIndex = 0;
+
+ var spans = job.spans;
+ var nSpans = spans.length;
+ // Index into spans after the last span which ends at or before sourceIndex.
+ var spanIndex = 0;
+
+ var decorations = job.decorations;
+ var nDecorations = decorations.length;
+ // Index into decorations after the last decoration which ends at or before
+ // sourceIndex.
+ var decorationIndex = 0;
+
+ // Remove all zero-length decorations.
+ decorations[nDecorations] = sourceLength;
+ var decPos, i;
+ for (i = decPos = 0; i < nDecorations;) {
+ if (decorations[i] !== decorations[i + 2]) {
+ decorations[decPos++] = decorations[i++];
+ decorations[decPos++] = decorations[i++];
+ } else {
+ i += 2;
+ }
+ }
+ nDecorations = decPos;
+
+ // Simplify decorations.
+ for (i = decPos = 0; i < nDecorations;) {
+ var startPos = decorations[i];
+ // Conflate all adjacent decorations that use the same style.
+ var startDec = decorations[i + 1];
+ var end = i + 2;
+ while (end + 2 <= nDecorations && decorations[end + 1] === startDec) {
+ end += 2;
+ }
+ decorations[decPos++] = startPos;
+ decorations[decPos++] = startDec;
+ i = end;
+ }
+
+ nDecorations = decorations.length = decPos;
+
+ var sourceNode = job.sourceNode;
+ var oldDisplay = "";
+ if (sourceNode) {
+ oldDisplay = sourceNode.style.display;
+ sourceNode.style.display = 'none';
+ }
+ try {
+ var decoration = null;
+ while (spanIndex < nSpans) {
+ var spanStart = spans[spanIndex];
+ var spanEnd = /** @type{number} */ (spans[spanIndex + 2])
+ || sourceLength;
+
+ var decEnd = decorations[decorationIndex + 2] || sourceLength;
+
+ var end = Math.min(spanEnd, decEnd);
+
+ var textNode = /** @type{Node} */ (spans[spanIndex + 1]);
+ var styledText;
+ if (textNode.nodeType !== 1 // Don't muck with <BR>s or <LI>s
+ // Don't introduce spans around empty text nodes.
+ && (styledText = source.substring(sourceIndex, end))) {
+ // This may seem bizarre, and it is. Emitting LF on IE causes the
+ // code to display with spaces instead of line breaks.
+ // Emitting Windows standard issue linebreaks (CRLF) causes a blank
+ // space to appear at the beginning of every line but the first.
+ // Emitting an old Mac OS 9 line separator makes everything spiffy.
+ if (isIE8OrEarlier) {
+ styledText = styledText.replace(newlineRe, '\r');
+ }
+ textNode.nodeValue = styledText;
+ var document = textNode.ownerDocument;
+ var span = document.createElement('span');
+ span.className = decorations[decorationIndex + 1];
+ var parentNode = textNode.parentNode;
+ parentNode.replaceChild(span, textNode);
+ span.appendChild(textNode);
+ if (sourceIndex < spanEnd) { // Split off a text node.
+ spans[spanIndex + 1] = textNode
+ // TODO: Possibly optimize by using '' if there's no flicker.
+ = document.createTextNode(source.substring(end, spanEnd));
+ parentNode.insertBefore(textNode, span.nextSibling);
+ }
+ }
+
+ sourceIndex = end;
+
+ if (sourceIndex >= spanEnd) {
+ spanIndex += 2;
+ }
+ if (sourceIndex >= decEnd) {
+ decorationIndex += 2;
+ }
+ }
+ } finally {
+ if (sourceNode) {
+ sourceNode.style.display = oldDisplay;
+ }
+ }
+ }
+
+ /** Maps language-specific file extensions to handlers. */
+ var langHandlerRegistry = {};
+ /** Register a language handler for the given file extensions.
+ * @param {function (JobT)} handler a function from source code to a list
+ * of decorations. Takes a single argument job which describes the
+ * state of the computation and attaches the decorations to it.
+ * @param {Array.<string>} fileExtensions
+ */
+ function registerLangHandler(handler, fileExtensions) {
+ for (var i = fileExtensions.length; --i >= 0;) {
+ var ext = fileExtensions[i];
+ if (!langHandlerRegistry.hasOwnProperty(ext)) {
+ langHandlerRegistry[ext] = handler;
+ } else if (win['console']) {
+ console['warn']('cannot override language handler %s', ext);
+ }
+ }
+ }
+ function langHandlerForExtension(extension, source) {
+ if (!(extension && langHandlerRegistry.hasOwnProperty(extension))) {
+ // Treat it as markup if the first non whitespace character is a < and
+ // the last non-whitespace character is a >.
+ extension = /^\s*</.test(source)
+ ? 'default-markup'
+ : 'default-code';
+ }
+ return langHandlerRegistry[extension];
+ }
+ registerLangHandler(decorateSource, ['default-code']);
+ registerLangHandler(
+ createSimpleLexer(
+ [],
+ [
+ [PR_PLAIN, /^[^<?]+/],
+ [PR_DECLARATION, /^<!\w[^>]*(?:>|$)/],
+ [PR_COMMENT, /^<\!--[\s\S]*?(?:-\->|$)/],
+ // Unescaped content in an unknown language
+ ['lang-', /^<\?([\s\S]+?)(?:\?>|$)/],
+ ['lang-', /^<%([\s\S]+?)(?:%>|$)/],
+ [PR_PUNCTUATION, /^(?:<[%?]|[%?]>)/],
+ ['lang-', /^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],
+ // Unescaped content in javascript. (Or possibly vbscript).
+ ['lang-js', /^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],
+ // Contains unescaped stylesheet content
+ ['lang-css', /^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],
+ ['lang-in.tag', /^(<\/?[a-z][^<>]*>)/i]
+ ]),
+ ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl']);
+ registerLangHandler(
+ createSimpleLexer(
+ [
+ [PR_PLAIN, /^[\s]+/, null, ' \t\r\n'],
+ [PR_ATTRIB_VALUE, /^(?:\"[^\"]*\"?|\'[^\']*\'?)/, null, '\"\'']
+ ],
+ [
+ [PR_TAG, /^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],
+ [PR_ATTRIB_NAME, /^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],
+ ['lang-uq.val', /^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],
+ [PR_PUNCTUATION, /^[=<>\/]+/],
+ ['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']);
+ registerLangHandler(
+ createSimpleLexer([], [[PR_ATTRIB_VALUE, /^[\s\S]+/]]), ['uq.val']);
+ registerLangHandler(sourceDecorator({
+ 'keywords': CPP_KEYWORDS,
+ 'hashComments': true,
+ 'cStyleComments': true,
+ 'types': C_TYPES
+ }), ['c', 'cc', 'cpp', 'cxx', 'cyc', 'm']);
+ registerLangHandler(sourceDecorator({
+ 'keywords': 'null,true,false'
+ }), ['json']);
+ registerLangHandler(sourceDecorator({
+ 'keywords': CSHARP_KEYWORDS,
+ 'hashComments': true,
+ 'cStyleComments': true,
+ 'verbatimStrings': true,
+ 'types': C_TYPES
+ }), ['cs']);
+ registerLangHandler(sourceDecorator({
+ 'keywords': JAVA_KEYWORDS,
+ 'cStyleComments': true
+ }), ['java']);
+ registerLangHandler(sourceDecorator({
+ 'keywords': SH_KEYWORDS,
+ 'hashComments': true,
+ 'multiLineStrings': true
+ }), ['bash', 'bsh', 'csh', 'sh']);
+ registerLangHandler(sourceDecorator({
+ 'keywords': PYTHON_KEYWORDS,
+ 'hashComments': true,
+ 'multiLineStrings': true,
+ 'tripleQuotedStrings': true
+ }), ['cv', 'py', 'python']);
+ registerLangHandler(sourceDecorator({
+ 'keywords': PERL_KEYWORDS,
+ 'hashComments': true,
+ 'multiLineStrings': true,
+ 'regexLiterals': 2 // multiline regex literals
+ }), ['perl', 'pl', 'pm']);
+ registerLangHandler(sourceDecorator({
+ 'keywords': RUBY_KEYWORDS,
+ 'hashComments': true,
+ 'multiLineStrings': true,
+ 'regexLiterals': true
+ }), ['rb', 'ruby']);
+ registerLangHandler(sourceDecorator({
+ 'keywords': JSCRIPT_KEYWORDS,
+ 'cStyleComments': true,
+ 'regexLiterals': true
+ }), ['javascript', 'js', 'ts', 'typescript']);
+ registerLangHandler(sourceDecorator({
+ 'keywords': COFFEE_KEYWORDS,
+ 'hashComments': 3, // ### style block comments
+ 'cStyleComments': true,
+ 'multilineStrings': true,
+ 'tripleQuotedStrings': true,
+ 'regexLiterals': true
+ }), ['coffee']);
+ registerLangHandler(
+ createSimpleLexer([], [[PR_STRING, /^[\s\S]+/]]), ['regex']);
+
+ /** @param {JobT} job */
+ function applyDecorator(job) {
+ var opt_langExtension = job.langExtension;
+
+ try {
+ // Extract tags, and convert the source code to plain text.
+ var sourceAndSpans = extractSourceSpans(job.sourceNode, job.pre);
+ /** Plain text. @type {string} */
+ var source = sourceAndSpans.sourceCode;
+ job.sourceCode = source;
+ job.spans = sourceAndSpans.spans;
+ job.basePos = 0;
+
+ // Apply the appropriate language handler
+ langHandlerForExtension(opt_langExtension, source)(job);
+
+ // Integrate the decorations and tags back into the source code,
+ // modifying the sourceNode in place.
+ recombineTagsAndDecorations(job);
+ } catch (e) {
+ if (win['console']) {
+ console['log'](e && e['stack'] || e);
+ }
+ }
+ }
+
+ /**
+ * Pretty print a chunk of code.
+ * @param sourceCodeHtml {string} The HTML to pretty print.
+ * @param opt_langExtension {string} The language name to use.
+ * Typically, a filename extension like 'cpp' or 'java'.
+ * @param opt_numberLines {number|boolean} True to number lines,
+ * or the 1-indexed number of the first line in sourceCodeHtml.
+ */
+ function $prettyPrintOne(sourceCodeHtml, opt_langExtension, opt_numberLines) {
+ /** @type{number|boolean} */
+ var nl = opt_numberLines || false;
+ /** @type{string|null} */
+ var langExtension = opt_langExtension || null;
+ /** @type{!Element} */
+ var container = document.createElement('div');
+ // This could cause images to load and onload listeners to fire.
+ // E.g. <img onerror="alert(1337)" src="nosuchimage.png">.
+ // We assume that the inner HTML is from a trusted source.
+ // The pre-tag is required for IE8 which strips newlines from innerHTML
+ // when it is injected into a <pre> tag.
+ // http://stackoverflow.com/questions/451486/pre-tag-loses-line-breaks-when-setting-innerhtml-in-ie
+ // http://stackoverflow.com/questions/195363/inserting-a-newline-into-a-pre-tag-ie-javascript
+ container.innerHTML = '<pre>' + sourceCodeHtml + '</pre>';
+ container = /** @type{!Element} */(container.firstChild);
+ if (nl) {
+ numberLines(container, nl, true);
+ }
+
+ /** @type{JobT} */
+ var job = {
+ langExtension: langExtension,
+ numberLines: nl,
+ sourceNode: container,
+ pre: 1,
+ sourceCode: null,
+ basePos: null,
+ spans: null,
+ decorations: null
+ };
+ applyDecorator(job);
+ return container.innerHTML;
+ }
+
+ /**
+ * Find all the {@code <pre>} and {@code <code>} tags in the DOM with
+ * {@code class=prettyprint} and prettify them.
+ *
+ * @param {Function} opt_whenDone called when prettifying is done.
+ * @param {HTMLElement|HTMLDocument} opt_root an element or document
+ * containing all the elements to pretty print.
+ * Defaults to {@code document.body}.
+ */
+ function $prettyPrint(opt_whenDone, opt_root) {
+ var root = opt_root || document.body;
+ var doc = root.ownerDocument || document;
+ function byTagName(tn) { return root.getElementsByTagName(tn); }
+ // fetch a list of nodes to rewrite
+ var codeSegments = [byTagName('pre'), byTagName('code'), byTagName('xmp')];
+ var elements = [];
+ for (var i = 0; i < codeSegments.length; ++i) {
+ for (var j = 0, n = codeSegments[i].length; j < n; ++j) {
+ elements.push(codeSegments[i][j]);
+ }
+ }
+ codeSegments = null;
+
+ var clock = Date;
+ if (!clock['now']) {
+ clock = { 'now': function () { return +(new Date); } };
+ }
+
+ // The loop is broken into a series of continuations to make sure that we
+ // don't make the browser unresponsive when rewriting a large page.
+ var k = 0;
+
+ var langExtensionRe = /\blang(?:uage)?-([\w.]+)(?!\S)/;
+ var prettyPrintRe = /\bprettyprint\b/;
+ var prettyPrintedRe = /\bprettyprinted\b/;
+ var preformattedTagNameRe = /pre|xmp/i;
+ var codeRe = /^code$/i;
+ var preCodeXmpRe = /^(?:pre|code|xmp)$/i;
+ var EMPTY = {};
+
+ function doWork() {
+ var endTime = (win['PR_SHOULD_USE_CONTINUATION'] ?
+ clock['now']() + 250 /* ms */ :
+ Infinity);
+ for (; k < elements.length && clock['now']() < endTime; k++) {
+ var cs = elements[k];
+
+ // Look for a preceding comment like
+ // <?prettify lang="..." linenums="..."?>
+ var attrs = EMPTY;
+ {
+ for (var preceder = cs; (preceder = preceder.previousSibling);) {
+ var nt = preceder.nodeType;
+ // <?foo?> is parsed by HTML 5 to a comment node (8)
+ // like <!--?foo?-->, but in XML is a processing instruction
+ var value = (nt === 7 || nt === 8) && preceder.nodeValue;
+ if (value
+ ? !/^\??prettify\b/.test(value)
+ : (nt !== 3 || /\S/.test(preceder.nodeValue))) {
+ // Skip over white-space text nodes but not others.
+ break;
+ }
+ if (value) {
+ attrs = {};
+ value.replace(
+ /\b(\w+)=([\w:.%+-]+)/g,
+ function (_, name, value) { attrs[name] = value; });
+ break;
+ }
+ }
+ }
+
+ var className = cs.className;
+ if ((attrs !== EMPTY || prettyPrintRe.test(className))
+ // Don't redo this if we've already done it.
+ // This allows recalling pretty print to just prettyprint elements
+ // that have been added to the page since last call.
+ && !prettyPrintedRe.test(className)) {
+
+ // make sure this is not nested in an already prettified element
+ var nested = false;
+ for (var p = cs.parentNode; p; p = p.parentNode) {
+ var tn = p.tagName;
+ if (preCodeXmpRe.test(tn)
+ && p.className && prettyPrintRe.test(p.className)) {
+ nested = true;
+ break;
+ }
+ }
+ if (!nested) {
+ // Mark done. If we fail to prettyprint for whatever reason,
+ // we shouldn't try again.
+ cs.className += ' prettyprinted';
+
+ // If the classes includes a language extensions, use it.
+ // Language extensions can be specified like
+ // <pre class="prettyprint lang-cpp">
+ // the language extension "cpp" is used to find a language handler
+ // as passed to PR.registerLangHandler.
+ // HTML5 recommends that a language be specified using "language-"
+ // as the prefix instead. Google Code Prettify supports both.
+ // http://dev.w3.org/html5/spec-author-view/the-code-element.html
+ var langExtension = attrs['lang'];
+ if (!langExtension) {
+ langExtension = className.match(langExtensionRe);
+ // Support <pre class="prettyprint"><code class="language-c">
+ var wrapper;
+ if (!langExtension && (wrapper = childContentWrapper(cs))
+ && codeRe.test(wrapper.tagName)) {
+ langExtension = wrapper.className.match(langExtensionRe);
+ }
+
+ if (langExtension) { langExtension = langExtension[1]; }
+ }
+
+ var preformatted;
+ if (preformattedTagNameRe.test(cs.tagName)) {
+ preformatted = 1;
+ } else {
+ var currentStyle = cs['currentStyle'];
+ var defaultView = doc.defaultView;
+ var whitespace = (
+ currentStyle
+ ? currentStyle['whiteSpace']
+ : (defaultView
+ && defaultView.getComputedStyle)
+ ? defaultView.getComputedStyle(cs, null)
+ .getPropertyValue('white-space')
+ : 0);
+ preformatted = whitespace
+ && 'pre' === whitespace.substring(0, 3);
+ }
+
+ // Look for a class like linenums or linenums:<n> where <n> is the
+ // 1-indexed number of the first line.
+ var lineNums = attrs['linenums'];
+ if (!(lineNums = lineNums === 'true' || +lineNums)) {
+ lineNums = className.match(/\blinenums\b(?::(\d+))?/);
+ lineNums =
+ lineNums
+ ? lineNums[1] && lineNums[1].length
+ ? +lineNums[1] : true
+ : false;
+ }
+ if (lineNums) { numberLines(cs, lineNums, preformatted); }
+
+ // do the pretty printing
+ var prettyPrintingJob = {
+ langExtension: langExtension,
+ sourceNode: cs,
+ numberLines: lineNums,
+ pre: preformatted,
+ sourceCode: null,
+ basePos: null,
+ spans: null,
+ decorations: null
+ };
+ applyDecorator(prettyPrintingJob);
+ }
+ }
+ }
+ if (k < elements.length) {
+ // finish up in a continuation
+ win.setTimeout(doWork, 250);
+ } else if ('function' === typeof opt_whenDone) {
+ opt_whenDone();
+ }
+ }
+
+ doWork();
+ }
+
+ /**
+ * Contains functions for creating and registering new language handlers.
+ * @type {Object}
+ */
+ var PR = win['PR'] = {
+ 'createSimpleLexer': createSimpleLexer,
+ 'registerLangHandler': registerLangHandler,
+ 'sourceDecorator': sourceDecorator,
+ 'PR_ATTRIB_NAME': PR_ATTRIB_NAME,
+ 'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE,
+ 'PR_COMMENT': PR_COMMENT,
+ 'PR_DECLARATION': PR_DECLARATION,
+ 'PR_KEYWORD': PR_KEYWORD,
+ 'PR_LITERAL': PR_LITERAL,
+ 'PR_NOCODE': PR_NOCODE,
+ 'PR_PLAIN': PR_PLAIN,
+ 'PR_PUNCTUATION': PR_PUNCTUATION,
+ 'PR_SOURCE': PR_SOURCE,
+ 'PR_STRING': PR_STRING,
+ 'PR_TAG': PR_TAG,
+ 'PR_TYPE': PR_TYPE,
+ 'prettyPrintOne':
+ IN_GLOBAL_SCOPE
+ ? (win['prettyPrintOne'] = $prettyPrintOne)
+ : (prettyPrintOne = $prettyPrintOne),
+ 'prettyPrint': prettyPrint =
+ IN_GLOBAL_SCOPE
+ ? (win['prettyPrint'] = $prettyPrint)
+ : (prettyPrint = $prettyPrint)
+ };
+
+ // Make PR available via the Asynchronous Module Definition (AMD) API.
+ // Per https://github.com/amdjs/amdjs-api/wiki/AMD:
+ // The Asynchronous Module Definition (AMD) API specifies a
+ // mechanism for defining modules such that the module and its
+ // dependencies can be asynchronously loaded.
+ // ...
+ // To allow a clear indicator that a global define function (as
+ // needed for script src browser loading) conforms to the AMD API,
+ // any global define function SHOULD have a property called "amd"
+ // whose value is an object. This helps avoid conflict with any
+ // other existing JavaScript code that could have defined a define()
+ // function that does not conform to the AMD API.
+ var define = win['define'];
+ if (typeof define === "function" && define['amd']) {
+ define("google-code-prettify", [], function () {
+ return PR;
+ });
+ }
+ })();
+ return prettyPrint;
+ })();
+
+ // If this script is deferred or async and the document is already
+ // loaded we need to wait for language handlers to load before performing
+ // any autorun.
+ function onLangsLoaded() {
+ if (autorun) {
+ contentLoaded(
+ function () {
+ var n = callbacks.length;
+ var callback = n ? function () {
+ for (var i = 0; i < n; ++i) {
+ (function (i) {
+ win.setTimeout(
+ function () {
+ win['exports'][callbacks[i]].apply(win, arguments);
+ }, 0);
+ })(i);
+ }
+ } : void 0;
+ prettyPrint(callback);
+ });
+ }
+ }
+ checkPendingLanguages();
+
+}());
\ No newline at end of file
diff --git a/static/js/selController.js b/static/js/selController.js
index 7f678a8..06c1abb 100644
--- a/static/js/selController.js
+++ b/static/js/selController.js
@@ -765,7 +765,7 @@
}
-angular.module('bmcApp').controller('selController', function($scope, Restangular) {
+angular.module('bmcApp').controller('selController', function($scope) {
var sdr_promise = Restangular.all('sdrentries').getList();
var sel_promise = Restangular.all('selentries').getList();
diff --git a/static/js/versionController.js b/static/js/versionController.js
index 082ccf8..b77f9b4 100644
--- a/static/js/versionController.js
+++ b/static/js/versionController.js
@@ -1,4 +1,4 @@
-angular.module('bmcApp').controller('versionController', function($scope, Restangular) {
+angular.module('bmcApp').controller('versionController', function($scope) {
var system_status = Restangular.one('systeminfo').get().then(function(system_status) {
$scope.system_status = system_status;