").append(m.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},m.expr.filters.animated=function(a){return m.grep(m.timers,function(b){return a===b.elem}).length};var cd=a.document.documentElement;function dd(a){return m.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}m.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=m.css(a,"position"),l=m(a),n={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=m.css(a,"top"),i=m.css(a,"left"),j=("absolute"===k||"fixed"===k)&&m.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),m.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(n.top=b.top-h.top+g),null!=b.left&&(n.left=b.left-h.left+e),"using"in b?b.using.call(a,n):l.css(n)}},m.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){m.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,m.contains(b,e)?(typeof e.getBoundingClientRect!==K&&(d=e.getBoundingClientRect()),c=dd(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===m.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),m.nodeName(a[0],"html")||(c=a.offset()),c.top+=m.css(a[0],"borderTopWidth",!0),c.left+=m.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-m.css(d,"marginTop",!0),left:b.left-c.left-m.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||cd;while(a&&!m.nodeName(a,"html")&&"static"===m.css(a,"position"))a=a.offsetParent;return a||cd})}}),m.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);m.fn[a]=function(d){return V(this,function(a,d,e){var f=dd(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?m(f).scrollLeft():e,c?e:m(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),m.each(["top","left"],function(a,b){m.cssHooks[b]=Lb(k.pixelPosition,function(a,c){return c?(c=Jb(a,b),Hb.test(c)?m(a).position()[b]+"px":c):void 0})}),m.each({Height:"height",Width:"width"},function(a,b){m.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){m.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return V(this,function(b,c,d){var e;return m.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?m.css(b,c,g):m.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),m.fn.size=function(){return this.length},m.fn.andSelf=m.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return m});var ed=a.jQuery,fd=a.$;return m.noConflict=function(b){return a.$===m&&(a.$=fd),b&&a.jQuery===m&&(a.jQuery=ed),m},typeof b===K&&(a.jQuery=a.$=m),m});
diff --git a/django_code/cloudmanager/templates/js/jquery.mixitup.js b/django_code/cloudmanager/templates/js/jquery.mixitup.js
new file mode 100644
index 0000000..d6b6f01
--- /dev/null
+++ b/django_code/cloudmanager/templates/js/jquery.mixitup.js
@@ -0,0 +1,2072 @@
+/**!
+ * MixItUp v2.1.7
+ *
+ * @copyright Copyright 2014 KunkaLabs Limited.
+ * @author KunkaLabs Limited.
+ * @link https://mixitup.kunkalabs.com
+ *
+ * @license Commercial use requires a commercial license.
+ * https://mixitup.kunkalabs.com/licenses/
+ *
+ * Non-commercial use permitted under terms of CC-BY-NC license.
+ * http://creativecommons.org/licenses/by-nc/3.0/
+ */
+
+(function($, undf){
+
+ /**
+ * MixItUp Constructor Function
+ * @constructor
+ * @extends jQuery
+ */
+
+ $.MixItUp = function(){
+ var self = this;
+
+ self._execAction('_constructor', 0);
+
+ $.extend(self, {
+
+ /* Public Properties
+ ---------------------------------------------------------------------- */
+
+ selectors: {
+ target: '.mix',
+ filter: '.filter',
+ sort: '.sort'
+ },
+
+ animation: {
+ enable: true,
+ effects: 'fade scale',
+ duration: 600,
+ easing: 'ease',
+ perspectiveDistance: '3000',
+ perspectiveOrigin: '50% 50%',
+ queue: true,
+ queueLimit: 1,
+ animateChangeLayout: false,
+ animateResizeContainer: true,
+ animateResizeTargets: false,
+ staggerSequence: false,
+ reverseOut: false
+ },
+
+ callbacks: {
+ onMixLoad: false,
+ onMixStart: false,
+ onMixBusy: false,
+ onMixEnd: false,
+ onMixFail: false,
+ _user: false
+ },
+
+ controls: {
+ enable: true,
+ live: false,
+ toggleFilterButtons: false,
+ toggleLogic: 'or',
+ activeClass: 'active'
+ },
+
+ layout: {
+ display: 'inline-block',
+ containerClass: '',
+ containerClassFail: 'fail'
+ },
+
+ load: {
+ filter: 'all',
+ sort: false
+ },
+
+ /* Private Properties
+ ---------------------------------------------------------------------- */
+
+ _$body: null,
+ _$container: null,
+ _$targets: null,
+ _$parent: null,
+ _$sortButtons: null,
+ _$filterButtons: null,
+
+ _suckMode: false,
+ _mixing: false,
+ _sorting: false,
+ _clicking: false,
+ _loading: true,
+ _changingLayout: false,
+ _changingClass: false,
+ _changingDisplay: false,
+
+ _origOrder: [],
+ _startOrder: [],
+ _newOrder: [],
+ _activeFilter: null,
+ _toggleArray: [],
+ _toggleString: '',
+ _activeSort: 'default:asc',
+ _newSort: null,
+ _startHeight: null,
+ _newHeight: null,
+ _incPadding: true,
+ _newDisplay: null,
+ _newClass: null,
+ _targetsBound: 0,
+ _targetsDone: 0,
+ _queue: [],
+
+ _$show: $(),
+ _$hide: $()
+ });
+
+ self._execAction('_constructor', 1);
+ };
+
+ /**
+ * MixItUp Prototype
+ * @override
+ */
+
+ $.MixItUp.prototype = {
+ constructor: $.MixItUp,
+
+ /* Static Properties
+ ---------------------------------------------------------------------- */
+
+ _instances: {},
+ _handled: {
+ _filter: {},
+ _sort: {}
+ },
+ _bound: {
+ _filter: {},
+ _sort: {}
+ },
+ _actions: {},
+ _filters: {},
+
+ /* Static Methods
+ ---------------------------------------------------------------------- */
+
+ /**
+ * Extend
+ * @since 2.1.0
+ * @param {object} new properties/methods
+ * @extends {object} prototype
+ */
+
+ extend: function(extension){
+ for(var key in extension){
+ $.MixItUp.prototype[key] = extension[key];
+ }
+ },
+
+ /**
+ * Add Action
+ * @since 2.1.0
+ * @param {string} hook name
+ * @param {string} namespace
+ * @param {function} function to execute
+ * @param {number} priority
+ * @extends {object} $.MixItUp.prototype._actions
+ */
+
+ addAction: function(hook, name, func, priority){
+ $.MixItUp.prototype._addHook('_actions', hook, name, func, priority);
+ },
+
+ /**
+ * Add Filter
+ * @since 2.1.0
+ * @param {string} hook name
+ * @param {string} namespace
+ * @param {function} function to execute
+ * @param {number} priority
+ * @extends {object} $.MixItUp.prototype._filters
+ */
+
+ addFilter: function(hook, name, func, priority){
+ $.MixItUp.prototype._addHook('_filters', hook, name, func, priority);
+ },
+
+ /**
+ * Add Hook
+ * @since 2.1.0
+ * @param {string} type of hook
+ * @param {string} hook name
+ * @param {function} function to execute
+ * @param {number} priority
+ * @extends {object} $.MixItUp.prototype._filters
+ */
+
+ _addHook: function(type, hook, name, func, priority){
+ var collection = $.MixItUp.prototype[type],
+ obj = {};
+
+ priority = (priority === 1 || priority === 'post') ? 'post' : 'pre';
+
+ obj[hook] = {};
+ obj[hook][priority] = {};
+ obj[hook][priority][name] = func;
+
+ $.extend(true, collection, obj);
+ },
+
+
+ /* Private Methods
+ ---------------------------------------------------------------------- */
+
+ /**
+ * Initialise
+ * @since 2.0.0
+ * @param {object} domNode
+ * @param {object} config
+ */
+
+ _init: function(domNode, config){
+ var self = this;
+
+ self._execAction('_init', 0, arguments);
+
+ config && $.extend(true, self, config);
+
+ self._$body = $('body');
+ self._domNode = domNode;
+ self._$container = $(domNode);
+ self._$container.addClass(self.layout.containerClass);
+ self._id = domNode.id;
+
+ self._platformDetect();
+
+ self._brake = self._getPrefixedCSS('transition', 'none');
+
+ self._refresh(true);
+
+ self._$parent = self._$targets.parent().length ? self._$targets.parent() : self._$container;
+
+ if(self.load.sort){
+ self._newSort = self._parseSort(self.load.sort);
+ self._newSortString = self.load.sort;
+ self._activeSort = self.load.sort;
+ self._sort();
+ self._printSort();
+ }
+
+ self._activeFilter = self.load.filter === 'all' ?
+ self.selectors.target :
+ self.load.filter === 'none' ?
+ '' :
+ self.load.filter;
+
+ self.controls.enable && self._bindHandlers();
+
+ if(self.controls.toggleFilterButtons){
+ self._buildToggleArray();
+
+ for(var i = 0; i < self._toggleArray.length; i++){
+ self._updateControls({filter: self._toggleArray[i], sort: self._activeSort}, true);
+ };
+ } else if(self.controls.enable){
+ self._updateControls({filter: self._activeFilter, sort: self._activeSort});
+ }
+
+ self._filter();
+
+ self._init = true;
+
+ self._$container.data('mixItUp',self);
+
+ self._execAction('_init', 1, arguments);
+
+ self._buildState();
+
+ self._$targets.css(self._brake);
+
+ self._goMix(self.animation.enable);
+ },
+
+ /**
+ * Platform Detect
+ * @since 2.0.0
+ */
+
+ _platformDetect: function(){
+ var self = this,
+ vendorsTrans = ['Webkit', 'Moz', 'O', 'ms'],
+ vendorsRAF = ['webkit', 'moz'],
+ chrome = window.navigator.appVersion.match(/Chrome\/(\d+)\./) || false,
+ ff = typeof InstallTrigger !== 'undefined',
+ prefix = function(el){
+ for (var i = 0; i < vendorsTrans.length; i++){
+ if (vendorsTrans[i] + 'Transition' in el.style){
+ return {
+ prefix: '-'+vendorsTrans[i].toLowerCase()+'-',
+ vendor: vendorsTrans[i]
+ };
+ };
+ };
+ return 'transition' in el.style ? '' : false;
+ },
+ transPrefix = prefix(self._domNode);
+
+ self._execAction('_platformDetect', 0);
+
+ self._chrome = chrome ? parseInt(chrome[1], 10) : false;
+ self._ff = ff ? parseInt(window.navigator.userAgent.match(/rv:([^)]+)\)/)[1]) : false;
+ self._prefix = transPrefix.prefix;
+ self._vendor = transPrefix.vendor;
+ self._suckMode = window.atob && self._prefix ? false : true;
+
+ self._suckMode && (self.animation.enable = false);
+ (self._ff && self._ff <= 4) && (self.animation.enable = false);
+
+ /* Polyfills
+ ---------------------------------------------------------------------- */
+
+ /**
+ * window.requestAnimationFrame
+ */
+
+ for(var x = 0; x < vendorsRAF.length && !window.requestAnimationFrame; x++){
+ window.requestAnimationFrame = window[vendorsRAF[x]+'RequestAnimationFrame'];
+ }
+
+ /**
+ * Object.getPrototypeOf
+ */
+
+ if(typeof Object.getPrototypeOf !== 'function'){
+ if(typeof 'test'.__proto__ === 'object'){
+ Object.getPrototypeOf = function(object){
+ return object.__proto__;
+ };
+ } else {
+ Object.getPrototypeOf = function(object){
+ return object.constructor.prototype;
+ };
+ }
+ }
+
+ /**
+ * Element.nextElementSibling
+ */
+
+ if(self._domNode.nextElementSibling === undf){
+ Object.defineProperty(Element.prototype, 'nextElementSibling',{
+ get: function(){
+ var el = this.nextSibling;
+
+ while(el){
+ if(el.nodeType ===1){
+ return el;
+ }
+ el = el.nextSibling;
+ }
+ return null;
+ }
+ });
+ }
+
+ self._execAction('_platformDetect', 1);
+ },
+
+ /**
+ * Refresh
+ * @since 2.0.0
+ * @param {boolean} init
+ * @param {boolean} force
+ */
+
+ _refresh: function(init, force){
+ var self = this;
+
+ self._execAction('_refresh', 0, arguments);
+
+ self._$targets = self._$container.find(self.selectors.target);
+
+ for(var i = 0; i < self._$targets.length; i++){
+ var target = self._$targets[i];
+
+ if(target.dataset === undf || force){
+
+ target.dataset = {};
+
+ for(var j = 0; j < target.attributes.length; j++){
+
+ var attr = target.attributes[j],
+ name = attr.name,
+ val = attr.value;
+
+ if(name.indexOf('data-') > -1){
+ var dataName = self._helpers._camelCase(name.substring(5,name.length));
+ target.dataset[dataName] = val;
+ }
+ }
+ }
+
+ if(target.mixParent === undf){
+ target.mixParent = self._id;
+ }
+ }
+
+ if(
+ (self._$targets.length && init) ||
+ (!self._origOrder.length && self._$targets.length)
+ ){
+ self._origOrder = [];
+
+ for(var i = 0; i < self._$targets.length; i++){
+ var target = self._$targets[i];
+
+ self._origOrder.push(target);
+ }
+ }
+
+ self._execAction('_refresh', 1, arguments);
+ },
+
+ /**
+ * Bind Handlers
+ * @since 2.0.0
+ */
+
+ _bindHandlers: function(){
+ var self = this,
+ filters = $.MixItUp.prototype._bound._filter,
+ sorts = $.MixItUp.prototype._bound._sort;
+
+ self._execAction('_bindHandlers', 0);
+
+ if(self.controls.live){
+ self._$body
+ .on('click.mixItUp.'+self._id, self.selectors.sort, function(){
+ self._processClick($(this), 'sort');
+ })
+ .on('click.mixItUp.'+self._id, self.selectors.filter, function(){
+ self._processClick($(this), 'filter');
+ });
+ } else {
+ self._$sortButtons = $(self.selectors.sort);
+ self._$filterButtons = $(self.selectors.filter);
+
+ self._$sortButtons.on('click.mixItUp.'+self._id, function(){
+ self._processClick($(this), 'sort');
+ });
+
+ self._$filterButtons.on('click.mixItUp.'+self._id, function(){
+ self._processClick($(this), 'filter');
+ });
+ }
+
+ filters[self.selectors.filter] = (filters[self.selectors.filter] === undf) ? 1 : filters[self.selectors.filter] + 1;
+ sorts[self.selectors.sort] = (sorts[self.selectors.sort] === undf) ? 1 : sorts[self.selectors.sort] + 1;
+
+ self._execAction('_bindHandlers', 1);
+ },
+
+ /**
+ * Process Click
+ * @since 2.0.0
+ * @param {object} $button
+ * @param {string} type
+ */
+
+ _processClick: function($button, type){
+ var self = this,
+ trackClick = function($button, type, off){
+ var proto = $.MixItUp.prototype;
+
+ proto._handled['_'+type][self.selectors[type]] = (proto._handled['_'+type][self.selectors[type]] === undf) ?
+ 1 :
+ proto._handled['_'+type][self.selectors[type]] + 1;
+
+ if(proto._handled['_'+type][self.selectors[type]] === proto._bound['_'+type][self.selectors[type]]){
+ $button[(off ? 'remove' : 'add')+'Class'](self.controls.activeClass);
+ delete proto._handled['_'+type][self.selectors[type]];
+ }
+ };
+
+ self._execAction('_processClick', 0, arguments);
+
+ if(!self._mixing || (self.animation.queue && self._queue.length < self.animation.queueLimit)){
+ self._clicking = true;
+
+ if(type === 'sort'){
+ var sort = $button.attr('data-sort');
+
+ if(!$button.hasClass(self.controls.activeClass) || sort.indexOf('random') > -1){
+ $(self.selectors.sort).removeClass(self.controls.activeClass);
+ trackClick($button, type);
+ self.sort(sort);
+ }
+ }
+
+ if(type === 'filter') {
+ var filter = $button.attr('data-filter'),
+ ndx,
+ seperator = self.controls.toggleLogic === 'or' ? ',' : '';
+
+ if(!self.controls.toggleFilterButtons){
+ if(!$button.hasClass(self.controls.activeClass)){
+ $(self.selectors.filter).removeClass(self.controls.activeClass);
+ trackClick($button, type);
+ self.filter(filter);
+ }
+ } else {
+ self._buildToggleArray();
+
+ if(!$button.hasClass(self.controls.activeClass)){
+ trackClick($button, type);
+
+ self._toggleArray.push(filter);
+ } else {
+ trackClick($button, type, true);
+ ndx = self._toggleArray.indexOf(filter);
+ self._toggleArray.splice(ndx, 1);
+ }
+
+ self._toggleArray = $.grep(self._toggleArray,function(n){return(n);});
+
+ self._toggleString = self._toggleArray.join(seperator);
+
+ self.filter(self._toggleString);
+ }
+ }
+
+ self._execAction('_processClick', 1, arguments);
+ } else {
+ if(typeof self.callbacks.onMixBusy === 'function'){
+ self.callbacks.onMixBusy.call(self._domNode, self._state, self);
+ }
+ self._execAction('_processClickBusy', 1, arguments);
+ }
+ },
+
+ /**
+ * Build Toggle Array
+ * @since 2.0.0
+ */
+
+ _buildToggleArray: function(){
+ var self = this,
+ activeFilter = self._activeFilter.replace(/\s/g, '');
+
+ self._execAction('_buildToggleArray', 0, arguments);
+
+ if(self.controls.toggleLogic === 'or'){
+ self._toggleArray = activeFilter.split(',');
+ } else {
+ self._toggleArray = activeFilter.split('.');
+
+ !self._toggleArray[0] && self._toggleArray.shift();
+
+ for(var i = 0, filter; filter = self._toggleArray[i]; i++){
+ self._toggleArray[i] = '.'+filter;
+ }
+ }
+
+ self._execAction('_buildToggleArray', 1, arguments);
+ },
+
+ /**
+ * Update Controls
+ * @since 2.0.0
+ * @param {object} command
+ * @param {boolean} multi
+ */
+
+ _updateControls: function(command, multi){
+ var self = this,
+ output = {
+ filter: command.filter,
+ sort: command.sort
+ },
+ update = function($el, filter){
+ (multi && type === 'filter' && !(output.filter === 'none' || output.filter === '')) ?
+ $el.filter(filter).addClass(self.controls.activeClass) :
+ $el.removeClass(self.controls.activeClass).filter(filter).addClass(self.controls.activeClass);
+ },
+ type = 'filter',
+ $el = null;
+
+ self._execAction('_updateControls', 0, arguments);
+
+ (command.filter === undf) && (output.filter = self._activeFilter);
+ (command.sort === undf) && (output.sort = self._activeSort);
+ (output.filter === self.selectors.target) && (output.filter = 'all');
+
+ for(var i = 0; i < 2; i++){
+ $el = self.controls.live ? $(self.selectors[type]) : self['_$'+type+'Buttons'];
+ $el && update($el, '[data-'+type+'="'+output[type]+'"]');
+ type = 'sort';
+ }
+
+ self._execAction('_updateControls', 1, arguments);
+ },
+
+ /**
+ * Filter (private)
+ * @since 2.0.0
+ */
+
+ _filter: function(){
+ var self = this;
+
+ self._execAction('_filter', 0);
+
+ for(var i = 0; i < self._$targets.length; i++){
+ var $target = $(self._$targets[i]);
+
+ if($target.is(self._activeFilter)){
+ self._$show = self._$show.add($target);
+ } else {
+ self._$hide = self._$hide.add($target);
+ }
+ }
+
+ self._execAction('_filter', 1);
+ },
+
+ /**
+ * Sort (private)
+ * @since 2.0.0
+ */
+
+ _sort: function(){
+ var self = this,
+ arrayShuffle = function(oldArray){
+ var newArray = oldArray.slice(),
+ len = newArray.length,
+ i = len;
+
+ while(i--){
+ var p = parseInt(Math.random()*len);
+ var t = newArray[i];
+ newArray[i] = newArray[p];
+ newArray[p] = t;
+ };
+ return newArray;
+ };
+
+ self._execAction('_sort', 0);
+
+ self._startOrder = [];
+
+ for(var i = 0; i < self._$targets.length; i++){
+ var target = self._$targets[i];
+
+ self._startOrder.push(target);
+ }
+
+ switch(self._newSort[0].sortBy){
+ case 'default':
+ self._newOrder = self._origOrder;
+ break;
+ case 'random':
+ self._newOrder = arrayShuffle(self._startOrder);
+ break;
+ case 'custom':
+ self._newOrder = self._newSort[0].order;
+ break;
+ default:
+ self._newOrder = self._startOrder.concat().sort(function(a, b){
+ return self._compare(a, b);
+ });
+ }
+
+ self._execAction('_sort', 1);
+ },
+
+ /**
+ * Compare Algorithm
+ * @since 2.0.0
+ * @param {string|number} a
+ * @param {string|number} b
+ * @param {number} depth (recursion)
+ * @return {number}
+ */
+
+ _compare: function(a, b, depth){
+ depth = depth ? depth : 0;
+
+ var self = this,
+ order = self._newSort[depth].order,
+ getData = function(el){
+ return el.dataset[self._newSort[depth].sortBy] || 0;
+ },
+ attrA = isNaN(getData(a) * 1) ? getData(a).toLowerCase() : getData(a) * 1,
+ attrB = isNaN(getData(b) * 1) ? getData(b).toLowerCase() : getData(b) * 1;
+
+ if(attrA < attrB)
+ return order === 'asc' ? -1 : 1;
+ if(attrA > attrB)
+ return order === 'asc' ? 1 : -1;
+ if(attrA === attrB && self._newSort.length > depth+1)
+ return self._compare(a, b, depth+1);
+
+ return 0;
+ },
+
+ /**
+ * Print Sort
+ * @since 2.0.0
+ * @param {boolean} reset
+ */
+
+ _printSort: function(reset){
+ var self = this,
+ order = reset ? self._startOrder : self._newOrder,
+ targets = self._$parent[0].querySelectorAll(self.selectors.target),
+ nextSibling = targets.length ? targets[targets.length -1].nextElementSibling : null,
+ frag = document.createDocumentFragment();
+
+ self._execAction('_printSort', 0, arguments);
+
+ for(var i = 0; i < targets.length; i++){
+ var target = targets[i],
+ whiteSpace = target.nextSibling;
+
+ if(target.style.position === 'absolute') continue;
+
+ if(whiteSpace && whiteSpace.nodeName === '#text'){
+ self._$parent[0].removeChild(whiteSpace);
+ }
+
+ self._$parent[0].removeChild(target);
+ }
+
+ for(var i = 0; i < order.length; i++){
+ var el = order[i];
+
+ if(self._newSort[0].sortBy === 'default' && self._newSort[0].order === 'desc' && !reset){
+ var firstChild = frag.firstChild;
+ frag.insertBefore(el, firstChild);
+ frag.insertBefore(document.createTextNode(' '), el);
+ } else {
+ frag.appendChild(el);
+ frag.appendChild(document.createTextNode(' '));
+ }
+ }
+
+ nextSibling ?
+ self._$parent[0].insertBefore(frag, nextSibling) :
+ self._$parent[0].appendChild(frag);
+
+ self._execAction('_printSort', 1, arguments);
+ },
+
+ /**
+ * Parse Sort
+ * @since 2.0.0
+ * @param {string} sortString
+ * @return {array} newSort
+ */
+
+ _parseSort: function(sortString){
+ var self = this,
+ rules = typeof sortString === 'string' ? sortString.split(' ') : [sortString],
+ newSort = [];
+
+ for(var i = 0; i < rules.length; i++){
+ var rule = typeof sortString === 'string' ? rules[i].split(':') : ['custom', rules[i]],
+ ruleObj = {
+ sortBy: self._helpers._camelCase(rule[0]),
+ order: rule[1] || 'asc'
+ };
+
+ newSort.push(ruleObj);
+
+ if(ruleObj.sortBy === 'default' || ruleObj.sortBy === 'random') break;
+ }
+
+ return self._execFilter('_parseSort', newSort, arguments);
+ },
+
+ /**
+ * Parse Effects
+ * @since 2.0.0
+ * @return {object} effects
+ */
+
+ _parseEffects: function(){
+ var self = this,
+ effects = {
+ opacity: '',
+ transformIn: '',
+ transformOut: '',
+ filter: ''
+ },
+ parse = function(effect, extract, reverse){
+ if(self.animation.effects.indexOf(effect) > -1){
+ if(extract){
+ var propIndex = self.animation.effects.indexOf(effect+'(');
+ if(propIndex > -1){
+ var str = self.animation.effects.substring(propIndex),
+ match = /\(([^)]+)\)/.exec(str),
+ val = match[1];
+
+ return {val: val};
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+ },
+ negate = function(value, invert){
+ if(invert){
+ return value.charAt(0) === '-' ? value.substr(1, value.length) : '-'+value;
+ } else {
+ return value;
+ }
+ },
+ buildTransform = function(key, invert){
+ var transforms = [
+ ['scale', '.01'],
+ ['translateX', '20px'],
+ ['translateY', '20px'],
+ ['translateZ', '20px'],
+ ['rotateX', '90deg'],
+ ['rotateY', '90deg'],
+ ['rotateZ', '180deg'],
+ ];
+
+ for(var i = 0; i < transforms.length; i++){
+ var prop = transforms[i][0],
+ def = transforms[i][1],
+ inverted = invert && prop !== 'scale';
+
+ effects[key] += parse(prop) ? prop+'('+negate(parse(prop, true).val || def, inverted)+') ' : '';
+ }
+ };
+
+ effects.opacity = parse('fade') ? parse('fade',true).val || '0' : '1';
+
+ buildTransform('transformIn');
+
+ self.animation.reverseOut ? buildTransform('transformOut', true) : (effects.transformOut = effects.transformIn);
+
+ effects.transition = {};
+
+ effects.transition = self._getPrefixedCSS('transition','all '+self.animation.duration+'ms '+self.animation.easing+', opacity '+self.animation.duration+'ms linear');
+
+ self.animation.stagger = parse('stagger') ? true : false;
+ self.animation.staggerDuration = parseInt(parse('stagger') ? (parse('stagger',true).val ? parse('stagger',true).val : 100) : 100);
+
+ return self._execFilter('_parseEffects', effects);
+ },
+
+ /**
+ * Build State
+ * @since 2.0.0
+ * @param {boolean} future
+ * @return {object} futureState
+ */
+
+ _buildState: function(future){
+ var self = this,
+ state = {};
+
+ self._execAction('_buildState', 0);
+
+ state = {
+ activeFilter: self._activeFilter === '' ? 'none' : self._activeFilter,
+ activeSort: future && self._newSortString ? self._newSortString : self._activeSort,
+ fail: !self._$show.length && self._activeFilter !== '',
+ $targets: self._$targets,
+ $show: self._$show,
+ $hide: self._$hide,
+ totalTargets: self._$targets.length,
+ totalShow: self._$show.length,
+ totalHide: self._$hide.length,
+ display: future && self._newDisplay ? self._newDisplay : self.layout.display
+ };
+
+ if(future){
+ return self._execFilter('_buildState', state);
+ } else {
+ self._state = state;
+
+ self._execAction('_buildState', 1);
+ }
+ },
+
+ /**
+ * Go Mix
+ * @since 2.0.0
+ * @param {boolean} animate
+ */
+
+ _goMix: function(animate){
+ var self = this,
+ phase1 = function(){
+ if(self._chrome && (self._chrome === 31)){
+ chromeFix(self._$parent[0]);
+ }
+
+ self._setInter();
+
+ phase2();
+ },
+ phase2 = function(){
+ var scrollTop = window.pageYOffset,
+ scrollLeft = window.pageXOffset,
+ docHeight = document.documentElement.scrollHeight;
+
+ self._getInterMixData();
+
+ self._setFinal();
+
+ self._getFinalMixData();
+
+ (window.pageYOffset !== scrollTop) && window.scrollTo(scrollLeft, scrollTop);
+
+ self._prepTargets();
+
+ if(window.requestAnimationFrame){
+ requestAnimationFrame(phase3);
+ } else {
+ setTimeout(function(){
+ phase3();
+ },20);
+ }
+ },
+ phase3 = function(){
+ self._animateTargets();
+
+ if(self._targetsBound === 0){
+ self._cleanUp();
+ }
+ },
+ chromeFix = function(grid){
+ var parent = grid.parentElement,
+ placeholder = document.createElement('div'),
+ frag = document.createDocumentFragment();
+
+ parent.insertBefore(placeholder, grid);
+ frag.appendChild(grid);
+ parent.replaceChild(grid, placeholder);
+ },
+ futureState = self._buildState(true);
+
+ self._execAction('_goMix', 0, arguments);
+
+ !self.animation.duration && (animate = false);
+
+ self._mixing = true;
+
+ self._$container.removeClass(self.layout.containerClassFail);
+
+ if(typeof self.callbacks.onMixStart === 'function'){
+ self.callbacks.onMixStart.call(self._domNode, self._state, futureState, self);
+ }
+
+ self._$container.trigger('mixStart', [self._state, futureState, self]);
+
+ self._getOrigMixData();
+
+ if(animate && !self._suckMode){
+
+ window.requestAnimationFrame ?
+ requestAnimationFrame(phase1) :
+ phase1();
+
+ } else {
+ self._cleanUp();
+ }
+
+ self._execAction('_goMix', 1, arguments);
+ },
+
+ /**
+ * Get Target Data
+ * @since 2.0.0
+ */
+
+ _getTargetData: function(el, stage){
+ var self = this,
+ elStyle;
+
+ el.dataset[stage+'PosX'] = el.offsetLeft;
+ el.dataset[stage+'PosY'] = el.offsetTop;
+
+ if(self.animation.animateResizeTargets){
+ elStyle = window.getComputedStyle(el);
+
+ el.dataset[stage+'MarginBottom'] = parseInt(elStyle.marginBottom);
+ el.dataset[stage+'MarginRight'] = parseInt(elStyle.marginRight);
+ el.dataset[stage+'Width'] = el.offsetWidth;
+ el.dataset[stage+'Height'] = el.offsetHeight;
+ }
+ },
+
+ /**
+ * Get Original Mix Data
+ * @since 2.0.0
+ */
+
+ _getOrigMixData: function(){
+ var self = this,
+ parentStyle = !self._suckMode ? window.getComputedStyle(self._$parent[0]) : {boxSizing: ''},
+ parentBS = parentStyle.boxSizing || parentStyle[self._vendor+'BoxSizing'];
+
+ self._incPadding = (parentBS === 'border-box');
+
+ self._execAction('_getOrigMixData', 0);
+
+ !self._suckMode && (self.effects = self._parseEffects());
+
+ self._$toHide = self._$hide.filter(':visible');
+ self._$toShow = self._$show.filter(':hidden');
+ self._$pre = self._$targets.filter(':visible');
+
+ self._startHeight = self._incPadding ?
+ self._$parent.outerHeight() :
+ self._$parent.height();
+
+ for(var i = 0; i < self._$pre.length; i++){
+ var el = self._$pre[i];
+
+ self._getTargetData(el, 'orig');
+ }
+
+ self._execAction('_getOrigMixData', 1);
+ },
+
+ /**
+ * Set Intermediate Positions
+ * @since 2.0.0
+ */
+
+ _setInter: function(){
+ var self = this;
+
+ self._execAction('_setInter', 0);
+
+ if(self._changingLayout && self.animation.animateChangeLayout){
+ self._$toShow.css('display',self._newDisplay);
+
+ if(self._changingClass){
+ self._$container
+ .removeClass(self.layout.containerClass)
+ .addClass(self._newClass);
+ }
+ } else {
+ self._$toShow.css('display', self.layout.display);
+ }
+
+ self._execAction('_setInter', 1);
+ },
+
+ /**
+ * Get Intermediate Mix Data
+ * @since 2.0.0
+ */
+
+ _getInterMixData: function(){
+ var self = this;
+
+ self._execAction('_getInterMixData', 0);
+
+ for(var i = 0; i < self._$toShow.length; i++){
+ var el = self._$toShow[i];
+
+ self._getTargetData(el, 'inter');
+ }
+
+ for(var i = 0; i < self._$pre.length; i++){
+ var el = self._$pre[i];
+
+ self._getTargetData(el, 'inter');
+ }
+
+ self._execAction('_getInterMixData', 1);
+ },
+
+ /**
+ * Set Final Positions
+ * @since 2.0.0
+ */
+
+ _setFinal: function(){
+ var self = this;
+
+ self._execAction('_setFinal', 0);
+
+ self._sorting && self._printSort();
+
+ self._$toHide.removeStyle('display');
+
+ if(self._changingLayout && self.animation.animateChangeLayout){
+ self._$pre.css('display',self._newDisplay);
+ }
+
+ self._execAction('_setFinal', 1);
+ },
+
+ /**
+ * Get Final Mix Data
+ * @since 2.0.0
+ */
+
+ _getFinalMixData: function(){
+ var self = this;
+
+ self._execAction('_getFinalMixData', 0);
+
+ for(var i = 0; i < self._$toShow.length; i++){
+ var el = self._$toShow[i];
+
+ self._getTargetData(el, 'final');
+ }
+
+ for(var i = 0; i < self._$pre.length; i++){
+ var el = self._$pre[i];
+
+ self._getTargetData(el, 'final');
+ }
+
+ self._newHeight = self._incPadding ?
+ self._$parent.outerHeight() :
+ self._$parent.height();
+
+ self._sorting && self._printSort(true);
+
+ self._$toShow.removeStyle('display');
+
+ self._$pre.css('display',self.layout.display);
+
+ if(self._changingClass && self.animation.animateChangeLayout){
+ self._$container
+ .removeClass(self._newClass)
+ .addClass(self.layout.containerClass);
+ }
+
+ self._execAction('_getFinalMixData', 1);
+ },
+
+ /**
+ * Prepare Targets
+ * @since 2.0.0
+ */
+
+ _prepTargets: function(){
+ var self = this,
+ transformCSS = {
+ _in: self._getPrefixedCSS('transform', self.effects.transformIn),
+ _out: self._getPrefixedCSS('transform', self.effects.transformOut)
+ };
+
+ self._execAction('_prepTargets', 0);
+
+ if(self.animation.animateResizeContainer){
+ self._$parent.css('height',self._startHeight+'px');
+ }
+
+ for(var i = 0; i < self._$toShow.length; i++){
+ var el = self._$toShow[i],
+ $el = $(el);
+
+ el.style.opacity = self.effects.opacity;
+ el.style.display = (self._changingLayout && self.animation.animateChangeLayout) ?
+ self._newDisplay :
+ self.layout.display;
+
+ $el.css(transformCSS._in);
+
+ if(self.animation.animateResizeTargets){
+ el.style.width = el.dataset.finalWidth+'px';
+ el.style.height = el.dataset.finalHeight+'px';
+ el.style.marginRight = -(el.dataset.finalWidth - el.dataset.interWidth) + (el.dataset.finalMarginRight * 1)+'px';
+ el.style.marginBottom = -(el.dataset.finalHeight - el.dataset.interHeight) + (el.dataset.finalMarginBottom * 1)+'px';
+ }
+ }
+
+ for(var i = 0; i < self._$pre.length; i++){
+ var el = self._$pre[i],
+ $el = $(el),
+ translate = {
+ x: el.dataset.origPosX - el.dataset.interPosX,
+ y: el.dataset.origPosY - el.dataset.interPosY
+ },
+ transformCSS = self._getPrefixedCSS('transform','translate('+translate.x+'px,'+translate.y+'px)');
+
+ $el.css(transformCSS);
+
+ if(self.animation.animateResizeTargets){
+ el.style.width = el.dataset.origWidth+'px';
+ el.style.height = el.dataset.origHeight+'px';
+
+ if(el.dataset.origWidth - el.dataset.finalWidth){
+ el.style.marginRight = -(el.dataset.origWidth - el.dataset.interWidth) + (el.dataset.origMarginRight * 1)+'px';
+ }
+
+ if(el.dataset.origHeight - el.dataset.finalHeight){
+ el.style.marginBottom = -(el.dataset.origHeight - el.dataset.interHeight) + (el.dataset.origMarginBottom * 1) +'px';
+ }
+ }
+ }
+
+ self._execAction('_prepTargets', 1);
+ },
+
+ /**
+ * Animate Targets
+ * @since 2.0.0
+ */
+
+ _animateTargets: function(){
+ var self = this;
+
+ self._execAction('_animateTargets', 0);
+
+ self._targetsDone = 0;
+ self._targetsBound = 0;
+
+ self._$parent
+ .css(self._getPrefixedCSS('perspective', self.animation.perspectiveDistance+'px'))
+ .css(self._getPrefixedCSS('perspective-origin', self.animation.perspectiveOrigin));
+
+ if(self.animation.animateResizeContainer){
+ self._$parent
+ .css(self._getPrefixedCSS('transition','height '+self.animation.duration+'ms ease'))
+ .css('height',self._newHeight+'px');
+ }
+
+ for(var i = 0; i < self._$toShow.length; i++){
+ var el = self._$toShow[i],
+ $el = $(el),
+ translate = {
+ x: el.dataset.finalPosX - el.dataset.interPosX,
+ y: el.dataset.finalPosY - el.dataset.interPosY
+ },
+ delay = self._getDelay(i),
+ toShowCSS = {};
+
+ el.style.opacity = '';
+
+ for(var j = 0; j < 2; j++){
+ var a = j === 0 ? a = self._prefix : '';
+
+ if(self._ff && self._ff <= 20){
+ toShowCSS[a+'transition-property'] = 'all';
+ toShowCSS[a+'transition-timing-function'] = self.animation.easing+'ms';
+ toShowCSS[a+'transition-duration'] = self.animation.duration+'ms';
+ }
+
+ toShowCSS[a+'transition-delay'] = delay+'ms';
+ toShowCSS[a+'transform'] = 'translate('+translate.x+'px,'+translate.y+'px)';
+ }
+
+ if(self.effects.transform || self.effects.opacity){
+ self._bindTargetDone($el);
+ }
+
+ (self._ff && self._ff <= 20) ?
+ $el.css(toShowCSS) :
+ $el.css(self.effects.transition).css(toShowCSS);
+ }
+
+ for(var i = 0; i < self._$pre.length; i++){
+ var el = self._$pre[i],
+ $el = $(el),
+ translate = {
+ x: el.dataset.finalPosX - el.dataset.interPosX,
+ y: el.dataset.finalPosY - el.dataset.interPosY
+ },
+ delay = self._getDelay(i);
+
+ if(!(
+ el.dataset.finalPosX === el.dataset.origPosX &&
+ el.dataset.finalPosY === el.dataset.origPosY
+ )){
+ self._bindTargetDone($el);
+ }
+
+ $el.css(self._getPrefixedCSS('transition', 'all '+self.animation.duration+'ms '+self.animation.easing+' '+delay+'ms'));
+ $el.css(self._getPrefixedCSS('transform', 'translate('+translate.x+'px,'+translate.y+'px)'));
+
+ if(self.animation.animateResizeTargets){
+ if(el.dataset.origWidth - el.dataset.finalWidth && el.dataset.finalWidth * 1){
+ el.style.width = el.dataset.finalWidth+'px';
+ el.style.marginRight = -(el.dataset.finalWidth - el.dataset.interWidth)+(el.dataset.finalMarginRight * 1)+'px';
+ }
+
+ if(el.dataset.origHeight - el.dataset.finalHeight && el.dataset.finalHeight * 1){
+ el.style.height = el.dataset.finalHeight+'px';
+ el.style.marginBottom = -(el.dataset.finalHeight - el.dataset.interHeight)+(el.dataset.finalMarginBottom * 1) +'px';
+ }
+ }
+ }
+
+ if(self._changingClass){
+ self._$container
+ .removeClass(self.layout.containerClass)
+ .addClass(self._newClass);
+ }
+
+ for(var i = 0; i < self._$toHide.length; i++){
+ var el = self._$toHide[i],
+ $el = $(el),
+ delay = self._getDelay(i),
+ toHideCSS = {};
+
+ for(var j = 0; j<2; j++){
+ var a = j === 0 ? a = self._prefix : '';
+
+ toHideCSS[a+'transition-delay'] = delay+'ms';
+ toHideCSS[a+'transform'] = self.effects.transformOut;
+ toHideCSS.opacity = self.effects.opacity;
+ }
+
+ $el.css(self.effects.transition).css(toHideCSS);
+
+ if(self.effects.transform || self.effects.opacity){
+ self._bindTargetDone($el);
+ };
+ }
+
+ self._execAction('_animateTargets', 1);
+
+ },
+
+ /**
+ * Bind Targets TransitionEnd
+ * @since 2.0.0
+ * @param {object} $el
+ */
+
+ _bindTargetDone: function($el){
+ var self = this,
+ el = $el[0];
+
+ self._execAction('_bindTargetDone', 0, arguments);
+
+ if(!el.dataset.bound){
+
+ el.dataset.bound = true;
+ self._targetsBound++;
+
+ $el.on('webkitTransitionEnd.mixItUp transitionend.mixItUp',function(e){
+ if(
+ (e.originalEvent.propertyName.indexOf('transform') > -1 ||
+ e.originalEvent.propertyName.indexOf('opacity') > -1) &&
+ $(e.originalEvent.target).is(self.selectors.target)
+ ){
+ $el.off('.mixItUp');
+ delete el.dataset.bound;
+ self._targetDone();
+ }
+ });
+ }
+
+ self._execAction('_bindTargetDone', 1, arguments);
+ },
+
+ /**
+ * Target Done
+ * @since 2.0.0
+ */
+
+ _targetDone: function(){
+ var self = this;
+
+ self._execAction('_targetDone', 0);
+
+ self._targetsDone++;
+
+ (self._targetsDone === self._targetsBound) && self._cleanUp();
+
+ self._execAction('_targetDone', 1);
+ },
+
+ /**
+ * Clean Up
+ * @since 2.0.0
+ */
+
+ _cleanUp: function(){
+ var self = this,
+ targetStyles = self.animation.animateResizeTargets ? 'transform opacity width height margin-bottom margin-right' : 'transform opacity';
+ unBrake = function(){
+ self._$targets.removeStyle('transition', self._prefix);
+ };
+
+ self._execAction('_cleanUp', 0);
+
+ !self._changingLayout ?
+ self._$show.css('display',self.layout.display) :
+ self._$show.css('display',self._newDisplay);
+
+ self._$targets.css(self._brake);
+
+ self._$targets
+ .removeStyle(targetStyles, self._prefix)
+ .removeAttr('data-inter-pos-x data-inter-pos-y data-final-pos-x data-final-pos-y data-orig-pos-x data-orig-pos-y data-orig-height data-orig-width data-final-height data-final-width data-inter-width data-inter-height data-orig-margin-right data-orig-margin-bottom data-inter-margin-right data-inter-margin-bottom data-final-margin-right data-final-margin-bottom');
+
+ self._$hide.removeStyle('display');
+
+ self._$parent.removeStyle('height transition perspective-distance perspective perspective-origin-x perspective-origin-y perspective-origin perspectiveOrigin', self._prefix);
+
+ if(self._sorting){
+ self._printSort();
+ self._activeSort = self._newSortString;
+ self._sorting = false;
+ }
+
+ if(self._changingLayout){
+ if(self._changingDisplay){
+ self.layout.display = self._newDisplay;
+ self._changingDisplay = false;
+ }
+
+ if(self._changingClass){
+ self._$parent.removeClass(self.layout.containerClass).addClass(self._newClass);
+ self.layout.containerClass = self._newClass;
+ self._changingClass = false;
+ }
+
+ self._changingLayout = false;
+ }
+
+ self._refresh();
+
+ self._buildState();
+
+ if(self._state.fail){
+ self._$container.addClass(self.layout.containerClassFail);
+ }
+
+ self._$show = $();
+ self._$hide = $();
+
+ if(window.requestAnimationFrame){
+ requestAnimationFrame(unBrake);
+ }
+
+ self._mixing = false;
+
+ if(typeof self.callbacks._user === 'function'){
+ self.callbacks._user.call(self._domNode, self._state, self);
+ }
+
+ if(typeof self.callbacks.onMixEnd === 'function'){
+ self.callbacks.onMixEnd.call(self._domNode, self._state, self);
+ }
+
+ self._$container.trigger('mixEnd', [self._state, self]);
+
+ if(self._state.fail){
+ (typeof self.callbacks.onMixFail === 'function') && self.callbacks.onMixFail.call(self._domNode, self._state, self);
+ self._$container.trigger('mixFail', [self._state, self]);
+ }
+
+ if(self._loading){
+ (typeof self.callbacks.onMixLoad === 'function') && self.callbacks.onMixLoad.call(self._domNode, self._state, self);
+ self._$container.trigger('mixLoad', [self._state, self]);
+ }
+
+ if(self._queue.length){
+ self._execAction('_queue', 0);
+
+ self.multiMix(self._queue[0][0],self._queue[0][1],self._queue[0][2]);
+ self._queue.splice(0, 1);
+ }
+
+ self._execAction('_cleanUp', 1);
+
+ self._loading = false;
+ },
+
+ /**
+ * Get Prefixed CSS
+ * @since 2.0.0
+ * @param {string} property
+ * @param {string} value
+ * @param {boolean} prefixValue
+ * @return {object} styles
+ */
+
+ _getPrefixedCSS: function(property, value, prefixValue){
+ var self = this,
+ styles = {};
+
+ for(i = 0; i < 2; i++){
+ var prefix = i === 0 ? self._prefix : '';
+ prefixValue ? styles[prefix+property] = prefix+value : styles[prefix+property] = value;
+ }
+
+ return self._execFilter('_getPrefixedCSS', styles, arguments);
+ },
+
+ /**
+ * Get Delay
+ * @since 2.0.0
+ * @param {number} i
+ * @return {number} delay
+ */
+
+ _getDelay: function(i){
+ var self = this,
+ n = typeof self.animation.staggerSequence === 'function' ? self.animation.staggerSequence.call(self._domNode, i, self._state) : i,
+ delay = self.animation.stagger ? n * self.animation.staggerDuration : 0;
+
+ return self._execFilter('_getDelay', delay, arguments);
+ },
+
+ /**
+ * Parse MultiMix Arguments
+ * @since 2.0.0
+ * @param {array} args
+ * @return {object} output
+ */
+
+ _parseMultiMixArgs: function(args){
+ var self = this,
+ output = {
+ command: null,
+ animate: self.animation.enable,
+ callback: null
+ };
+
+ for(var i = 0; i < args.length; i++){
+ var arg = args[i];
+
+ if(arg !== null){
+ if(typeof arg === 'object' || typeof arg === 'string'){
+ output.command = arg;
+ } else if(typeof arg === 'boolean'){
+ output.animate = arg;
+ } else if(typeof arg === 'function'){
+ output.callback = arg;
+ }
+ }
+ }
+
+ return self._execFilter('_parseMultiMixArgs', output, arguments);
+ },
+
+ /**
+ * Parse Insert Arguments
+ * @since 2.0.0
+ * @param {array} args
+ * @return {object} output
+ */
+
+ _parseInsertArgs: function(args){
+ var self = this,
+ output = {
+ index: 0,
+ $object: $(),
+ multiMix: {filter: self._state.activeFilter},
+ callback: null
+ };
+
+ for(var i = 0; i < args.length; i++){
+ var arg = args[i];
+
+ if(typeof arg === 'number'){
+ output.index = arg;
+ } else if(typeof arg === 'object' && arg instanceof $){
+ output.$object = arg;
+ } else if(typeof arg === 'object' && self._helpers._isElement(arg)){
+ output.$object = $(arg);
+ } else if(typeof arg === 'object' && arg !== null){
+ output.multiMix = arg;
+ } else if(typeof arg === 'boolean' && !arg){
+ output.multiMix = false;
+ } else if(typeof arg === 'function'){
+ output.callback = arg;
+ }
+ }
+
+ return self._execFilter('_parseInsertArgs', output, arguments);
+ },
+
+ /**
+ * Execute Action
+ * @since 2.0.0
+ * @param {string} methodName
+ * @param {boolean} isPost
+ * @param {array} args
+ */
+
+ _execAction: function(methodName, isPost, args){
+ var self = this,
+ context = isPost ? 'post' : 'pre';
+
+ if(!self._actions.isEmptyObject && self._actions.hasOwnProperty(methodName)){
+ for(var key in self._actions[methodName][context]){
+ self._actions[methodName][context][key].call(self, args);
+ }
+ }
+ },
+
+ /**
+ * Execute Filter
+ * @since 2.0.0
+ * @param {string} methodName
+ * @param {mixed} value
+ * @return {mixed} value
+ */
+
+ _execFilter: function(methodName, value, args){
+ var self = this;
+
+ if(!self._filters.isEmptyObject && self._filters.hasOwnProperty(methodName)){
+ for(var key in self._filters[methodName]){
+ return self._filters[methodName][key].call(self, args);
+ }
+ } else {
+ return value;
+ }
+ },
+
+ /* Helpers
+ ---------------------------------------------------------------------- */
+
+ _helpers: {
+
+ /**
+ * CamelCase
+ * @since 2.0.0
+ * @param {string}
+ * @return {string}
+ */
+
+ _camelCase: function(string){
+ return string.replace(/-([a-z])/g, function(g){
+ return g[1].toUpperCase();
+ });
+ },
+
+ /**
+ * Is Element
+ * @since 2.1.3
+ * @param {object} element to test
+ * @return {boolean}
+ */
+
+ _isElement: function(el){
+ if(window.HTMLElement){
+ return el instanceof HTMLElement;
+ } else {
+ return (
+ el !== null &&
+ el.nodeType === 1 &&
+ el.nodeName === 'string'
+ );
+ }
+ }
+ },
+
+ /* Public Methods
+ ---------------------------------------------------------------------- */
+
+ /**
+ * Is Mixing
+ * @since 2.0.0
+ * @return {boolean}
+ */
+
+ isMixing: function(){
+ var self = this;
+
+ return self._execFilter('isMixing', self._mixing);
+ },
+
+ /**
+ * Filter (public)
+ * @since 2.0.0
+ * @param {array} arguments
+ */
+
+ filter: function(){
+ var self = this,
+ args = self._parseMultiMixArgs(arguments);
+
+ self._clicking && (self._toggleString = '');
+
+ self.multiMix({filter: args.command}, args.animate, args.callback);
+ },
+
+ /**
+ * Sort (public)
+ * @since 2.0.0
+ * @param {array} arguments
+ */
+
+ sort: function(){
+ var self = this,
+ args = self._parseMultiMixArgs(arguments);
+
+ self.multiMix({sort: args.command}, args.animate, args.callback);
+ },
+
+ /**
+ * Change Layout (public)
+ * @since 2.0.0
+ * @param {array} arguments
+ */
+
+ changeLayout: function(){
+ var self = this,
+ args = self._parseMultiMixArgs(arguments);
+
+ self.multiMix({changeLayout: args.command}, args.animate, args.callback);
+ },
+
+ /**
+ * MultiMix
+ * @since 2.0.0
+ * @param {array} arguments
+ */
+
+ multiMix: function(){
+ var self = this,
+ args = self._parseMultiMixArgs(arguments);
+
+ self._execAction('multiMix', 0, arguments);
+
+ if(!self._mixing){
+ if(self.controls.enable && !self._clicking){
+ self.controls.toggleFilterButtons && self._buildToggleArray();
+ self._updateControls(args.command, self.controls.toggleFilterButtons);
+ }
+
+ (self._queue.length < 2) && (self._clicking = false);
+
+ delete self.callbacks._user;
+ if(args.callback) self.callbacks._user = args.callback;
+
+ var sort = args.command.sort,
+ filter = args.command.filter,
+ changeLayout = args.command.changeLayout;
+
+ self._refresh();
+
+ if(sort){
+ self._newSort = self._parseSort(sort);
+ self._newSortString = sort;
+
+ self._sorting = true;
+ self._sort();
+ }
+
+ if(filter !== undf){
+ filter = (filter === 'all') ? self.selectors.target : filter;
+
+ self._activeFilter = filter;
+ }
+
+ self._filter();
+
+ if(changeLayout){
+ self._newDisplay = (typeof changeLayout === 'string') ? changeLayout : changeLayout.display || self.layout.display;
+ self._newClass = changeLayout.containerClass || '';
+
+ if(
+ self._newDisplay !== self.layout.display ||
+ self._newClass !== self.layout.containerClass
+ ){
+ self._changingLayout = true;
+
+ self._changingClass = (self._newClass !== self.layout.containerClass);
+ self._changingDisplay = (self._newDisplay !== self.layout.display);
+ }
+ }
+
+ self._$targets.css(self._brake);
+
+ self._goMix(args.animate ^ self.animation.enable ? args.animate : self.animation.enable);
+
+ self._execAction('multiMix', 1, arguments);
+
+ } else {
+ if(self.animation.queue && self._queue.length < self.animation.queueLimit){
+ self._queue.push(arguments);
+
+ (self.controls.enable && !self._clicking) && self._updateControls(args.command);
+
+ self._execAction('multiMixQueue', 1, arguments);
+
+ } else {
+ if(typeof self.callbacks.onMixBusy === 'function'){
+ self.callbacks.onMixBusy.call(self._domNode, self._state, self);
+ }
+ self._$container.trigger('mixBusy', [self._state, self]);
+
+ self._execAction('multiMixBusy', 1, arguments);
+ }
+ }
+ },
+
+ /**
+ * Insert
+ * @since 2.0.0
+ * @param {array} arguments
+ */
+
+ insert: function(){
+ var self = this,
+ args = self._parseInsertArgs(arguments),
+ callback = (typeof args.callback === 'function') ? args.callback : null,
+ frag = document.createDocumentFragment(),
+ target = (function(){
+ self._refresh();
+
+ if(self._$targets.length){
+ return (args.index < self._$targets.length || !self._$targets.length) ?
+ self._$targets[args.index] :
+ self._$targets[self._$targets.length-1].nextElementSibling;
+ } else {
+ return self._$parent[0].children[0];
+ }
+ })();
+
+ self._execAction('insert', 0, arguments);
+
+ if(args.$object){
+ for(var i = 0; i < args.$object.length; i++){
+ var el = args.$object[i];
+
+ frag.appendChild(el);
+ frag.appendChild(document.createTextNode(' '));
+ }
+
+ self._$parent[0].insertBefore(frag, target);
+ }
+
+ self._execAction('insert', 1, arguments);
+
+ if(typeof args.multiMix === 'object'){
+ self.multiMix(args.multiMix, callback);
+ }
+ },
+
+ /**
+ * Prepend
+ * @since 2.0.0
+ * @param {array} arguments
+ */
+
+ prepend: function(){
+ var self = this,
+ args = self._parseInsertArgs(arguments);
+
+ self.insert(0, args.$object, args.multiMix, args.callback);
+ },
+
+ /**
+ * Append
+ * @since 2.0.0
+ * @param {array} arguments
+ */
+
+ append: function(){
+ var self = this,
+ args = self._parseInsertArgs(arguments);
+
+ self.insert(self._state.totalTargets, args.$object, args.multiMix, args.callback);
+ },
+
+ /**
+ * Get Option
+ * @since 2.0.0
+ * @param {string} string
+ * @return {mixed} value
+ */
+
+ getOption: function(string){
+ var self = this,
+ getProperty = function(obj, prop){
+ var parts = prop.split('.'),
+ last = parts.pop(),
+ l = parts.length,
+ i = 1,
+ current = parts[0] || prop;
+
+ while((obj = obj[current]) && i < l){
+ current = parts[i];
+ i++;
+ }
+
+ if(obj !== undf){
+ return obj[last] !== undf ? obj[last] : obj;
+ }
+ };
+
+ return string ? self._execFilter('getOption', getProperty(self, string), arguments) : self;
+ },
+
+ /**
+ * Set Options
+ * @since 2.0.0
+ * @param {object} config
+ */
+
+ setOptions: function(config){
+ var self = this;
+
+ self._execAction('setOptions', 0, arguments);
+
+ typeof config === 'object' && $.extend(true, self, config);
+
+ self._execAction('setOptions', 1, arguments);
+ },
+
+ /**
+ * Get State
+ * @since 2.0.0
+ * @return {object} state
+ */
+
+ getState: function(){
+ var self = this;
+
+ return self._execFilter('getState', self._state, self);
+ },
+
+ /**
+ * Force Refresh
+ * @since 2.1.2
+ */
+
+ forceRefresh: function(){
+ var self = this;
+
+ self._refresh(false, true);
+ },
+
+ /**
+ * Destroy
+ * @since 2.0.0
+ * @param {boolean} hideAll
+ */
+
+ destroy: function(hideAll){
+ var self = this;
+
+ self._execAction('destroy', 0, arguments);
+
+ self._$body
+ .add($(self.selectors.sort))
+ .add($(self.selectors.filter))
+ .off('.mixItUp');
+
+ for(var i = 0; i < self._$targets.length; i++){
+ var target = self._$targets[i];
+
+ hideAll && (target.style.display = '');
+
+ delete target.mixParent;
+ }
+
+ self._execAction('destroy', 1, arguments);
+
+ delete $.MixItUp.prototype._instances[self._id];
+ }
+
+ };
+
+ /* jQuery Methods
+ ---------------------------------------------------------------------- */
+
+ /**
+ * jQuery .mixItUp() method
+ * @since 2.0.0
+ * @extends $.fn
+ */
+
+ $.fn.mixItUp = function(){
+ var args = arguments,
+ dataReturn = [],
+ eachReturn,
+ _instantiate = function(domNode, settings){
+ var instance = new $.MixItUp(),
+ rand = function(){
+ return ('00000'+(Math.random()*16777216<<0).toString(16)).substr(-6).toUpperCase();
+ };
+
+ instance._execAction('_instantiate', 0, arguments);
+
+ domNode.id = !domNode.id ? 'MixItUp'+rand() : domNode.id;
+
+ if(!instance._instances[domNode.id]){
+ instance._instances[domNode.id] = instance;
+ instance._init(domNode, settings);
+ }
+
+ instance._execAction('_instantiate', 1, arguments);
+ };
+
+ eachReturn = this.each(function(){
+ if(args && typeof args[0] === 'string'){
+ var instance = $.MixItUp.prototype._instances[this.id];
+ if(args[0] === 'isLoaded'){
+ dataReturn.push(instance ? true : false);
+ } else {
+ var data = instance[args[0]](args[1], args[2], args[3]);
+ if(data !== undf)dataReturn.push(data);
+ }
+ } else {
+ _instantiate(this, args[0]);
+ }
+ });
+
+ if(dataReturn.length){
+ return dataReturn.length > 1 ? dataReturn : dataReturn[0];
+ } else {
+ return eachReturn;
+ }
+ };
+
+ /**
+ * jQuery .removeStyle() method
+ * @since 2.0.0
+ * @extends $.fn
+ */
+
+ $.fn.removeStyle = function(style, prefix){
+ prefix = prefix ? prefix : '';
+
+ return this.each(function(){
+ var el = this,
+ styles = style.split(' ');
+
+ for(var i = 0; i < styles.length; i++){
+ for(var j = 0; j < 4; j++){
+ switch (j) {
+ case 0:
+ var prop = styles[i];
+ break;
+ case 1:
+ var prop = $.MixItUp.prototype._helpers._camelCase(prop);
+ break;
+ case 2:
+ var prop = prefix+styles[i];
+ break;
+ case 3:
+ var prop = $.MixItUp.prototype._helpers._camelCase(prefix+styles[i]);
+ }
+
+ if(
+ el.style[prop] !== undf &&
+ typeof el.style[prop] !== 'unknown' &&
+ el.style[prop].length > 0
+ ){
+ el.style[prop] = '';
+ }
+
+ if(!prefix && j === 1)break;
+ }
+ }
+
+ if(el.attributes && el.attributes.style && el.attributes.style !== undf && el.attributes.style.value === ''){
+ el.attributes.removeNamedItem('style');
+ }
+ });
+ };
+
+})(jQuery);
\ No newline at end of file
diff --git a/django_code/cloudmanager/templates/js/jquery.mixitup.min.js b/django_code/cloudmanager/templates/js/jquery.mixitup.min.js
new file mode 100644
index 0000000..0b17aa7
--- /dev/null
+++ b/django_code/cloudmanager/templates/js/jquery.mixitup.min.js
@@ -0,0 +1,14 @@
+/**!
+ * MixItUp v2.1.7
+ *
+ * @copyright Copyright 2014 KunkaLabs Limited.
+ * @author KunkaLabs Limited.
+ * @link https://mixitup.kunkalabs.com
+ *
+ * @license Commercial use requires a commercial license.
+ * https://mixitup.kunkalabs.com/licenses/
+ *
+ * Non-commercial use permitted under terms of CC-BY-NC license.
+ * http://creativecommons.org/licenses/by-nc/3.0/
+ */
+!function(a,b){a.MixItUp=function(){var b=this;b._execAction("_constructor",0),a.extend(b,{selectors:{target:".mix",filter:".filter",sort:".sort"},animation:{enable:!0,effects:"fade scale",duration:600,easing:"ease",perspectiveDistance:"3000",perspectiveOrigin:"50% 50%",queue:!0,queueLimit:1,animateChangeLayout:!1,animateResizeContainer:!0,animateResizeTargets:!1,staggerSequence:!1,reverseOut:!1},callbacks:{onMixLoad:!1,onMixStart:!1,onMixBusy:!1,onMixEnd:!1,onMixFail:!1,_user:!1},controls:{enable:!0,live:!1,toggleFilterButtons:!1,toggleLogic:"or",activeClass:"active"},layout:{display:"inline-block",containerClass:"",containerClassFail:"fail"},load:{filter:"all",sort:!1},_$body:null,_$container:null,_$targets:null,_$parent:null,_$sortButtons:null,_$filterButtons:null,_suckMode:!1,_mixing:!1,_sorting:!1,_clicking:!1,_loading:!0,_changingLayout:!1,_changingClass:!1,_changingDisplay:!1,_origOrder:[],_startOrder:[],_newOrder:[],_activeFilter:null,_toggleArray:[],_toggleString:"",_activeSort:"default:asc",_newSort:null,_startHeight:null,_newHeight:null,_incPadding:!0,_newDisplay:null,_newClass:null,_targetsBound:0,_targetsDone:0,_queue:[],_$show:a(),_$hide:a()}),b._execAction("_constructor",1)},a.MixItUp.prototype={constructor:a.MixItUp,_instances:{},_handled:{_filter:{},_sort:{}},_bound:{_filter:{},_sort:{}},_actions:{},_filters:{},extend:function(b){for(var c in b)a.MixItUp.prototype[c]=b[c]},addAction:function(b,c,d,e){a.MixItUp.prototype._addHook("_actions",b,c,d,e)},addFilter:function(b,c,d,e){a.MixItUp.prototype._addHook("_filters",b,c,d,e)},_addHook:function(b,c,d,e,f){var g=a.MixItUp.prototype[b],h={};f=1===f||"post"===f?"post":"pre",h[c]={},h[c][f]={},h[c][f][d]=e,a.extend(!0,g,h)},_init:function(b,c){var d=this;if(d._execAction("_init",0,arguments),c&&a.extend(!0,d,c),d._$body=a("body"),d._domNode=b,d._$container=a(b),d._$container.addClass(d.layout.containerClass),d._id=b.id,d._platformDetect(),d._brake=d._getPrefixedCSS("transition","none"),d._refresh(!0),d._$parent=d._$targets.parent().length?d._$targets.parent():d._$container,d.load.sort&&(d._newSort=d._parseSort(d.load.sort),d._newSortString=d.load.sort,d._activeSort=d.load.sort,d._sort(),d._printSort()),d._activeFilter="all"===d.load.filter?d.selectors.target:"none"===d.load.filter?"":d.load.filter,d.controls.enable&&d._bindHandlers(),d.controls.toggleFilterButtons){d._buildToggleArray();for(var e=0;e
-1){var k=d._helpers._camelCase(i.substring(5,i.length));f.dataset[k]=j}}}f.mixParent===b&&(f.mixParent=d._id)}if(d._$targets.length&&a||!d._origOrder.length&&d._$targets.length){d._origOrder=[];for(var e=0;e-1)&&(a(e.selectors.sort).removeClass(e.controls.activeClass),f(c,d),e.sort(g))}if("filter"===d){var h,i=c.attr("data-filter"),j="or"===e.controls.toggleLogic?",":"";e.controls.toggleFilterButtons?(e._buildToggleArray(),c.hasClass(e.controls.activeClass)?(f(c,d,!0),h=e._toggleArray.indexOf(i),e._toggleArray.splice(h,1)):(f(c,d),e._toggleArray.push(i)),e._toggleArray=a.grep(e._toggleArray,function(a){return a}),e._toggleString=e._toggleArray.join(j),e.filter(e._toggleString)):c.hasClass(e.controls.activeClass)||(a(e.selectors.filter).removeClass(e.controls.activeClass),f(c,d),e.filter(i))}e._execAction("_processClick",1,arguments)}else"function"==typeof e.callbacks.onMixBusy&&e.callbacks.onMixBusy.call(e._domNode,e._state,e),e._execAction("_processClickBusy",1,arguments)},_buildToggleArray:function(){var a=this,b=a._activeFilter.replace(/\s/g,"");if(a._execAction("_buildToggleArray",0,arguments),"or"===a.controls.toggleLogic)a._toggleArray=b.split(",");else{a._toggleArray=b.split("."),!a._toggleArray[0]&&a._toggleArray.shift();for(var c,d=0;c=a._toggleArray[d];d++)a._toggleArray[d]="."+c}a._execAction("_buildToggleArray",1,arguments)},_updateControls:function(c,d){var e=this,f={filter:c.filter,sort:c.sort},g=function(a,b){d&&"filter"===h&&"none"!==f.filter&&""!==f.filter?a.filter(b).addClass(e.controls.activeClass):a.removeClass(e.controls.activeClass).filter(b).addClass(e.controls.activeClass)},h="filter",i=null;e._execAction("_updateControls",0,arguments),c.filter===b&&(f.filter=e._activeFilter),c.sort===b&&(f.sort=e._activeSort),f.filter===e.selectors.target&&(f.filter="all");for(var j=0;2>j;j++)i=e.controls.live?a(e.selectors[h]):e["_$"+h+"Buttons"],i&&g(i,"[data-"+h+'="'+f[h]+'"]'),h="sort";e._execAction("_updateControls",1,arguments)},_filter:function(){var b=this;b._execAction("_filter",0);for(var c=0;cg?"asc"===e?-1:1:g>h?"asc"===e?1:-1:g===h&&d._newSort.length>c+1?d._compare(a,b,c+1):0},_printSort:function(a){var b=this,c=a?b._startOrder:b._newOrder,d=b._$parent[0].querySelectorAll(b.selectors.target),e=d.length?d[d.length-1].nextElementSibling:null,f=document.createDocumentFragment();b._execAction("_printSort",0,arguments);for(var g=0;g-1){if(c){var d=a.animation.effects.indexOf(b+"(");if(d>-1){var e=a.animation.effects.substring(d),f=/\(([^)]+)\)/.exec(e),g=f[1];return{val:g}}}return!0}return!1},d=function(a,b){return b?"-"===a.charAt(0)?a.substr(1,a.length):"-"+a:a},e=function(a,e){for(var f=[["scale",".01"],["translateX","20px"],["translateY","20px"],["translateZ","20px"],["rotateX","90deg"],["rotateY","90deg"],["rotateZ","180deg"]],g=0;gi;i++){var j=0===i?j=b._prefix:"";b._ff&&b._ff<=20&&(h[j+"transition-property"]="all",h[j+"transition-timing-function"]=b.animation.easing+"ms",h[j+"transition-duration"]=b.animation.duration+"ms"),h[j+"transition-delay"]=g+"ms",h[j+"transform"]="translate("+f.x+"px,"+f.y+"px)"}(b.effects.transform||b.effects.opacity)&&b._bindTargetDone(e),b._ff&&b._ff<=20?e.css(h):e.css(b.effects.transition).css(h)}for(var c=0;ci;i++){var j=0===i?j=b._prefix:"";k[j+"transition-delay"]=g+"ms",k[j+"transform"]=b.effects.transformOut,k.opacity=b.effects.opacity}e.css(b.effects.transition).css(k),(b.effects.transform||b.effects.opacity)&&b._bindTargetDone(e)}b._execAction("_animateTargets",1)},_bindTargetDone:function(b){var c=this,d=b[0];c._execAction("_bindTargetDone",0,arguments),d.dataset.bound||(d.dataset.bound=!0,c._targetsBound++,b.on("webkitTransitionEnd.mixItUp transitionend.mixItUp",function(e){(e.originalEvent.propertyName.indexOf("transform")>-1||e.originalEvent.propertyName.indexOf("opacity")>-1)&&a(e.originalEvent.target).is(c.selectors.target)&&(b.off(".mixItUp"),delete d.dataset.bound,c._targetDone())})),c._execAction("_bindTargetDone",1,arguments)},_targetDone:function(){var a=this;a._execAction("_targetDone",0),a._targetsDone++,a._targetsDone===a._targetsBound&&a._cleanUp(),a._execAction("_targetDone",1)},_cleanUp:function(){var b=this,c=b.animation.animateResizeTargets?"transform opacity width height margin-bottom margin-right":"transform opacity";unBrake=function(){b._$targets.removeStyle("transition",b._prefix)},b._execAction("_cleanUp",0),b._changingLayout?b._$show.css("display",b._newDisplay):b._$show.css("display",b.layout.display),b._$targets.css(b._brake),b._$targets.removeStyle(c,b._prefix).removeAttr("data-inter-pos-x data-inter-pos-y data-final-pos-x data-final-pos-y data-orig-pos-x data-orig-pos-y data-orig-height data-orig-width data-final-height data-final-width data-inter-width data-inter-height data-orig-margin-right data-orig-margin-bottom data-inter-margin-right data-inter-margin-bottom data-final-margin-right data-final-margin-bottom"),b._$hide.removeStyle("display"),b._$parent.removeStyle("height transition perspective-distance perspective perspective-origin-x perspective-origin-y perspective-origin perspectiveOrigin",b._prefix),b._sorting&&(b._printSort(),b._activeSort=b._newSortString,b._sorting=!1),b._changingLayout&&(b._changingDisplay&&(b.layout.display=b._newDisplay,b._changingDisplay=!1),b._changingClass&&(b._$parent.removeClass(b.layout.containerClass).addClass(b._newClass),b.layout.containerClass=b._newClass,b._changingClass=!1),b._changingLayout=!1),b._refresh(),b._buildState(),b._state.fail&&b._$container.addClass(b.layout.containerClassFail),b._$show=a(),b._$hide=a(),window.requestAnimationFrame&&requestAnimationFrame(unBrake),b._mixing=!1,"function"==typeof b.callbacks._user&&b.callbacks._user.call(b._domNode,b._state,b),"function"==typeof b.callbacks.onMixEnd&&b.callbacks.onMixEnd.call(b._domNode,b._state,b),b._$container.trigger("mixEnd",[b._state,b]),b._state.fail&&("function"==typeof b.callbacks.onMixFail&&b.callbacks.onMixFail.call(b._domNode,b._state,b),b._$container.trigger("mixFail",[b._state,b])),b._loading&&("function"==typeof b.callbacks.onMixLoad&&b.callbacks.onMixLoad.call(b._domNode,b._state,b),b._$container.trigger("mixLoad",[b._state,b])),b._queue.length&&(b._execAction("_queue",0),b.multiMix(b._queue[0][0],b._queue[0][1],b._queue[0][2]),b._queue.splice(0,1)),b._execAction("_cleanUp",1),b._loading=!1},_getPrefixedCSS:function(a,b,c){var d=this,e={};for(i=0;2>i;i++){var f=0===i?d._prefix:"";e[f+a]=c?f+b:b}return d._execFilter("_getPrefixedCSS",e,arguments)},_getDelay:function(a){var b=this,c="function"==typeof b.animation.staggerSequence?b.animation.staggerSequence.call(b._domNode,a,b._state):a,d=b.animation.stagger?c*b.animation.staggerDuration:0;return b._execFilter("_getDelay",d,arguments)},_parseMultiMixArgs:function(a){for(var b=this,c={command:null,animate:b.animation.enable,callback:null},d=0;dg;)h=d[g],g++;return a!==b?a[e]!==b?a[e]:a:void 0};return a?c._execFilter("getOption",d(c,a),arguments):c},setOptions:function(b){var c=this;c._execAction("setOptions",0,arguments),"object"==typeof b&&a.extend(!0,c,b),c._execAction("setOptions",1,arguments)},getState:function(){var a=this;return a._execFilter("getState",a._state,a)},forceRefresh:function(){var a=this;a._refresh(!1,!0)},destroy:function(b){var c=this;c._execAction("destroy",0,arguments),c._$body.add(a(c.selectors.sort)).add(a(c.selectors.filter)).off(".mixItUp");for(var d=0;d1?e:e[0]:c},a.fn.removeStyle=function(c,d){return d=d?d:"",this.each(function(){for(var e=this,f=c.split(" "),g=0;gh;h++){switch(h){case 0:var i=f[g];break;case 1:var i=a.MixItUp.prototype._helpers._camelCase(i);break;case 2:var i=d+f[g];break;case 3:var i=a.MixItUp.prototype._helpers._camelCase(d+f[g])}if(e.style[i]!==b&&"unknown"!=typeof e.style[i]&&e.style[i].length>0&&(e.style[i]=""),!d&&1===h)break}e.attributes&&e.attributes.style&&e.attributes.style!==b&&""===e.attributes.style.value&&e.attributes.removeNamedItem("style")})}}(jQuery);
\ No newline at end of file
diff --git a/django_code/cloudmanager/templates/js/jquery.prettyPhoto.js b/django_code/cloudmanager/templates/js/jquery.prettyPhoto.js
new file mode 100644
index 0000000..d958202
--- /dev/null
+++ b/django_code/cloudmanager/templates/js/jquery.prettyPhoto.js
@@ -0,0 +1,7 @@
+/* ------------------------------------------------------------------------
+ Class: prettyPhoto
+ Use: Lightbox clone for jQuery
+ Author: Stephane Caron (http://www.no-margin-for-errors.com)
+ Version: 3.1.5
+------------------------------------------------------------------------- */
+(function(e){function t(){var e=location.href;hashtag=e.indexOf("#prettyPhoto")!==-1?decodeURI(e.substring(e.indexOf("#prettyPhoto")+1,e.length)):false;return hashtag}function n(){if(typeof theRel=="undefined")return;location.hash=theRel+"/"+rel_index+"/"}function r(){if(location.href.indexOf("#prettyPhoto")!==-1)location.hash="prettyPhoto"}function i(e,t){e=e.replace(/[\[]/,"\\[").replace(/[\]]/,"\\]");var n="[\\?&]"+e+"=([^]*)";var r=new RegExp(n);var i=r.exec(t);return i==null?"":i[1]}e.prettyPhoto={version:"3.1.5"};e.fn.prettyPhoto=function(s){function g(){e(".pp_loaderIcon").hide();projectedTop=scroll_pos["scrollTop"]+(d/2-a["containerHeight"]/2);if(projectedTop<0)projectedTop=0;$ppt.fadeTo(settings.animation_speed,1);$pp_pic_holder.find(".pp_content").animate({height:a["contentHeight"],width:a["contentWidth"]},settings.animation_speed);$pp_pic_holder.animate({top:projectedTop,left:v/2-a["containerWidth"]/2<0?0:v/2-a["containerWidth"]/2,width:a["containerWidth"]},settings.animation_speed,function(){$pp_pic_holder.find(".pp_hoverContainer,#fullResImage").height(a["height"]).width(a["width"]);$pp_pic_holder.find(".pp_fade").fadeIn(settings.animation_speed);if(isSet&&S(pp_images[set_position])=="image"){$pp_pic_holder.find(".pp_hoverContainer").show()}else{$pp_pic_holder.find(".pp_hoverContainer").hide()}if(settings.allow_expand){if(a["resized"]){e("a.pp_expand,a.pp_contract").show()}else{e("a.pp_expand").hide()}}if(settings.autoplay_slideshow&&!m&&!f)e.prettyPhoto.startSlideshow();settings.changepicturecallback();f=true});C();s.ajaxcallback()}function y(t){$pp_pic_holder.find("#pp_full_res object,#pp_full_res embed").css("visibility","hidden");$pp_pic_holder.find(".pp_fade").fadeOut(settings.animation_speed,function(){e(".pp_loaderIcon").show();t()})}function b(t){t>1?e(".pp_nav").show():e(".pp_nav").hide()}function w(e,t){resized=false;E(e,t);imageWidth=e,imageHeight=t;if((p>v||h>d)&&doresize&&settings.allow_resize&&!u){resized=true,fitting=false;while(!fitting){if(p>v){imageWidth=v-200;imageHeight=t/e*imageWidth}else if(h>d){imageHeight=d-200;imageWidth=e/t*imageHeight}else{fitting=true}h=imageHeight,p=imageWidth}if(p>v||h>d){w(p,h)}E(imageWidth,imageHeight)}return{width:Math.floor(imageWidth),height:Math.floor(imageHeight),containerHeight:Math.floor(h),containerWidth:Math.floor(p)+settings.horizontal_padding*2,contentHeight:Math.floor(l),contentWidth:Math.floor(c),resized:resized}}function E(t,n){t=parseFloat(t);n=parseFloat(n);$pp_details=$pp_pic_holder.find(".pp_details");$pp_details.width(t);detailsHeight=parseFloat($pp_details.css("marginTop"))+parseFloat($pp_details.css("marginBottom"));$pp_details=$pp_details.clone().addClass(settings.theme).width(t).appendTo(e("body")).css({position:"absolute",top:-1e4});detailsHeight+=$pp_details.height();detailsHeight=detailsHeight<=34?36:detailsHeight;$pp_details.remove();$pp_title=$pp_pic_holder.find(".ppt");$pp_title.width(t);titleHeight=parseFloat($pp_title.css("marginTop"))+parseFloat($pp_title.css("marginBottom"));$pp_title=$pp_title.clone().appendTo(e("body")).css({position:"absolute",top:-1e4});titleHeight+=$pp_title.height();$pp_title.remove();l=n+detailsHeight;c=t;h=l+titleHeight+$pp_pic_holder.find(".pp_top").height()+$pp_pic_holder.find(".pp_bottom").height();p=t}function S(e){if(e.match(/youtube\.com\/watch/i)||e.match(/youtu\.be/i)){return"youtube"}else if(e.match(/vimeo\.com/i)){return"vimeo"}else if(e.match(/\b.mov\b/i)){return"quicktime"}else if(e.match(/\b.swf\b/i)){return"flash"}else if(e.match(/\biframe=true\b/i)){return"iframe"}else if(e.match(/\bajax=true\b/i)){return"ajax"}else if(e.match(/\bcustom=true\b/i)){return"custom"}else if(e.substr(0,1)=="#"){return"inline"}else{return"image"}}function x(){if(doresize&&typeof $pp_pic_holder!="undefined"){scroll_pos=T();contentHeight=$pp_pic_holder.height(),contentwidth=$pp_pic_holder.width();projectedTop=d/2+scroll_pos["scrollTop"]-contentHeight/2;if(projectedTop<0)projectedTop=0;if(contentHeight>d)return;$pp_pic_holder.css({top:projectedTop,left:v/2+scroll_pos["scrollLeft"]-contentwidth/2})}}function T(){if(self.pageYOffset){return{scrollTop:self.pageYOffset,scrollLeft:self.pageXOffset}}else if(document.documentElement&&document.documentElement.scrollTop){return{scrollTop:document.documentElement.scrollTop,scrollLeft:document.documentElement.scrollLeft}}else if(document.body){return{scrollTop:document.body.scrollTop,scrollLeft:document.body.scrollLeft}}}function N(){d=e(window).height(),v=e(window).width();if(typeof $pp_overlay!="undefined")$pp_overlay.height(e(document).height()).width(v)}function C(){if(isSet&&settings.overlay_gallery&&S(pp_images[set_position])=="image"){itemWidth=52+5;navWidth=settings.theme=="facebook"||settings.theme=="pp_default"?50:30;itemsPerPage=Math.floor((a["containerWidth"]-100-navWidth)/itemWidth);itemsPerPage=itemsPerPage
"}toInject=settings.gallery_markup.replace(/{gallery}/g,toInject);$pp_pic_holder.find("#pp_full_res").after(toInject);$pp_gallery=e(".pp_pic_holder .pp_gallery"),$pp_gallery_li=$pp_gallery.find("li");$pp_gallery.find(".pp_arrow_next").click(function(){e.prettyPhoto.changeGalleryPage("next");e.prettyPhoto.stopSlideshow();return false});$pp_gallery.find(".pp_arrow_previous").click(function(){e.prettyPhoto.changeGalleryPage("previous");e.prettyPhoto.stopSlideshow();return false});$pp_pic_holder.find(".pp_content").hover(function(){$pp_pic_holder.find(".pp_gallery:not(.disabled)").fadeIn()},function(){$pp_pic_holder.find(".pp_gallery:not(.disabled)").fadeOut()});itemWidth=52+5;$pp_gallery_li.each(function(t){e(this).find("a").click(function(){e.prettyPhoto.changePage(t);e.prettyPhoto.stopSlideshow();return false})})}if(settings.slideshow){$pp_pic_holder.find(".pp_nav").prepend('Play');$pp_pic_holder.find(".pp_nav .pp_play").click(function(){e.prettyPhoto.startSlideshow();return false})}$pp_pic_holder.attr("class","pp_pic_holder "+settings.theme);$pp_overlay.css({opacity:0,height:e(document).height(),width:e(window).width()}).bind("click",function(){if(!settings.modal)e.prettyPhoto.close()});e("a.pp_close").bind("click",function(){e.prettyPhoto.close();return false});if(settings.allow_expand){e("a.pp_expand").bind("click",function(t){if(e(this).hasClass("pp_expand")){e(this).removeClass("pp_expand").addClass("pp_contract");doresize=false}else{e(this).removeClass("pp_contract").addClass("pp_expand");doresize=true}y(function(){e.prettyPhoto.open()});return false})}$pp_pic_holder.find(".pp_previous, .pp_nav .pp_arrow_previous").bind("click",function(){e.prettyPhoto.changePage("previous");e.prettyPhoto.stopSlideshow();return false});$pp_pic_holder.find(".pp_next, .pp_nav .pp_arrow_next").bind("click",function(){e.prettyPhoto.changePage("next");e.prettyPhoto.stopSlideshow();return false});x()}s=jQuery.extend({hook:"rel",animation_speed:"fast",ajaxcallback:function(){},slideshow:5e3,autoplay_slideshow:false,opacity:.8,show_title:true,allow_resize:true,allow_expand:true,default_width:500,default_height:344,counter_separator_label:"/",theme:"pp_default",horizontal_padding:20,hideflash:false,wmode:"opaque",autoplay:true,modal:false,deeplinking:true,overlay_gallery:true,overlay_gallery_max:30,keyboard_shortcuts:true,changepicturecallback:function(){},callback:function(){},ie6_fallback:true,markup:' ',gallery_markup:'',image_markup:'
',flash_markup:'',quicktime_markup:'',iframe_markup:'',inline_markup:'{content}
',custom_markup:"",social_tools:''},s);var o=this,u=false,a,f,l,c,h,p,d=e(window).height(),v=e(window).width(),m;doresize=true,scroll_pos=T();e(window).unbind("resize.prettyphoto").bind("resize.prettyphoto",function(){x();N()});if(s.keyboard_shortcuts){e(document).unbind("keydown.prettyphoto").bind("keydown.prettyphoto",function(t){if(typeof $pp_pic_holder!="undefined"){if($pp_pic_holder.is(":visible")){switch(t.keyCode){case 37:e.prettyPhoto.changePage("previous");t.preventDefault();break;case 39:e.prettyPhoto.changePage("next");t.preventDefault();break;case 27:if(!settings.modal)e.prettyPhoto.close();t.preventDefault();break}}}})}e.prettyPhoto.initialize=function(){settings=s;if(settings.theme=="pp_default")settings.horizontal_padding=16;theRel=e(this).attr(settings.hook);galleryRegExp=/\[(?:.*)\]/;isSet=galleryRegExp.exec(theRel)?true:false;pp_images=isSet?jQuery.map(o,function(t,n){if(e(t).attr(settings.hook).indexOf(theRel)!=-1)return e(t).attr("href")}):e.makeArray(e(this).attr("href"));pp_titles=isSet?jQuery.map(o,function(t,n){if(e(t).attr(settings.hook).indexOf(theRel)!=-1)return e(t).find("img").attr("alt")?e(t).find("img").attr("alt"):""}):e.makeArray(e(this).find("img").attr("alt"));pp_descriptions=isSet?jQuery.map(o,function(t,n){if(e(t).attr(settings.hook).indexOf(theRel)!=-1)return e(t).attr("title")?e(t).attr("title"):""}):e.makeArray(e(this).attr("title"));if(pp_images.length>settings.overlay_gallery_max)settings.overlay_gallery=false;set_position=jQuery.inArray(e(this).attr("href"),pp_images);rel_index=isSet?set_position:e("a["+settings.hook+"^='"+theRel+"']").index(e(this));k(this);if(settings.allow_resize)e(window).bind("scroll.prettyphoto",function(){x()});e.prettyPhoto.open();return false};e.prettyPhoto.open=function(t){if(typeof settings=="undefined"){settings=s;pp_images=e.makeArray(arguments[0]);pp_titles=arguments[1]?e.makeArray(arguments[1]):e.makeArray("");pp_descriptions=arguments[2]?e.makeArray(arguments[2]):e.makeArray("");isSet=pp_images.length>1?true:false;set_position=arguments[3]?arguments[3]:0;k(t.target)}if(settings.hideflash)e("object,embed,iframe[src*=youtube],iframe[src*=vimeo]").css("visibility","hidden");b(e(pp_images).size());e(".pp_loaderIcon").show();if(settings.deeplinking)n();if(settings.social_tools){facebook_like_link=settings.social_tools.replace("{location_href}",encodeURIComponent(location.href));$pp_pic_holder.find(".pp_social").html(facebook_like_link)}if($ppt.is(":hidden"))$ppt.css("opacity",0).show();$pp_overlay.show().fadeTo(settings.animation_speed,settings.opacity);$pp_pic_holder.find(".currentTextHolder").text(set_position+1+settings.counter_separator_label+e(pp_images).size());if(typeof pp_descriptions[set_position]!="undefined"&&pp_descriptions[set_position]!=""){$pp_pic_holder.find(".pp_description").show().html(unescape(pp_descriptions[set_position]))}else{$pp_pic_holder.find(".pp_description").hide()}movie_width=parseFloat(i("width",pp_images[set_position]))?i("width",pp_images[set_position]):settings.default_width.toString();movie_height=parseFloat(i("height",pp_images[set_position]))?i("height",pp_images[set_position]):settings.default_height.toString();u=false;if(movie_height.indexOf("%")!=-1){movie_height=parseFloat(e(window).height()*parseFloat(movie_height)/100-150);u=true}if(movie_width.indexOf("%")!=-1){movie_width=parseFloat(e(window).width()*parseFloat(movie_width)/100-150);u=true}$pp_pic_holder.fadeIn(function(){settings.show_title&&pp_titles[set_position]!=""&&typeof pp_titles[set_position]!="undefined"?$ppt.html(unescape(pp_titles[set_position])):$ppt.html(" ");imgPreloader="";skipInjection=false;switch(S(pp_images[set_position])){case"image":imgPreloader=new Image;nextImage=new Image;if(isSet&&set_position0)movie_id=movie_id.substr(0,movie_id.indexOf("?"));if(movie_id.indexOf("&")>0)movie_id=movie_id.substr(0,movie_id.indexOf("&"))}movie="http://www.youtube.com/embed/"+movie_id;i("rel",pp_images[set_position])?movie+="?rel="+i("rel",pp_images[set_position]):movie+="?rel=1";if(settings.autoplay)movie+="&autoplay=1";toInject=settings.iframe_markup.replace(/{width}/g,a["width"]).replace(/{height}/g,a["height"]).replace(/{wmode}/g,settings.wmode).replace(/{path}/g,movie);break;case"vimeo":a=w(movie_width,movie_height);movie_id=pp_images[set_position];var t=/http(s?):\/\/(www\.)?vimeo.com\/(\d+)/;var n=movie_id.match(t);movie="http://player.vimeo.com/video/"+n[3]+"?title=0&byline=0&portrait=0";if(settings.autoplay)movie+="&autoplay=1;";vimeo_width=a["width"]+"/embed/?moog_width="+a["width"];toInject=settings.iframe_markup.replace(/{width}/g,vimeo_width).replace(/{height}/g,a["height"]).replace(/{path}/g,movie);break;case"quicktime":a=w(movie_width,movie_height);a["height"]+=15;a["contentHeight"]+=15;a["containerHeight"]+=15;toInject=settings.quicktime_markup.replace(/{width}/g,a["width"]).replace(/{height}/g,a["height"]).replace(/{wmode}/g,settings.wmode).replace(/{path}/g,pp_images[set_position]).replace(/{autoplay}/g,settings.autoplay);break;case"flash":a=w(movie_width,movie_height);flash_vars=pp_images[set_position];flash_vars=flash_vars.substring(pp_images[set_position].indexOf("flashvars")+10,pp_images[set_position].length);filename=pp_images[set_position];filename=filename.substring(0,filename.indexOf("?"));toInject=settings.flash_markup.replace(/{width}/g,a["width"]).replace(/{height}/g,a["height"]).replace(/{wmode}/g,settings.wmode).replace(/{path}/g,filename+"?"+flash_vars);break;case"iframe":a=w(movie_width,movie_height);frame_url=pp_images[set_position];frame_url=frame_url.substr(0,frame_url.indexOf("iframe")-1);toInject=settings.iframe_markup.replace(/{width}/g,a["width"]).replace(/{height}/g,a["height"]).replace(/{path}/g,frame_url);break;case"ajax":doresize=false;a=w(movie_width,movie_height);doresize=true;skipInjection=true;e.get(pp_images[set_position],function(e){toInject=settings.inline_markup.replace(/{content}/g,e);$pp_pic_holder.find("#pp_full_res")[0].innerHTML=toInject;g()});break;case"custom":a=w(movie_width,movie_height);toInject=settings.custom_markup;break;case"inline":myClone=e(pp_images[set_position]).clone().append('
').css({width:settings.default_width}).wrapInner('').appendTo(e("body")).show();doresize=false;a=w(e(myClone).width(),e(myClone).height());doresize=true;e(myClone).remove();toInject=settings.inline_markup.replace(/{content}/g,e(pp_images[set_position]).html());break}if(!imgPreloader&&!skipInjection){$pp_pic_holder.find("#pp_full_res")[0].innerHTML=toInject;g()}});return false};e.prettyPhoto.changePage=function(t){currentGalleryPage=0;if(t=="previous"){set_position--;if(set_position<0)set_position=e(pp_images).size()-1}else if(t=="next"){set_position++;if(set_position>e(pp_images).size()-1)set_position=0}else{set_position=t}rel_index=set_position;if(!doresize)doresize=true;if(settings.allow_expand){e(".pp_contract").removeClass("pp_contract").addClass("pp_expand")}y(function(){e.prettyPhoto.open()})};e.prettyPhoto.changeGalleryPage=function(e){if(e=="next"){currentGalleryPage++;if(currentGalleryPage>totalPage)currentGalleryPage=0}else if(e=="previous"){currentGalleryPage--;if(currentGalleryPage<0)currentGalleryPage=totalPage}else{currentGalleryPage=e}slide_speed=e=="next"||e=="previous"?settings.animation_speed:0;slide_to=currentGalleryPage*itemsPerPage*itemWidth;$pp_gallery.find("ul").animate({left:-slide_to},slide_speed)};e.prettyPhoto.startSlideshow=function(){if(typeof m=="undefined"){$pp_pic_holder.find(".pp_play").unbind("click").removeClass("pp_play").addClass("pp_pause").click(function(){e.prettyPhoto.stopSlideshow();return false});m=setInterval(e.prettyPhoto.startSlideshow,settings.slideshow)}else{e.prettyPhoto.changePage("next")}};e.prettyPhoto.stopSlideshow=function(){$pp_pic_holder.find(".pp_pause").unbind("click").removeClass("pp_pause").addClass("pp_play").click(function(){e.prettyPhoto.startSlideshow();return false});clearInterval(m);m=undefined};e.prettyPhoto.close=function(){if($pp_overlay.is(":animated"))return;e.prettyPhoto.stopSlideshow();$pp_pic_holder.stop().find("object,embed").css("visibility","hidden");e("div.pp_pic_holder,div.ppt,.pp_fade").fadeOut(settings.animation_speed,function(){e(this).remove()});$pp_overlay.fadeOut(settings.animation_speed,function(){if(settings.hideflash)e("object,embed,iframe[src*=youtube],iframe[src*=vimeo]").css("visibility","visible");e(this).remove();e(window).unbind("scroll.prettyphoto");r();settings.callback();doresize=true;f=false;delete settings})};if(!pp_alreadyInitialized&&t()){pp_alreadyInitialized=true;hashIndex=t();hashRel=hashIndex;hashIndex=hashIndex.substring(hashIndex.indexOf("/")+1,hashIndex.length-1);hashRel=hashRel.substring(0,hashRel.indexOf("/"));setTimeout(function(){e("a["+s.hook+"^='"+hashRel+"']:eq("+hashIndex+")").trigger("click")},50)}return this.unbind("click.prettyphoto").bind("click.prettyphoto",e.prettyPhoto.initialize)};})(jQuery);var pp_alreadyInitialized=false
\ No newline at end of file
diff --git a/django_code/cloudmanager/templates/js/jquery.validate.js b/django_code/cloudmanager/templates/js/jquery.validate.js
new file mode 100644
index 0000000..cadc305
--- /dev/null
+++ b/django_code/cloudmanager/templates/js/jquery.validate.js
@@ -0,0 +1,1231 @@
+/*!
+ * jQuery Validation Plugin 1.11.1
+ *
+ * http://bassistance.de/jquery-plugins/jquery-plugin-validation/
+ * http://docs.jquery.com/Plugins/Validation
+ *
+ * Copyright 2013 Jörn Zaefferer
+ * Released under the MIT license:
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+
+(function($) {
+
+$.extend($.fn, {
+ // http://docs.jquery.com/Plugins/Validation/validate
+ validate: function( options ) {
+
+ // if nothing is selected, return nothing; can't chain anyway
+ if ( !this.length ) {
+ if ( options && options.debug && window.console ) {
+ console.warn( "Nothing selected, can't validate, returning nothing." );
+ }
+ return;
+ }
+
+ // check if a validator for this form was already created
+ var validator = $.data( this[0], "validator" );
+ if ( validator ) {
+ return validator;
+ }
+
+ // Add novalidate tag if HTML5.
+ this.attr( "novalidate", "novalidate" );
+
+ validator = new $.validator( options, this[0] );
+ $.data( this[0], "validator", validator );
+
+ if ( validator.settings.onsubmit ) {
+
+ this.validateDelegate( ":submit", "click", function( event ) {
+ if ( validator.settings.submitHandler ) {
+ validator.submitButton = event.target;
+ }
+ // allow suppressing validation by adding a cancel class to the submit button
+ if ( $(event.target).hasClass("cancel") ) {
+ validator.cancelSubmit = true;
+ }
+
+ // allow suppressing validation by adding the html5 formnovalidate attribute to the submit button
+ if ( $(event.target).attr("formnovalidate") !== undefined ) {
+ validator.cancelSubmit = true;
+ }
+ });
+
+ // validate the form on submit
+ this.submit( function( event ) {
+ if ( validator.settings.debug ) {
+ // prevent form submit to be able to see console output
+ event.preventDefault();
+ }
+ function handle() {
+ var hidden;
+ if ( validator.settings.submitHandler ) {
+ if ( validator.submitButton ) {
+ // insert a hidden input as a replacement for the missing submit button
+ hidden = $("").attr("name", validator.submitButton.name).val( $(validator.submitButton).val() ).appendTo(validator.currentForm);
+ }
+ validator.settings.submitHandler.call( validator, validator.currentForm, event );
+ if ( validator.submitButton ) {
+ // and clean up afterwards; thanks to no-block-scope, hidden can be referenced
+ hidden.remove();
+ }
+ return false;
+ }
+ return true;
+ }
+
+ // prevent submit for invalid forms or custom submit handlers
+ if ( validator.cancelSubmit ) {
+ validator.cancelSubmit = false;
+ return handle();
+ }
+ if ( validator.form() ) {
+ if ( validator.pendingRequest ) {
+ validator.formSubmitted = true;
+ return false;
+ }
+ return handle();
+ } else {
+ validator.focusInvalid();
+ return false;
+ }
+ });
+ }
+
+ return validator;
+ },
+ // http://docs.jquery.com/Plugins/Validation/valid
+ valid: function() {
+ if ( $(this[0]).is("form")) {
+ return this.validate().form();
+ } else {
+ var valid = true;
+ var validator = $(this[0].form).validate();
+ this.each(function() {
+ valid = valid && validator.element(this);
+ });
+ return valid;
+ }
+ },
+ // attributes: space seperated list of attributes to retrieve and remove
+ removeAttrs: function( attributes ) {
+ var result = {},
+ $element = this;
+ $.each(attributes.split(/\s/), function( index, value ) {
+ result[value] = $element.attr(value);
+ $element.removeAttr(value);
+ });
+ return result;
+ },
+ // http://docs.jquery.com/Plugins/Validation/rules
+ rules: function( command, argument ) {
+ var element = this[0];
+
+ if ( command ) {
+ var settings = $.data(element.form, "validator").settings;
+ var staticRules = settings.rules;
+ var existingRules = $.validator.staticRules(element);
+ switch(command) {
+ case "add":
+ $.extend(existingRules, $.validator.normalizeRule(argument));
+ // remove messages from rules, but allow them to be set separetely
+ delete existingRules.messages;
+ staticRules[element.name] = existingRules;
+ if ( argument.messages ) {
+ settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages );
+ }
+ break;
+ case "remove":
+ if ( !argument ) {
+ delete staticRules[element.name];
+ return existingRules;
+ }
+ var filtered = {};
+ $.each(argument.split(/\s/), function( index, method ) {
+ filtered[method] = existingRules[method];
+ delete existingRules[method];
+ });
+ return filtered;
+ }
+ }
+
+ var data = $.validator.normalizeRules(
+ $.extend(
+ {},
+ $.validator.classRules(element),
+ $.validator.attributeRules(element),
+ $.validator.dataRules(element),
+ $.validator.staticRules(element)
+ ), element);
+
+ // make sure required is at front
+ if ( data.required ) {
+ var param = data.required;
+ delete data.required;
+ data = $.extend({required: param}, data);
+ }
+
+ return data;
+ }
+});
+
+// Custom selectors
+$.extend($.expr[":"], {
+ // http://docs.jquery.com/Plugins/Validation/blank
+ blank: function( a ) { return !$.trim("" + $(a).val()); },
+ // http://docs.jquery.com/Plugins/Validation/filled
+ filled: function( a ) { return !!$.trim("" + $(a).val()); },
+ // http://docs.jquery.com/Plugins/Validation/unchecked
+ unchecked: function( a ) { return !$(a).prop("checked"); }
+});
+
+// constructor for validator
+$.validator = function( options, form ) {
+ this.settings = $.extend( true, {}, $.validator.defaults, options );
+ this.currentForm = form;
+ this.init();
+};
+
+$.validator.format = function( source, params ) {
+ if ( arguments.length === 1 ) {
+ return function() {
+ var args = $.makeArray(arguments);
+ args.unshift(source);
+ return $.validator.format.apply( this, args );
+ };
+ }
+ if ( arguments.length > 2 && params.constructor !== Array ) {
+ params = $.makeArray(arguments).slice(1);
+ }
+ if ( params.constructor !== Array ) {
+ params = [ params ];
+ }
+ $.each(params, function( i, n ) {
+ source = source.replace( new RegExp("\\{" + i + "\\}", "g"), function() {
+ return n;
+ });
+ });
+ return source;
+};
+
+$.extend($.validator, {
+
+ defaults: {
+ messages: {},
+ groups: {},
+ rules: {},
+ errorClass: "error",
+ validClass: "valid",
+ errorElement: "label",
+ focusInvalid: true,
+ errorContainer: $([]),
+ errorLabelContainer: $([]),
+ onsubmit: true,
+ ignore: ":hidden",
+ ignoreTitle: false,
+ onfocusin: function( element, event ) {
+ this.lastActive = element;
+
+ // hide error label and remove error class on focus if enabled
+ if ( this.settings.focusCleanup && !this.blockFocusCleanup ) {
+ if ( this.settings.unhighlight ) {
+ this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
+ }
+ this.addWrapper(this.errorsFor(element)).hide();
+ }
+ },
+ onfocusout: function( element, event ) {
+ if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) {
+ this.element(element);
+ }
+ },
+ onkeyup: function( element, event ) {
+ if ( event.which === 9 && this.elementValue(element) === "" ) {
+ return;
+ } else if ( element.name in this.submitted || element === this.lastElement ) {
+ this.element(element);
+ }
+ },
+ onclick: function( element, event ) {
+ // click on selects, radiobuttons and checkboxes
+ if ( element.name in this.submitted ) {
+ this.element(element);
+ }
+ // or option elements, check parent select in that case
+ else if ( element.parentNode.name in this.submitted ) {
+ this.element(element.parentNode);
+ }
+ },
+ highlight: function( element, errorClass, validClass ) {
+ if ( element.type === "radio" ) {
+ this.findByName(element.name).addClass(errorClass).removeClass(validClass);
+ } else {
+ $(element).addClass(errorClass).removeClass(validClass);
+ }
+ },
+ unhighlight: function( element, errorClass, validClass ) {
+ if ( element.type === "radio" ) {
+ this.findByName(element.name).removeClass(errorClass).addClass(validClass);
+ } else {
+ $(element).removeClass(errorClass).addClass(validClass);
+ }
+ }
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults
+ setDefaults: function( settings ) {
+ $.extend( $.validator.defaults, settings );
+ },
+
+ messages: {
+ required: "This field is required.",
+ remote: "Please fix this field.",
+ email: "Please enter a valid email address.",
+ url: "Please enter a valid URL.",
+ date: "Please enter a valid date.",
+ dateISO: "Please enter a valid date (ISO).",
+ number: "Please enter a valid number.",
+ digits: "Please enter only digits.",
+ creditcard: "Please enter a valid credit card number.",
+ equalTo: "Please enter the same value again.",
+ maxlength: $.validator.format("Please enter no more than {0} characters."),
+ minlength: $.validator.format("Please enter at least {0} characters."),
+ rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."),
+ range: $.validator.format("Please enter a value between {0} and {1}."),
+ max: $.validator.format("Please enter a value less than or equal to {0}."),
+ min: $.validator.format("Please enter a value greater than or equal to {0}.")
+ },
+
+ autoCreateRanges: false,
+
+ prototype: {
+
+ init: function() {
+ this.labelContainer = $(this.settings.errorLabelContainer);
+ this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm);
+ this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer );
+ this.submitted = {};
+ this.valueCache = {};
+ this.pendingRequest = 0;
+ this.pending = {};
+ this.invalid = {};
+ this.reset();
+
+ var groups = (this.groups = {});
+ $.each(this.settings.groups, function( key, value ) {
+ if ( typeof value === "string" ) {
+ value = value.split(/\s/);
+ }
+ $.each(value, function( index, name ) {
+ groups[name] = key;
+ });
+ });
+ var rules = this.settings.rules;
+ $.each(rules, function( key, value ) {
+ rules[key] = $.validator.normalizeRule(value);
+ });
+
+ function delegate(event) {
+ var validator = $.data(this[0].form, "validator"),
+ eventType = "on" + event.type.replace(/^validate/, "");
+ if ( validator.settings[eventType] ) {
+ validator.settings[eventType].call(validator, this[0], event);
+ }
+ }
+ $(this.currentForm)
+ .validateDelegate(":text, [type='password'], [type='file'], select, textarea, " +
+ "[type='number'], [type='search'] ,[type='tel'], [type='url'], " +
+ "[type='email'], [type='datetime'], [type='date'], [type='month'], " +
+ "[type='week'], [type='time'], [type='datetime-local'], " +
+ "[type='range'], [type='color'] ",
+ "focusin focusout keyup", delegate)
+ .validateDelegate("[type='radio'], [type='checkbox'], select, option", "click", delegate);
+
+ if ( this.settings.invalidHandler ) {
+ $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler);
+ }
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Validator/form
+ form: function() {
+ this.checkForm();
+ $.extend(this.submitted, this.errorMap);
+ this.invalid = $.extend({}, this.errorMap);
+ if ( !this.valid() ) {
+ $(this.currentForm).triggerHandler("invalid-form", [this]);
+ }
+ this.showErrors();
+ return this.valid();
+ },
+
+ checkForm: function() {
+ this.prepareForm();
+ for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) {
+ this.check( elements[i] );
+ }
+ return this.valid();
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Validator/element
+ element: function( element ) {
+ element = this.validationTargetFor( this.clean( element ) );
+ this.lastElement = element;
+ this.prepareElement( element );
+ this.currentElements = $(element);
+ var result = this.check( element ) !== false;
+ if ( result ) {
+ delete this.invalid[element.name];
+ } else {
+ this.invalid[element.name] = true;
+ }
+ if ( !this.numberOfInvalids() ) {
+ // Hide error containers on last error
+ this.toHide = this.toHide.add( this.containers );
+ }
+ this.showErrors();
+ return result;
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Validator/showErrors
+ showErrors: function( errors ) {
+ if ( errors ) {
+ // add items to error list and map
+ $.extend( this.errorMap, errors );
+ this.errorList = [];
+ for ( var name in errors ) {
+ this.errorList.push({
+ message: errors[name],
+ element: this.findByName(name)[0]
+ });
+ }
+ // remove items from success list
+ this.successList = $.grep( this.successList, function( element ) {
+ return !(element.name in errors);
+ });
+ }
+ if ( this.settings.showErrors ) {
+ this.settings.showErrors.call( this, this.errorMap, this.errorList );
+ } else {
+ this.defaultShowErrors();
+ }
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Validator/resetForm
+ resetForm: function() {
+ if ( $.fn.resetForm ) {
+ $(this.currentForm).resetForm();
+ }
+ this.submitted = {};
+ this.lastElement = null;
+ this.prepareForm();
+ this.hideErrors();
+ this.elements().removeClass( this.settings.errorClass ).removeData( "previousValue" );
+ },
+
+ numberOfInvalids: function() {
+ return this.objectLength(this.invalid);
+ },
+
+ objectLength: function( obj ) {
+ var count = 0;
+ for ( var i in obj ) {
+ count++;
+ }
+ return count;
+ },
+
+ hideErrors: function() {
+ this.addWrapper( this.toHide ).hide();
+ },
+
+ valid: function() {
+ return this.size() === 0;
+ },
+
+ size: function() {
+ return this.errorList.length;
+ },
+
+ focusInvalid: function() {
+ if ( this.settings.focusInvalid ) {
+ try {
+ $(this.findLastActive() || this.errorList.length && this.errorList[0].element || [])
+ .filter(":visible")
+ .focus()
+ // manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
+ .trigger("focusin");
+ } catch(e) {
+ // ignore IE throwing errors when focusing hidden elements
+ }
+ }
+ },
+
+ findLastActive: function() {
+ var lastActive = this.lastActive;
+ return lastActive && $.grep(this.errorList, function( n ) {
+ return n.element.name === lastActive.name;
+ }).length === 1 && lastActive;
+ },
+
+ elements: function() {
+ var validator = this,
+ rulesCache = {};
+
+ // select all valid inputs inside the form (no submit or reset buttons)
+ return $(this.currentForm)
+ .find("input, select, textarea")
+ .not(":submit, :reset, :image, [disabled]")
+ .not( this.settings.ignore )
+ .filter(function() {
+ if ( !this.name && validator.settings.debug && window.console ) {
+ console.error( "%o has no name assigned", this);
+ }
+
+ // select only the first element for each name, and only those with rules specified
+ if ( this.name in rulesCache || !validator.objectLength($(this).rules()) ) {
+ return false;
+ }
+
+ rulesCache[this.name] = true;
+ return true;
+ });
+ },
+
+ clean: function( selector ) {
+ return $(selector)[0];
+ },
+
+ errors: function() {
+ var errorClass = this.settings.errorClass.replace(" ", ".");
+ return $(this.settings.errorElement + "." + errorClass, this.errorContext);
+ },
+
+ reset: function() {
+ this.successList = [];
+ this.errorList = [];
+ this.errorMap = {};
+ this.toShow = $([]);
+ this.toHide = $([]);
+ this.currentElements = $([]);
+ },
+
+ prepareForm: function() {
+ this.reset();
+ this.toHide = this.errors().add( this.containers );
+ },
+
+ prepareElement: function( element ) {
+ this.reset();
+ this.toHide = this.errorsFor(element);
+ },
+
+ elementValue: function( element ) {
+ var type = $(element).attr("type"),
+ val = $(element).val();
+
+ if ( type === "radio" || type === "checkbox" ) {
+ return $("input[name='" + $(element).attr("name") + "']:checked").val();
+ }
+
+ if ( typeof val === "string" ) {
+ return val.replace(/\r/g, "");
+ }
+ return val;
+ },
+
+ check: function( element ) {
+ element = this.validationTargetFor( this.clean( element ) );
+
+ var rules = $(element).rules();
+ var dependencyMismatch = false;
+ var val = this.elementValue(element);
+ var result;
+
+ for (var method in rules ) {
+ var rule = { method: method, parameters: rules[method] };
+ try {
+
+ result = $.validator.methods[method].call( this, val, element, rule.parameters );
+
+ // if a method indicates that the field is optional and therefore valid,
+ // don't mark it as valid when there are no other rules
+ if ( result === "dependency-mismatch" ) {
+ dependencyMismatch = true;
+ continue;
+ }
+ dependencyMismatch = false;
+
+ if ( result === "pending" ) {
+ this.toHide = this.toHide.not( this.errorsFor(element) );
+ return;
+ }
+
+ if ( !result ) {
+ this.formatAndAdd( element, rule );
+ return false;
+ }
+ } catch(e) {
+ if ( this.settings.debug && window.console ) {
+ console.log( "Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.", e );
+ }
+ throw e;
+ }
+ }
+ if ( dependencyMismatch ) {
+ return;
+ }
+ if ( this.objectLength(rules) ) {
+ this.successList.push(element);
+ }
+ return true;
+ },
+
+ // return the custom message for the given element and validation method
+ // specified in the element's HTML5 data attribute
+ customDataMessage: function( element, method ) {
+ return $(element).data("msg-" + method.toLowerCase()) || (element.attributes && $(element).attr("data-msg-" + method.toLowerCase()));
+ },
+
+ // return the custom message for the given element name and validation method
+ customMessage: function( name, method ) {
+ var m = this.settings.messages[name];
+ return m && (m.constructor === String ? m : m[method]);
+ },
+
+ // return the first defined argument, allowing empty strings
+ findDefined: function() {
+ for(var i = 0; i < arguments.length; i++) {
+ if ( arguments[i] !== undefined ) {
+ return arguments[i];
+ }
+ }
+ return undefined;
+ },
+
+ defaultMessage: function( element, method ) {
+ return this.findDefined(
+ this.customMessage( element.name, method ),
+ this.customDataMessage( element, method ),
+ // title is never undefined, so handle empty string as undefined
+ !this.settings.ignoreTitle && element.title || undefined,
+ $.validator.messages[method],
+ "Warning: No message defined for " + element.name + ""
+ );
+ },
+
+ formatAndAdd: function( element, rule ) {
+ var message = this.defaultMessage( element, rule.method ),
+ theregex = /\$?\{(\d+)\}/g;
+ if ( typeof message === "function" ) {
+ message = message.call(this, rule.parameters, element);
+ } else if (theregex.test(message)) {
+ message = $.validator.format(message.replace(theregex, "{$1}"), rule.parameters);
+ }
+ this.errorList.push({
+ message: message,
+ element: element
+ });
+
+ this.errorMap[element.name] = message;
+ this.submitted[element.name] = message;
+ },
+
+ addWrapper: function( toToggle ) {
+ if ( this.settings.wrapper ) {
+ toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );
+ }
+ return toToggle;
+ },
+
+ defaultShowErrors: function() {
+ var i, elements;
+ for ( i = 0; this.errorList[i]; i++ ) {
+ var error = this.errorList[i];
+ if ( this.settings.highlight ) {
+ this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
+ }
+ this.showLabel( error.element, error.message );
+ }
+ if ( this.errorList.length ) {
+ this.toShow = this.toShow.add( this.containers );
+ }
+ if ( this.settings.success ) {
+ for ( i = 0; this.successList[i]; i++ ) {
+ this.showLabel( this.successList[i] );
+ }
+ }
+ if ( this.settings.unhighlight ) {
+ for ( i = 0, elements = this.validElements(); elements[i]; i++ ) {
+ this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass );
+ }
+ }
+ this.toHide = this.toHide.not( this.toShow );
+ this.hideErrors();
+ this.addWrapper( this.toShow ).show();
+ },
+
+ validElements: function() {
+ return this.currentElements.not(this.invalidElements());
+ },
+
+ invalidElements: function() {
+ return $(this.errorList).map(function() {
+ return this.element;
+ });
+ },
+
+ showLabel: function( element, message ) {
+ var label = this.errorsFor( element );
+ if ( label.length ) {
+ // refresh error/success class
+ label.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );
+ // replace message on existing label
+ label.html(message);
+ } else {
+ // create label
+ label = $("<" + this.settings.errorElement + ">")
+ .attr("for", this.idOrName(element))
+ .addClass(this.settings.errorClass)
+ .html(message || "");
+ if ( this.settings.wrapper ) {
+ // make sure the element is visible, even in IE
+ // actually showing the wrapped element is handled elsewhere
+ label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent();
+ }
+ if ( !this.labelContainer.append(label).length ) {
+ if ( this.settings.errorPlacement ) {
+ this.settings.errorPlacement(label, $(element) );
+ } else {
+ label.insertAfter(element);
+ }
+ }
+ }
+ if ( !message && this.settings.success ) {
+ label.text("");
+ if ( typeof this.settings.success === "string" ) {
+ label.addClass( this.settings.success );
+ } else {
+ this.settings.success( label, element );
+ }
+ }
+ this.toShow = this.toShow.add(label);
+ },
+
+ errorsFor: function( element ) {
+ var name = this.idOrName(element);
+ return this.errors().filter(function() {
+ return $(this).attr("for") === name;
+ });
+ },
+
+ idOrName: function( element ) {
+ return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);
+ },
+
+ validationTargetFor: function( element ) {
+ // if radio/checkbox, validate first element in group instead
+ if ( this.checkable(element) ) {
+ element = this.findByName( element.name ).not(this.settings.ignore)[0];
+ }
+ return element;
+ },
+
+ checkable: function( element ) {
+ return (/radio|checkbox/i).test(element.type);
+ },
+
+ findByName: function( name ) {
+ return $(this.currentForm).find("[name='" + name + "']");
+ },
+
+ getLength: function( value, element ) {
+ switch( element.nodeName.toLowerCase() ) {
+ case "select":
+ return $("option:selected", element).length;
+ case "input":
+ if ( this.checkable( element) ) {
+ return this.findByName(element.name).filter(":checked").length;
+ }
+ }
+ return value.length;
+ },
+
+ depend: function( param, element ) {
+ return this.dependTypes[typeof param] ? this.dependTypes[typeof param](param, element) : true;
+ },
+
+ dependTypes: {
+ "boolean": function( param, element ) {
+ return param;
+ },
+ "string": function( param, element ) {
+ return !!$(param, element.form).length;
+ },
+ "function": function( param, element ) {
+ return param(element);
+ }
+ },
+
+ optional: function( element ) {
+ var val = this.elementValue(element);
+ return !$.validator.methods.required.call(this, val, element) && "dependency-mismatch";
+ },
+
+ startRequest: function( element ) {
+ if ( !this.pending[element.name] ) {
+ this.pendingRequest++;
+ this.pending[element.name] = true;
+ }
+ },
+
+ stopRequest: function( element, valid ) {
+ this.pendingRequest--;
+ // sometimes synchronization fails, make sure pendingRequest is never < 0
+ if ( this.pendingRequest < 0 ) {
+ this.pendingRequest = 0;
+ }
+ delete this.pending[element.name];
+ if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) {
+ $(this.currentForm).submit();
+ this.formSubmitted = false;
+ } else if (!valid && this.pendingRequest === 0 && this.formSubmitted) {
+ $(this.currentForm).triggerHandler("invalid-form", [this]);
+ this.formSubmitted = false;
+ }
+ },
+
+ previousValue: function( element ) {
+ return $.data(element, "previousValue") || $.data(element, "previousValue", {
+ old: null,
+ valid: true,
+ message: this.defaultMessage( element, "remote" )
+ });
+ }
+
+ },
+
+ classRuleSettings: {
+ required: {required: true},
+ email: {email: true},
+ url: {url: true},
+ date: {date: true},
+ dateISO: {dateISO: true},
+ number: {number: true},
+ digits: {digits: true},
+ creditcard: {creditcard: true}
+ },
+
+ addClassRules: function( className, rules ) {
+ if ( className.constructor === String ) {
+ this.classRuleSettings[className] = rules;
+ } else {
+ $.extend(this.classRuleSettings, className);
+ }
+ },
+
+ classRules: function( element ) {
+ var rules = {};
+ var classes = $(element).attr("class");
+ if ( classes ) {
+ $.each(classes.split(" "), function() {
+ if ( this in $.validator.classRuleSettings ) {
+ $.extend(rules, $.validator.classRuleSettings[this]);
+ }
+ });
+ }
+ return rules;
+ },
+
+ attributeRules: function( element ) {
+ var rules = {};
+ var $element = $(element);
+ var type = $element[0].getAttribute("type");
+
+ for (var method in $.validator.methods) {
+ var value;
+
+ // support for in both html5 and older browsers
+ if ( method === "required" ) {
+ value = $element.get(0).getAttribute(method);
+ // Some browsers return an empty string for the required attribute
+ // and non-HTML5 browsers might have required="" markup
+ if ( value === "" ) {
+ value = true;
+ }
+ // force non-HTML5 browsers to return bool
+ value = !!value;
+ } else {
+ value = $element.attr(method);
+ }
+
+ // convert the value to a number for number inputs, and for text for backwards compability
+ // allows type="date" and others to be compared as strings
+ if ( /min|max/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) {
+ value = Number(value);
+ }
+
+ if ( value ) {
+ rules[method] = value;
+ } else if ( type === method && type !== 'range' ) {
+ // exception: the jquery validate 'range' method
+ // does not test for the html5 'range' type
+ rules[method] = true;
+ }
+ }
+
+ // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs
+ if ( rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength) ) {
+ delete rules.maxlength;
+ }
+
+ return rules;
+ },
+
+ dataRules: function( element ) {
+ var method, value,
+ rules = {}, $element = $(element);
+ for (method in $.validator.methods) {
+ value = $element.data("rule-" + method.toLowerCase());
+ if ( value !== undefined ) {
+ rules[method] = value;
+ }
+ }
+ return rules;
+ },
+
+ staticRules: function( element ) {
+ var rules = {};
+ var validator = $.data(element.form, "validator");
+ if ( validator.settings.rules ) {
+ rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {};
+ }
+ return rules;
+ },
+
+ normalizeRules: function( rules, element ) {
+ // handle dependency check
+ $.each(rules, function( prop, val ) {
+ // ignore rule when param is explicitly false, eg. required:false
+ if ( val === false ) {
+ delete rules[prop];
+ return;
+ }
+ if ( val.param || val.depends ) {
+ var keepRule = true;
+ switch (typeof val.depends) {
+ case "string":
+ keepRule = !!$(val.depends, element.form).length;
+ break;
+ case "function":
+ keepRule = val.depends.call(element, element);
+ break;
+ }
+ if ( keepRule ) {
+ rules[prop] = val.param !== undefined ? val.param : true;
+ } else {
+ delete rules[prop];
+ }
+ }
+ });
+
+ // evaluate parameters
+ $.each(rules, function( rule, parameter ) {
+ rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter;
+ });
+
+ // clean number parameters
+ $.each(['minlength', 'maxlength'], function() {
+ if ( rules[this] ) {
+ rules[this] = Number(rules[this]);
+ }
+ });
+ $.each(['rangelength', 'range'], function() {
+ var parts;
+ if ( rules[this] ) {
+ if ( $.isArray(rules[this]) ) {
+ rules[this] = [Number(rules[this][0]), Number(rules[this][1])];
+ } else if ( typeof rules[this] === "string" ) {
+ parts = rules[this].split(/[\s,]+/);
+ rules[this] = [Number(parts[0]), Number(parts[1])];
+ }
+ }
+ });
+
+ if ( $.validator.autoCreateRanges ) {
+ // auto-create ranges
+ if ( rules.min && rules.max ) {
+ rules.range = [rules.min, rules.max];
+ delete rules.min;
+ delete rules.max;
+ }
+ if ( rules.minlength && rules.maxlength ) {
+ rules.rangelength = [rules.minlength, rules.maxlength];
+ delete rules.minlength;
+ delete rules.maxlength;
+ }
+ }
+
+ return rules;
+ },
+
+ // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
+ normalizeRule: function( data ) {
+ if ( typeof data === "string" ) {
+ var transformed = {};
+ $.each(data.split(/\s/), function() {
+ transformed[this] = true;
+ });
+ data = transformed;
+ }
+ return data;
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Validator/addMethod
+ addMethod: function( name, method, message ) {
+ $.validator.methods[name] = method;
+ $.validator.messages[name] = message !== undefined ? message : $.validator.messages[name];
+ if ( method.length < 3 ) {
+ $.validator.addClassRules(name, $.validator.normalizeRule(name));
+ }
+ },
+
+ methods: {
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/required
+ required: function( value, element, param ) {
+ // check if dependency is met
+ if ( !this.depend(param, element) ) {
+ return "dependency-mismatch";
+ }
+ if ( element.nodeName.toLowerCase() === "select" ) {
+ // could be an array for select-multiple or a string, both are fine this way
+ var val = $(element).val();
+ return val && val.length > 0;
+ }
+ if ( this.checkable(element) ) {
+ return this.getLength(value, element) > 0;
+ }
+ return $.trim(value).length > 0;
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/email
+ email: function( value, element ) {
+ // contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/
+ return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i.test(value);
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/url
+ url: function( value, element ) {
+ // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/
+ return this.optional(element) || /^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value);
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/date
+ date: function( value, element ) {
+ return this.optional(element) || !/Invalid|NaN/.test(new Date(value).toString());
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/dateISO
+ dateISO: function( value, element ) {
+ return this.optional(element) || /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/.test(value);
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/number
+ number: function( value, element ) {
+ return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value);
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/digits
+ digits: function( value, element ) {
+ return this.optional(element) || /^\d+$/.test(value);
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/creditcard
+ // based on http://en.wikipedia.org/wiki/Luhn
+ creditcard: function( value, element ) {
+ if ( this.optional(element) ) {
+ return "dependency-mismatch";
+ }
+ // accept only spaces, digits and dashes
+ if ( /[^0-9 \-]+/.test(value) ) {
+ return false;
+ }
+ var nCheck = 0,
+ nDigit = 0,
+ bEven = false;
+
+ value = value.replace(/\D/g, "");
+
+ for (var n = value.length - 1; n >= 0; n--) {
+ var cDigit = value.charAt(n);
+ nDigit = parseInt(cDigit, 10);
+ if ( bEven ) {
+ if ( (nDigit *= 2) > 9 ) {
+ nDigit -= 9;
+ }
+ }
+ nCheck += nDigit;
+ bEven = !bEven;
+ }
+
+ return (nCheck % 10) === 0;
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/minlength
+ minlength: function( value, element, param ) {
+ var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element);
+ return this.optional(element) || length >= param;
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/maxlength
+ maxlength: function( value, element, param ) {
+ var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element);
+ return this.optional(element) || length <= param;
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/rangelength
+ rangelength: function( value, element, param ) {
+ var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element);
+ return this.optional(element) || ( length >= param[0] && length <= param[1] );
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/min
+ min: function( value, element, param ) {
+ return this.optional(element) || value >= param;
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/max
+ max: function( value, element, param ) {
+ return this.optional(element) || value <= param;
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/range
+ range: function( value, element, param ) {
+ return this.optional(element) || ( value >= param[0] && value <= param[1] );
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/equalTo
+ equalTo: function( value, element, param ) {
+ // bind to the blur event of the target in order to revalidate whenever the target field is updated
+ // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead
+ var target = $(param);
+ if ( this.settings.onfocusout ) {
+ target.unbind(".validate-equalTo").bind("blur.validate-equalTo", function() {
+ $(element).valid();
+ });
+ }
+ return value === target.val();
+ },
+
+ // http://docs.jquery.com/Plugins/Validation/Methods/remote
+ remote: function( value, element, param ) {
+ if ( this.optional(element) ) {
+ return "dependency-mismatch";
+ }
+
+ var previous = this.previousValue(element);
+ if (!this.settings.messages[element.name] ) {
+ this.settings.messages[element.name] = {};
+ }
+ previous.originalMessage = this.settings.messages[element.name].remote;
+ this.settings.messages[element.name].remote = previous.message;
+
+ param = typeof param === "string" && {url:param} || param;
+
+ if ( previous.old === value ) {
+ return previous.valid;
+ }
+
+ previous.old = value;
+ var validator = this;
+ this.startRequest(element);
+ var data = {};
+ data[element.name] = value;
+ $.ajax($.extend(true, {
+ url: param,
+ mode: "abort",
+ port: "validate" + element.name,
+ dataType: "json",
+ data: data,
+ success: function( response ) {
+ validator.settings.messages[element.name].remote = previous.originalMessage;
+ var valid = response === true || response === "true";
+ if ( valid ) {
+ var submitted = validator.formSubmitted;
+ validator.prepareElement(element);
+ validator.formSubmitted = submitted;
+ validator.successList.push(element);
+ delete validator.invalid[element.name];
+ validator.showErrors();
+ } else {
+ var errors = {};
+ var message = response || validator.defaultMessage( element, "remote" );
+ errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message;
+ validator.invalid[element.name] = true;
+ validator.showErrors(errors);
+ }
+ previous.valid = valid;
+ validator.stopRequest(element, valid);
+ }
+ }, param));
+ return "pending";
+ }
+
+ }
+
+});
+
+// deprecated, use $.validator.format instead
+$.format = $.validator.format;
+
+}(jQuery));
+
+// ajax mode: abort
+// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
+// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
+(function($) {
+ var pendingRequests = {};
+ // Use a prefilter if available (1.5+)
+ if ( $.ajaxPrefilter ) {
+ $.ajaxPrefilter(function( settings, _, xhr ) {
+ var port = settings.port;
+ if ( settings.mode === "abort" ) {
+ if ( pendingRequests[port] ) {
+ pendingRequests[port].abort();
+ }
+ pendingRequests[port] = xhr;
+ }
+ });
+ } else {
+ // Proxy ajax
+ var ajax = $.ajax;
+ $.ajax = function( settings ) {
+ var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
+ port = ( "port" in settings ? settings : $.ajaxSettings ).port;
+ if ( mode === "abort" ) {
+ if ( pendingRequests[port] ) {
+ pendingRequests[port].abort();
+ }
+ pendingRequests[port] = ajax.apply(this, arguments);
+ return pendingRequests[port];
+ }
+ return ajax.apply(this, arguments);
+ };
+ }
+}(jQuery));
+
+// provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation
+// handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target
+(function($) {
+ $.extend($.fn, {
+ validateDelegate: function( delegate, type, handler ) {
+ return this.bind(type, function( event ) {
+ var target = $(event.target);
+ if ( target.is(delegate) ) {
+ return handler.apply(target, arguments);
+ }
+ });
+ }
+ });
+}(jQuery));
\ No newline at end of file
diff --git a/django_code/cloudmanager/templates/js/jquery.validate.min.js b/django_code/cloudmanager/templates/js/jquery.validate.min.js
new file mode 100644
index 0000000..5264617
--- /dev/null
+++ b/django_code/cloudmanager/templates/js/jquery.validate.min.js
@@ -0,0 +1,4 @@
+/*! jQuery Validation Plugin - v1.13.0 - 7/1/2014
+ * http://jqueryvalidation.org/
+ * Copyright (c) 2014 Jörn Zaefferer; Licensed MIT */
+!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a(jQuery)}(function(a){a.extend(a.fn,{validate:function(b){if(!this.length)return void(b&&b.debug&&window.console&&console.warn("Nothing selected, can't validate, returning nothing."));var c=a.data(this[0],"validator");return c?c:(this.attr("novalidate","novalidate"),c=new a.validator(b,this[0]),a.data(this[0],"validator",c),c.settings.onsubmit&&(this.validateDelegate(":submit","click",function(b){c.settings.submitHandler&&(c.submitButton=b.target),a(b.target).hasClass("cancel")&&(c.cancelSubmit=!0),void 0!==a(b.target).attr("formnovalidate")&&(c.cancelSubmit=!0)}),this.submit(function(b){function d(){var d;return c.settings.submitHandler?(c.submitButton&&(d=a("").attr("name",c.submitButton.name).val(a(c.submitButton).val()).appendTo(c.currentForm)),c.settings.submitHandler.call(c,c.currentForm,b),c.submitButton&&d.remove(),!1):!0}return c.settings.debug&&b.preventDefault(),c.cancelSubmit?(c.cancelSubmit=!1,d()):c.form()?c.pendingRequest?(c.formSubmitted=!0,!1):d():(c.focusInvalid(),!1)})),c)},valid:function(){var b,c;return a(this[0]).is("form")?b=this.validate().form():(b=!0,c=a(this[0].form).validate(),this.each(function(){b=c.element(this)&&b})),b},removeAttrs:function(b){var c={},d=this;return a.each(b.split(/\s/),function(a,b){c[b]=d.attr(b),d.removeAttr(b)}),c},rules:function(b,c){var d,e,f,g,h,i,j=this[0];if(b)switch(d=a.data(j.form,"validator").settings,e=d.rules,f=a.validator.staticRules(j),b){case"add":a.extend(f,a.validator.normalizeRule(c)),delete f.messages,e[j.name]=f,c.messages&&(d.messages[j.name]=a.extend(d.messages[j.name],c.messages));break;case"remove":return c?(i={},a.each(c.split(/\s/),function(b,c){i[c]=f[c],delete f[c],"required"===c&&a(j).removeAttr("aria-required")}),i):(delete e[j.name],f)}return g=a.validator.normalizeRules(a.extend({},a.validator.classRules(j),a.validator.attributeRules(j),a.validator.dataRules(j),a.validator.staticRules(j)),j),g.required&&(h=g.required,delete g.required,g=a.extend({required:h},g),a(j).attr("aria-required","true")),g.remote&&(h=g.remote,delete g.remote,g=a.extend(g,{remote:h})),g}}),a.extend(a.expr[":"],{blank:function(b){return!a.trim(""+a(b).val())},filled:function(b){return!!a.trim(""+a(b).val())},unchecked:function(b){return!a(b).prop("checked")}}),a.validator=function(b,c){this.settings=a.extend(!0,{},a.validator.defaults,b),this.currentForm=c,this.init()},a.validator.format=function(b,c){return 1===arguments.length?function(){var c=a.makeArray(arguments);return c.unshift(b),a.validator.format.apply(this,c)}:(arguments.length>2&&c.constructor!==Array&&(c=a.makeArray(arguments).slice(1)),c.constructor!==Array&&(c=[c]),a.each(c,function(a,c){b=b.replace(new RegExp("\\{"+a+"\\}","g"),function(){return c})}),b)},a.extend(a.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:"error",validClass:"valid",errorElement:"label",focusInvalid:!0,errorContainer:a([]),errorLabelContainer:a([]),onsubmit:!0,ignore:":hidden",ignoreTitle:!1,onfocusin:function(a){this.lastActive=a,this.settings.focusCleanup&&!this.blockFocusCleanup&&(this.settings.unhighlight&&this.settings.unhighlight.call(this,a,this.settings.errorClass,this.settings.validClass),this.hideThese(this.errorsFor(a)))},onfocusout:function(a){this.checkable(a)||!(a.name in this.submitted)&&this.optional(a)||this.element(a)},onkeyup:function(a,b){(9!==b.which||""!==this.elementValue(a))&&(a.name in this.submitted||a===this.lastElement)&&this.element(a)},onclick:function(a){a.name in this.submitted?this.element(a):a.parentNode.name in this.submitted&&this.element(a.parentNode)},highlight:function(b,c,d){"radio"===b.type?this.findByName(b.name).addClass(c).removeClass(d):a(b).addClass(c).removeClass(d)},unhighlight:function(b,c,d){"radio"===b.type?this.findByName(b.name).removeClass(c).addClass(d):a(b).removeClass(c).addClass(d)}},setDefaults:function(b){a.extend(a.validator.defaults,b)},messages:{required:"This field is required.",remote:"Please fix this field.",email:"Please enter a valid email address.",url:"Please enter a valid URL.",date:"Please enter a valid date.",dateISO:"Please enter a valid date ( ISO ).",number:"Please enter a valid number.",digits:"Please enter only digits.",creditcard:"Please enter a valid credit card number.",equalTo:"Please enter the same value again.",maxlength:a.validator.format("Please enter no more than {0} characters."),minlength:a.validator.format("Please enter at least {0} characters."),rangelength:a.validator.format("Please enter a value between {0} and {1} characters long."),range:a.validator.format("Please enter a value between {0} and {1}."),max:a.validator.format("Please enter a value less than or equal to {0}."),min:a.validator.format("Please enter a value greater than or equal to {0}.")},autoCreateRanges:!1,prototype:{init:function(){function b(b){var c=a.data(this[0].form,"validator"),d="on"+b.type.replace(/^validate/,""),e=c.settings;e[d]&&!this.is(e.ignore)&&e[d].call(c,this[0],b)}this.labelContainer=a(this.settings.errorLabelContainer),this.errorContext=this.labelContainer.length&&this.labelContainer||a(this.currentForm),this.containers=a(this.settings.errorContainer).add(this.settings.errorLabelContainer),this.submitted={},this.valueCache={},this.pendingRequest=0,this.pending={},this.invalid={},this.reset();var c,d=this.groups={};a.each(this.settings.groups,function(b,c){"string"==typeof c&&(c=c.split(/\s/)),a.each(c,function(a,c){d[c]=b})}),c=this.settings.rules,a.each(c,function(b,d){c[b]=a.validator.normalizeRule(d)}),a(this.currentForm).validateDelegate(":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'] ,[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], [type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], [type='radio'], [type='checkbox']","focusin focusout keyup",b).validateDelegate("select, option, [type='radio'], [type='checkbox']","click",b),this.settings.invalidHandler&&a(this.currentForm).bind("invalid-form.validate",this.settings.invalidHandler),a(this.currentForm).find("[required], [data-rule-required], .required").attr("aria-required","true")},form:function(){return this.checkForm(),a.extend(this.submitted,this.errorMap),this.invalid=a.extend({},this.errorMap),this.valid()||a(this.currentForm).triggerHandler("invalid-form",[this]),this.showErrors(),this.valid()},checkForm:function(){this.prepareForm();for(var a=0,b=this.currentElements=this.elements();b[a];a++)this.check(b[a]);return this.valid()},element:function(b){var c=this.clean(b),d=this.validationTargetFor(c),e=!0;return this.lastElement=d,void 0===d?delete this.invalid[c.name]:(this.prepareElement(d),this.currentElements=a(d),e=this.check(d)!==!1,e?delete this.invalid[d.name]:this.invalid[d.name]=!0),a(b).attr("aria-invalid",!e),this.numberOfInvalids()||(this.toHide=this.toHide.add(this.containers)),this.showErrors(),e},showErrors:function(b){if(b){a.extend(this.errorMap,b),this.errorList=[];for(var c in b)this.errorList.push({message:b[c],element:this.findByName(c)[0]});this.successList=a.grep(this.successList,function(a){return!(a.name in b)})}this.settings.showErrors?this.settings.showErrors.call(this,this.errorMap,this.errorList):this.defaultShowErrors()},resetForm:function(){a.fn.resetForm&&a(this.currentForm).resetForm(),this.submitted={},this.lastElement=null,this.prepareForm(),this.hideErrors(),this.elements().removeClass(this.settings.errorClass).removeData("previousValue").removeAttr("aria-invalid")},numberOfInvalids:function(){return this.objectLength(this.invalid)},objectLength:function(a){var b,c=0;for(b in a)c++;return c},hideErrors:function(){this.hideThese(this.toHide)},hideThese:function(a){a.not(this.containers).text(""),this.addWrapper(a).hide()},valid:function(){return 0===this.size()},size:function(){return this.errorList.length},focusInvalid:function(){if(this.settings.focusInvalid)try{a(this.findLastActive()||this.errorList.length&&this.errorList[0].element||[]).filter(":visible").focus().trigger("focusin")}catch(b){}},findLastActive:function(){var b=this.lastActive;return b&&1===a.grep(this.errorList,function(a){return a.element.name===b.name}).length&&b},elements:function(){var b=this,c={};return a(this.currentForm).find("input, select, textarea").not(":submit, :reset, :image, [disabled]").not(this.settings.ignore).filter(function(){return!this.name&&b.settings.debug&&window.console&&console.error("%o has no name assigned",this),this.name in c||!b.objectLength(a(this).rules())?!1:(c[this.name]=!0,!0)})},clean:function(b){return a(b)[0]},errors:function(){var b=this.settings.errorClass.split(" ").join(".");return a(this.settings.errorElement+"."+b,this.errorContext)},reset:function(){this.successList=[],this.errorList=[],this.errorMap={},this.toShow=a([]),this.toHide=a([]),this.currentElements=a([])},prepareForm:function(){this.reset(),this.toHide=this.errors().add(this.containers)},prepareElement:function(a){this.reset(),this.toHide=this.errorsFor(a)},elementValue:function(b){var c,d=a(b),e=b.type;return"radio"===e||"checkbox"===e?a("input[name='"+b.name+"']:checked").val():"number"===e&&"undefined"!=typeof b.validity?b.validity.badInput?!1:d.val():(c=d.val(),"string"==typeof c?c.replace(/\r/g,""):c)},check:function(b){b=this.validationTargetFor(this.clean(b));var c,d,e,f=a(b).rules(),g=a.map(f,function(a,b){return b}).length,h=!1,i=this.elementValue(b);for(d in f){e={method:d,parameters:f[d]};try{if(c=a.validator.methods[d].call(this,i,b,e.parameters),"dependency-mismatch"===c&&1===g){h=!0;continue}if(h=!1,"pending"===c)return void(this.toHide=this.toHide.not(this.errorsFor(b)));if(!c)return this.formatAndAdd(b,e),!1}catch(j){throw this.settings.debug&&window.console&&console.log("Exception occurred when checking element "+b.id+", check the '"+e.method+"' method.",j),j}}if(!h)return this.objectLength(f)&&this.successList.push(b),!0},customDataMessage:function(b,c){return a(b).data("msg"+c.charAt(0).toUpperCase()+c.substring(1).toLowerCase())||a(b).data("msg")},customMessage:function(a,b){var c=this.settings.messages[a];return c&&(c.constructor===String?c:c[b])},findDefined:function(){for(var a=0;aWarning: No message defined for "+b.name+"")},formatAndAdd:function(b,c){var d=this.defaultMessage(b,c.method),e=/\$?\{(\d+)\}/g;"function"==typeof d?d=d.call(this,c.parameters,b):e.test(d)&&(d=a.validator.format(d.replace(e,"{$1}"),c.parameters)),this.errorList.push({message:d,element:b,method:c.method}),this.errorMap[b.name]=d,this.submitted[b.name]=d},addWrapper:function(a){return this.settings.wrapper&&(a=a.add(a.parent(this.settings.wrapper))),a},defaultShowErrors:function(){var a,b,c;for(a=0;this.errorList[a];a++)c=this.errorList[a],this.settings.highlight&&this.settings.highlight.call(this,c.element,this.settings.errorClass,this.settings.validClass),this.showLabel(c.element,c.message);if(this.errorList.length&&(this.toShow=this.toShow.add(this.containers)),this.settings.success)for(a=0;this.successList[a];a++)this.showLabel(this.successList[a]);if(this.settings.unhighlight)for(a=0,b=this.validElements();b[a];a++)this.settings.unhighlight.call(this,b[a],this.settings.errorClass,this.settings.validClass);this.toHide=this.toHide.not(this.toShow),this.hideErrors(),this.addWrapper(this.toShow).show()},validElements:function(){return this.currentElements.not(this.invalidElements())},invalidElements:function(){return a(this.errorList).map(function(){return this.element})},showLabel:function(b,c){var d,e,f,g=this.errorsFor(b),h=this.idOrName(b),i=a(b).attr("aria-describedby");g.length?(g.removeClass(this.settings.validClass).addClass(this.settings.errorClass),g.html(c)):(g=a("<"+this.settings.errorElement+">").attr("id",h+"-error").addClass(this.settings.errorClass).html(c||""),d=g,this.settings.wrapper&&(d=g.hide().show().wrap("<"+this.settings.wrapper+"/>").parent()),this.labelContainer.length?this.labelContainer.append(d):this.settings.errorPlacement?this.settings.errorPlacement(d,a(b)):d.insertAfter(b),g.is("label")?g.attr("for",h):0===g.parents("label[for='"+h+"']").length&&(f=g.attr("id"),i?i.match(new RegExp("\b"+f+"\b"))||(i+=" "+f):i=f,a(b).attr("aria-describedby",i),e=this.groups[b.name],e&&a.each(this.groups,function(b,c){c===e&&a("[name='"+b+"']",this.currentForm).attr("aria-describedby",g.attr("id"))}))),!c&&this.settings.success&&(g.text(""),"string"==typeof this.settings.success?g.addClass(this.settings.success):this.settings.success(g,b)),this.toShow=this.toShow.add(g)},errorsFor:function(b){var c=this.idOrName(b),d=a(b).attr("aria-describedby"),e="label[for='"+c+"'], label[for='"+c+"'] *";return d&&(e=e+", #"+d.replace(/\s+/g,", #")),this.errors().filter(e)},idOrName:function(a){return this.groups[a.name]||(this.checkable(a)?a.name:a.id||a.name)},validationTargetFor:function(a){return this.checkable(a)&&(a=this.findByName(a.name).not(this.settings.ignore)[0]),a},checkable:function(a){return/radio|checkbox/i.test(a.type)},findByName:function(b){return a(this.currentForm).find("[name='"+b+"']")},getLength:function(b,c){switch(c.nodeName.toLowerCase()){case"select":return a("option:selected",c).length;case"input":if(this.checkable(c))return this.findByName(c.name).filter(":checked").length}return b.length},depend:function(a,b){return this.dependTypes[typeof a]?this.dependTypes[typeof a](a,b):!0},dependTypes:{"boolean":function(a){return a},string:function(b,c){return!!a(b,c.form).length},"function":function(a,b){return a(b)}},optional:function(b){var c=this.elementValue(b);return!a.validator.methods.required.call(this,c,b)&&"dependency-mismatch"},startRequest:function(a){this.pending[a.name]||(this.pendingRequest++,this.pending[a.name]=!0)},stopRequest:function(b,c){this.pendingRequest--,this.pendingRequest<0&&(this.pendingRequest=0),delete this.pending[b.name],c&&0===this.pendingRequest&&this.formSubmitted&&this.form()?(a(this.currentForm).submit(),this.formSubmitted=!1):!c&&0===this.pendingRequest&&this.formSubmitted&&(a(this.currentForm).triggerHandler("invalid-form",[this]),this.formSubmitted=!1)},previousValue:function(b){return a.data(b,"previousValue")||a.data(b,"previousValue",{old:null,valid:!0,message:this.defaultMessage(b,"remote")})}},classRuleSettings:{required:{required:!0},email:{email:!0},url:{url:!0},date:{date:!0},dateISO:{dateISO:!0},number:{number:!0},digits:{digits:!0},creditcard:{creditcard:!0}},addClassRules:function(b,c){b.constructor===String?this.classRuleSettings[b]=c:a.extend(this.classRuleSettings,b)},classRules:function(b){var c={},d=a(b).attr("class");return d&&a.each(d.split(" "),function(){this in a.validator.classRuleSettings&&a.extend(c,a.validator.classRuleSettings[this])}),c},attributeRules:function(b){var c,d,e={},f=a(b),g=b.getAttribute("type");for(c in a.validator.methods)"required"===c?(d=b.getAttribute(c),""===d&&(d=!0),d=!!d):d=f.attr(c),/min|max/.test(c)&&(null===g||/number|range|text/.test(g))&&(d=Number(d)),d||0===d?e[c]=d:g===c&&"range"!==g&&(e[c]=!0);return e.maxlength&&/-1|2147483647|524288/.test(e.maxlength)&&delete e.maxlength,e},dataRules:function(b){var c,d,e={},f=a(b);for(c in a.validator.methods)d=f.data("rule"+c.charAt(0).toUpperCase()+c.substring(1).toLowerCase()),void 0!==d&&(e[c]=d);return e},staticRules:function(b){var c={},d=a.data(b.form,"validator");return d.settings.rules&&(c=a.validator.normalizeRule(d.settings.rules[b.name])||{}),c},normalizeRules:function(b,c){return a.each(b,function(d,e){if(e===!1)return void delete b[d];if(e.param||e.depends){var f=!0;switch(typeof e.depends){case"string":f=!!a(e.depends,c.form).length;break;case"function":f=e.depends.call(c,c)}f?b[d]=void 0!==e.param?e.param:!0:delete b[d]}}),a.each(b,function(d,e){b[d]=a.isFunction(e)?e(c):e}),a.each(["minlength","maxlength"],function(){b[this]&&(b[this]=Number(b[this]))}),a.each(["rangelength","range"],function(){var c;b[this]&&(a.isArray(b[this])?b[this]=[Number(b[this][0]),Number(b[this][1])]:"string"==typeof b[this]&&(c=b[this].replace(/[\[\]]/g,"").split(/[\s,]+/),b[this]=[Number(c[0]),Number(c[1])]))}),a.validator.autoCreateRanges&&(b.min&&b.max&&(b.range=[b.min,b.max],delete b.min,delete b.max),b.minlength&&b.maxlength&&(b.rangelength=[b.minlength,b.maxlength],delete b.minlength,delete b.maxlength)),b},normalizeRule:function(b){if("string"==typeof b){var c={};a.each(b.split(/\s/),function(){c[this]=!0}),b=c}return b},addMethod:function(b,c,d){a.validator.methods[b]=c,a.validator.messages[b]=void 0!==d?d:a.validator.messages[b],c.length<3&&a.validator.addClassRules(b,a.validator.normalizeRule(b))},methods:{required:function(b,c,d){if(!this.depend(d,c))return"dependency-mismatch";if("select"===c.nodeName.toLowerCase()){var e=a(c).val();return e&&e.length>0}return this.checkable(c)?this.getLength(b,c)>0:a.trim(b).length>0},email:function(a,b){return this.optional(b)||/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(a)},url:function(a,b){return this.optional(b)||/^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(a)},date:function(a,b){return this.optional(b)||!/Invalid|NaN/.test(new Date(a).toString())},dateISO:function(a,b){return this.optional(b)||/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(a)},number:function(a,b){return this.optional(b)||/^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(a)},digits:function(a,b){return this.optional(b)||/^\d+$/.test(a)},creditcard:function(a,b){if(this.optional(b))return"dependency-mismatch";if(/[^0-9 \-]+/.test(a))return!1;var c,d,e=0,f=0,g=!1;if(a=a.replace(/\D/g,""),a.length<13||a.length>19)return!1;for(c=a.length-1;c>=0;c--)d=a.charAt(c),f=parseInt(d,10),g&&(f*=2)>9&&(f-=9),e+=f,g=!g;return e%10===0},minlength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(a.trim(b),c);return this.optional(c)||e>=d},maxlength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(a.trim(b),c);return this.optional(c)||d>=e},rangelength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(a.trim(b),c);return this.optional(c)||e>=d[0]&&e<=d[1]},min:function(a,b,c){return this.optional(b)||a>=c},max:function(a,b,c){return this.optional(b)||c>=a},range:function(a,b,c){return this.optional(b)||a>=c[0]&&a<=c[1]},equalTo:function(b,c,d){var e=a(d);return this.settings.onfocusout&&e.unbind(".validate-equalTo").bind("blur.validate-equalTo",function(){a(c).valid()}),b===e.val()},remote:function(b,c,d){if(this.optional(c))return"dependency-mismatch";var e,f,g=this.previousValue(c);return this.settings.messages[c.name]||(this.settings.messages[c.name]={}),g.originalMessage=this.settings.messages[c.name].remote,this.settings.messages[c.name].remote=g.message,d="string"==typeof d&&{url:d}||d,g.old===b?g.valid:(g.old=b,e=this,this.startRequest(c),f={},f[c.name]=b,a.ajax(a.extend(!0,{url:d,mode:"abort",port:"validate"+c.name,dataType:"json",data:f,context:e.currentForm,success:function(d){var f,h,i,j=d===!0||"true"===d;e.settings.messages[c.name].remote=g.originalMessage,j?(i=e.formSubmitted,e.prepareElement(c),e.formSubmitted=i,e.successList.push(c),delete e.invalid[c.name],e.showErrors()):(f={},h=d||e.defaultMessage(c,"remote"),f[c.name]=g.message=a.isFunction(h)?h(b):h,e.invalid[c.name]=!0,e.showErrors(f)),g.valid=j,e.stopRequest(c,j)}},d)),"pending")}}}),a.format=function(){throw"$.format has been deprecated. Please use $.validator.format instead."};var b,c={};a.ajaxPrefilter?a.ajaxPrefilter(function(a,b,d){var e=a.port;"abort"===a.mode&&(c[e]&&c[e].abort(),c[e]=d)}):(b=a.ajax,a.ajax=function(d){var e=("mode"in d?d:a.ajaxSettings).mode,f=("port"in d?d:a.ajaxSettings).port;return"abort"===e?(c[f]&&c[f].abort(),c[f]=b.apply(this,arguments),c[f]):b.apply(this,arguments)}),a.extend(a.fn,{validateDelegate:function(b,c,d){return this.bind(c,function(c){var e=a(c.target);return e.is(b)?d.apply(e,arguments):void 0})}})});
\ No newline at end of file
diff --git a/django_code/cloudmanager/templates/js/retina.js b/django_code/cloudmanager/templates/js/retina.js
new file mode 100644
index 0000000..7646e0b
--- /dev/null
+++ b/django_code/cloudmanager/templates/js/retina.js
@@ -0,0 +1,182 @@
+/*!
+ * Retina.js v1.3.0
+ *
+ * Copyright 2014 Imulus, LLC
+ * Released under the MIT license
+ *
+ * Retina.js is an open source script that makes it easy to serve
+ * high-resolution images to devices with retina displays.
+ */
+
+(function() {
+ var root = (typeof exports === 'undefined' ? window : exports);
+ var config = {
+ // An option to choose a suffix for 2x images
+ retinaImageSuffix : '@2x',
+
+ // Ensure Content-Type is an image before trying to load @2x image
+ // https://github.com/imulus/retinajs/pull/45)
+ check_mime_type: true,
+
+ // Resize high-resolution images to original image's pixel dimensions
+ // https://github.com/imulus/retinajs/issues/8
+ force_original_dimensions: true
+ };
+
+ function Retina() {}
+
+ root.Retina = Retina;
+
+ Retina.configure = function(options) {
+ if (options === null) {
+ options = {};
+ }
+
+ for (var prop in options) {
+ if (options.hasOwnProperty(prop)) {
+ config[prop] = options[prop];
+ }
+ }
+ };
+
+ Retina.init = function(context) {
+ if (context === null) {
+ context = root;
+ }
+
+ var existing_onload = context.onload || function(){};
+
+ context.onload = function() {
+ var images = document.getElementsByTagName('img'), retinaImages = [], i, image;
+ for (i = 0; i < images.length; i += 1) {
+ image = images[i];
+ if (!!!image.getAttributeNode('data-no-retina')) {
+ retinaImages.push(new RetinaImage(image));
+ }
+ }
+ existing_onload();
+ };
+ };
+
+ Retina.isRetina = function(){
+ var mediaQuery = '(-webkit-min-device-pixel-ratio: 1.5), (min--moz-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3/2), (min-resolution: 1.5dppx)';
+
+ if (root.devicePixelRatio > 1) {
+ return true;
+ }
+
+ if (root.matchMedia && root.matchMedia(mediaQuery).matches) {
+ return true;
+ }
+
+ return false;
+ };
+
+
+ var regexMatch = /\.\w+$/;
+ function suffixReplace (match) {
+ return config.retinaImageSuffix + match;
+ }
+
+ function RetinaImagePath(path, at_2x_path) {
+ this.path = path || '';
+ if (typeof at_2x_path !== 'undefined' && at_2x_path !== null) {
+ this.at_2x_path = at_2x_path;
+ this.perform_check = false;
+ } else {
+ if (undefined !== document.createElement) {
+ var locationObject = document.createElement('a');
+ locationObject.href = this.path;
+ locationObject.pathname = locationObject.pathname.replace(regexMatch, suffixReplace);
+ this.at_2x_path = locationObject.href;
+ } else {
+ var parts = this.path.split('?');
+ parts[0] = parts[0].replace(regexMatch, suffixReplace);
+ this.at_2x_path = parts.join('?');
+ }
+ this.perform_check = true;
+ }
+ }
+
+ root.RetinaImagePath = RetinaImagePath;
+
+ RetinaImagePath.confirmed_paths = [];
+
+ RetinaImagePath.prototype.is_external = function() {
+ return !!(this.path.match(/^https?\:/i) && !this.path.match('//' + document.domain) );
+ };
+
+ RetinaImagePath.prototype.check_2x_variant = function(callback) {
+ var http, that = this;
+ if (this.is_external()) {
+ return callback(false);
+ } else if (!this.perform_check && typeof this.at_2x_path !== 'undefined' && this.at_2x_path !== null) {
+ return callback(true);
+ } else if (this.at_2x_path in RetinaImagePath.confirmed_paths) {
+ return callback(true);
+ } else {
+ http = new XMLHttpRequest();
+ http.open('HEAD', this.at_2x_path);
+ http.onreadystatechange = function() {
+ if (http.readyState !== 4) {
+ return callback(false);
+ }
+
+ if (http.status >= 200 && http.status <= 399) {
+ if (config.check_mime_type) {
+ var type = http.getResponseHeader('Content-Type');
+ if (type === null || !type.match(/^image/i)) {
+ return callback(false);
+ }
+ }
+
+ RetinaImagePath.confirmed_paths.push(that.at_2x_path);
+ return callback(true);
+ } else {
+ return callback(false);
+ }
+ };
+ http.send();
+ }
+ };
+
+
+ function RetinaImage(el) {
+ this.el = el;
+ this.path = new RetinaImagePath(this.el.getAttribute('src'), this.el.getAttribute('data-at2x'));
+ var that = this;
+ this.path.check_2x_variant(function(hasVariant) {
+ if (hasVariant) {
+ that.swap();
+ }
+ });
+ }
+
+ root.RetinaImage = RetinaImage;
+
+ RetinaImage.prototype.swap = function(path) {
+ if (typeof path === 'undefined') {
+ path = this.path.at_2x_path;
+ }
+
+ var that = this;
+ function load() {
+ if (! that.el.complete) {
+ setTimeout(load, 5);
+ } else {
+ if (config.force_original_dimensions) {
+ that.el.setAttribute('width', that.el.offsetWidth);
+ that.el.setAttribute('height', that.el.offsetHeight);
+ }
+
+ that.el.setAttribute('src', path);
+ }
+ }
+ load();
+ };
+
+
+ if (Retina.isRetina()) {
+ Retina.init(root);
+ }
+})();
diff --git a/django_code/cloudmanager/templates/js/retina.min.js b/django_code/cloudmanager/templates/js/retina.min.js
new file mode 100644
index 0000000..da0a60d
--- /dev/null
+++ b/django_code/cloudmanager/templates/js/retina.min.js
@@ -0,0 +1,10 @@
+/*!
+ * Retina.js v1.3.0
+ *
+ * Copyright 2014 Imulus, LLC
+ * Released under the MIT license
+ *
+ * Retina.js is an open source script that makes it easy to serve
+ * high-resolution images to devices with retina displays.
+ */
+!function(){function a(){}function b(a){return f.retinaImageSuffix+a}function c(a,c){if(this.path=a||"","undefined"!=typeof c&&null!==c)this.at_2x_path=c,this.perform_check=!1;else{if(void 0!==document.createElement){var d=document.createElement("a");d.href=this.path,d.pathname=d.pathname.replace(g,b),this.at_2x_path=d.href}else{var e=this.path.split("?");e[0]=e[0].replace(g,b),this.at_2x_path=e.join("?")}this.perform_check=!0}}function d(a){this.el=a,this.path=new c(this.el.getAttribute("src"),this.el.getAttribute("data-at2x"));var b=this;this.path.check_2x_variant(function(a){a&&b.swap()})}var e="undefined"==typeof exports?window:exports,f={retinaImageSuffix:"@2x",check_mime_type:!0,force_original_dimensions:!0};e.Retina=a,a.configure=function(a){null===a&&(a={});for(var b in a)a.hasOwnProperty(b)&&(f[b]=a[b])},a.init=function(a){null===a&&(a=e);var b=a.onload||function(){};a.onload=function(){var a,c,e=document.getElementsByTagName("img"),f=[];for(a=0;a1?!0:e.matchMedia&&e.matchMedia(a).matches?!0:!1};var g=/\.\w+$/;e.RetinaImagePath=c,c.confirmed_paths=[],c.prototype.is_external=function(){return!(!this.path.match(/^https?\:/i)||this.path.match("//"+document.domain))},c.prototype.check_2x_variant=function(a){var b,d=this;return this.is_external()?a(!1):this.perform_check||"undefined"==typeof this.at_2x_path||null===this.at_2x_path?this.at_2x_path in c.confirmed_paths?a(!0):(b=new XMLHttpRequest,b.open("HEAD",this.at_2x_path),b.onreadystatechange=function(){if(4!==b.readyState)return a(!1);if(b.status>=200&&b.status<=399){if(f.check_mime_type){var e=b.getResponseHeader("Content-Type");if(null===e||!e.match(/^image/i))return a(!1)}return c.confirmed_paths.push(d.at_2x_path),a(!0)}return a(!1)},b.send(),void 0):a(!0)},e.RetinaImage=d,d.prototype.swap=function(a){function b(){c.el.complete?(f.force_original_dimensions&&(c.el.setAttribute("width",c.el.offsetWidth),c.el.setAttribute("height",c.el.offsetHeight)),c.el.setAttribute("src",a)):setTimeout(b,5)}"undefined"==typeof a&&(a=this.path.at_2x_path);var c=this;b()},a.isRetina()&&a.init(e)}();
\ No newline at end of file
diff --git a/django_code/cloudmanager/templates/js/waypoints.js b/django_code/cloudmanager/templates/js/waypoints.js
new file mode 100644
index 0000000..4f9a33b
--- /dev/null
+++ b/django_code/cloudmanager/templates/js/waypoints.js
@@ -0,0 +1,517 @@
+// Generated by CoffeeScript 1.6.2
+/*!
+jQuery Waypoints - v2.0.5
+Copyright (c) 2011-2014 Caleb Troughton
+Licensed under the MIT license.
+https://github.com/imakewebthings/jquery-waypoints/blob/master/licenses.txt
+*/
+
+
+(function() {
+ var __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
+ __slice = [].slice;
+
+ (function(root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ return define('waypoints', ['jquery'], function($) {
+ return factory($, root);
+ });
+ } else {
+ return factory(root.jQuery, root);
+ }
+ })(window, function($, window) {
+ var $w, Context, Waypoint, allWaypoints, contextCounter, contextKey, contexts, isTouch, jQMethods, methods, resizeEvent, scrollEvent, waypointCounter, waypointKey, wp, wps;
+
+ $w = $(window);
+ isTouch = __indexOf.call(window, 'ontouchstart') >= 0;
+ allWaypoints = {
+ horizontal: {},
+ vertical: {}
+ };
+ contextCounter = 1;
+ contexts = {};
+ contextKey = 'waypoints-context-id';
+ resizeEvent = 'resize.waypoints';
+ scrollEvent = 'scroll.waypoints';
+ waypointCounter = 1;
+ waypointKey = 'waypoints-waypoint-ids';
+ wp = 'waypoint';
+ wps = 'waypoints';
+ Context = (function() {
+ function Context($element) {
+ var _this = this;
+
+ this.$element = $element;
+ this.element = $element[0];
+ this.didResize = false;
+ this.didScroll = false;
+ this.id = 'context' + contextCounter++;
+ this.oldScroll = {
+ x: $element.scrollLeft(),
+ y: $element.scrollTop()
+ };
+ this.waypoints = {
+ horizontal: {},
+ vertical: {}
+ };
+ this.element[contextKey] = this.id;
+ contexts[this.id] = this;
+ $element.bind(scrollEvent, function() {
+ var scrollHandler;
+
+ if (!(_this.didScroll || isTouch)) {
+ _this.didScroll = true;
+ scrollHandler = function() {
+ _this.doScroll();
+ return _this.didScroll = false;
+ };
+ return window.setTimeout(scrollHandler, $[wps].settings.scrollThrottle);
+ }
+ });
+ $element.bind(resizeEvent, function() {
+ var resizeHandler;
+
+ if (!_this.didResize) {
+ _this.didResize = true;
+ resizeHandler = function() {
+ $[wps]('refresh');
+ return _this.didResize = false;
+ };
+ return window.setTimeout(resizeHandler, $[wps].settings.resizeThrottle);
+ }
+ });
+ }
+
+ Context.prototype.doScroll = function() {
+ var axes,
+ _this = this;
+
+ axes = {
+ horizontal: {
+ newScroll: this.$element.scrollLeft(),
+ oldScroll: this.oldScroll.x,
+ forward: 'right',
+ backward: 'left'
+ },
+ vertical: {
+ newScroll: this.$element.scrollTop(),
+ oldScroll: this.oldScroll.y,
+ forward: 'down',
+ backward: 'up'
+ }
+ };
+ if (isTouch && (!axes.vertical.oldScroll || !axes.vertical.newScroll)) {
+ $[wps]('refresh');
+ }
+ $.each(axes, function(aKey, axis) {
+ var direction, isForward, triggered;
+
+ triggered = [];
+ isForward = axis.newScroll > axis.oldScroll;
+ direction = isForward ? axis.forward : axis.backward;
+ $.each(_this.waypoints[aKey], function(wKey, waypoint) {
+ var _ref, _ref1;
+
+ if ((axis.oldScroll < (_ref = waypoint.offset) && _ref <= axis.newScroll)) {
+ return triggered.push(waypoint);
+ } else if ((axis.newScroll < (_ref1 = waypoint.offset) && _ref1 <= axis.oldScroll)) {
+ return triggered.push(waypoint);
+ }
+ });
+ triggered.sort(function(a, b) {
+ return a.offset - b.offset;
+ });
+ if (!isForward) {
+ triggered.reverse();
+ }
+ return $.each(triggered, function(i, waypoint) {
+ if (waypoint.options.continuous || i === triggered.length - 1) {
+ return waypoint.trigger([direction]);
+ }
+ });
+ });
+ return this.oldScroll = {
+ x: axes.horizontal.newScroll,
+ y: axes.vertical.newScroll
+ };
+ };
+
+ Context.prototype.refresh = function() {
+ var axes, cOffset, isWin,
+ _this = this;
+
+ isWin = $.isWindow(this.element);
+ cOffset = this.$element.offset();
+ this.doScroll();
+ axes = {
+ horizontal: {
+ contextOffset: isWin ? 0 : cOffset.left,
+ contextScroll: isWin ? 0 : this.oldScroll.x,
+ contextDimension: this.$element.width(),
+ oldScroll: this.oldScroll.x,
+ forward: 'right',
+ backward: 'left',
+ offsetProp: 'left'
+ },
+ vertical: {
+ contextOffset: isWin ? 0 : cOffset.top,
+ contextScroll: isWin ? 0 : this.oldScroll.y,
+ contextDimension: isWin ? $[wps]('viewportHeight') : this.$element.height(),
+ oldScroll: this.oldScroll.y,
+ forward: 'down',
+ backward: 'up',
+ offsetProp: 'top'
+ }
+ };
+ return $.each(axes, function(aKey, axis) {
+ return $.each(_this.waypoints[aKey], function(i, waypoint) {
+ var adjustment, elementOffset, oldOffset, _ref, _ref1;
+
+ adjustment = waypoint.options.offset;
+ oldOffset = waypoint.offset;
+ elementOffset = $.isWindow(waypoint.element) ? 0 : waypoint.$element.offset()[axis.offsetProp];
+ if ($.isFunction(adjustment)) {
+ adjustment = adjustment.apply(waypoint.element);
+ } else if (typeof adjustment === 'string') {
+ adjustment = parseFloat(adjustment);
+ if (waypoint.options.offset.indexOf('%') > -1) {
+ adjustment = Math.ceil(axis.contextDimension * adjustment / 100);
+ }
+ }
+ waypoint.offset = elementOffset - axis.contextOffset + axis.contextScroll - adjustment;
+ if ((waypoint.options.onlyOnScroll && (oldOffset != null)) || !waypoint.enabled) {
+ return;
+ }
+ if (oldOffset !== null && (oldOffset < (_ref = axis.oldScroll) && _ref <= waypoint.offset)) {
+ return waypoint.trigger([axis.backward]);
+ } else if (oldOffset !== null && (oldOffset > (_ref1 = axis.oldScroll) && _ref1 >= waypoint.offset)) {
+ return waypoint.trigger([axis.forward]);
+ } else if (oldOffset === null && axis.oldScroll >= waypoint.offset) {
+ return waypoint.trigger([axis.forward]);
+ }
+ });
+ });
+ };
+
+ Context.prototype.checkEmpty = function() {
+ if ($.isEmptyObject(this.waypoints.horizontal) && $.isEmptyObject(this.waypoints.vertical)) {
+ this.$element.unbind([resizeEvent, scrollEvent].join(' '));
+ return delete contexts[this.id];
+ }
+ };
+
+ return Context;
+
+ })();
+ Waypoint = (function() {
+ function Waypoint($element, context, options) {
+ var idList, _ref;
+
+ if (options.offset === 'bottom-in-view') {
+ options.offset = function() {
+ var contextHeight;
+
+ contextHeight = $[wps]('viewportHeight');
+ if (!$.isWindow(context.element)) {
+ contextHeight = context.$element.height();
+ }
+ return contextHeight - $(this).outerHeight();
+ };
+ }
+ this.$element = $element;
+ this.element = $element[0];
+ this.axis = options.horizontal ? 'horizontal' : 'vertical';
+ this.callback = options.handler;
+ this.context = context;
+ this.enabled = options.enabled;
+ this.id = 'waypoints' + waypointCounter++;
+ this.offset = null;
+ this.options = options;
+ context.waypoints[this.axis][this.id] = this;
+ allWaypoints[this.axis][this.id] = this;
+ idList = (_ref = this.element[waypointKey]) != null ? _ref : [];
+ idList.push(this.id);
+ this.element[waypointKey] = idList;
+ }
+
+ Waypoint.prototype.trigger = function(args) {
+ if (!this.enabled) {
+ return;
+ }
+ if (this.callback != null) {
+ this.callback.apply(this.element, args);
+ }
+ if (this.options.triggerOnce) {
+ return this.destroy();
+ }
+ };
+
+ Waypoint.prototype.disable = function() {
+ return this.enabled = false;
+ };
+
+ Waypoint.prototype.enable = function() {
+ this.context.refresh();
+ return this.enabled = true;
+ };
+
+ Waypoint.prototype.destroy = function() {
+ delete allWaypoints[this.axis][this.id];
+ delete this.context.waypoints[this.axis][this.id];
+ return this.context.checkEmpty();
+ };
+
+ Waypoint.getWaypointsByElement = function(element) {
+ var all, ids;
+
+ ids = element[waypointKey];
+ if (!ids) {
+ return [];
+ }
+ all = $.extend({}, allWaypoints.horizontal, allWaypoints.vertical);
+ return $.map(ids, function(id) {
+ return all[id];
+ });
+ };
+
+ return Waypoint;
+
+ })();
+ methods = {
+ init: function(f, options) {
+ var _ref;
+
+ options = $.extend({}, $.fn[wp].defaults, options);
+ if ((_ref = options.handler) == null) {
+ options.handler = f;
+ }
+ this.each(function() {
+ var $this, context, contextElement, _ref1;
+
+ $this = $(this);
+ contextElement = (_ref1 = options.context) != null ? _ref1 : $.fn[wp].defaults.context;
+ if (!$.isWindow(contextElement)) {
+ contextElement = $this.closest(contextElement);
+ }
+ contextElement = $(contextElement);
+ context = contexts[contextElement[0][contextKey]];
+ if (!context) {
+ context = new Context(contextElement);
+ }
+ return new Waypoint($this, context, options);
+ });
+ $[wps]('refresh');
+ return this;
+ },
+ disable: function() {
+ return methods._invoke.call(this, 'disable');
+ },
+ enable: function() {
+ return methods._invoke.call(this, 'enable');
+ },
+ destroy: function() {
+ return methods._invoke.call(this, 'destroy');
+ },
+ prev: function(axis, selector) {
+ return methods._traverse.call(this, axis, selector, function(stack, index, waypoints) {
+ if (index > 0) {
+ return stack.push(waypoints[index - 1]);
+ }
+ });
+ },
+ next: function(axis, selector) {
+ return methods._traverse.call(this, axis, selector, function(stack, index, waypoints) {
+ if (index < waypoints.length - 1) {
+ return stack.push(waypoints[index + 1]);
+ }
+ });
+ },
+ _traverse: function(axis, selector, push) {
+ var stack, waypoints;
+
+ if (axis == null) {
+ axis = 'vertical';
+ }
+ if (selector == null) {
+ selector = window;
+ }
+ waypoints = jQMethods.aggregate(selector);
+ stack = [];
+ this.each(function() {
+ var index;
+
+ index = $.inArray(this, waypoints[axis]);
+ return push(stack, index, waypoints[axis]);
+ });
+ return this.pushStack(stack);
+ },
+ _invoke: function(method) {
+ this.each(function() {
+ var waypoints;
+
+ waypoints = Waypoint.getWaypointsByElement(this);
+ return $.each(waypoints, function(i, waypoint) {
+ waypoint[method]();
+ return true;
+ });
+ });
+ return this;
+ }
+ };
+ $.fn[wp] = function() {
+ var args, method;
+
+ method = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
+ if (methods[method]) {
+ return methods[method].apply(this, args);
+ } else if ($.isFunction(method)) {
+ return methods.init.apply(this, arguments);
+ } else if ($.isPlainObject(method)) {
+ return methods.init.apply(this, [null, method]);
+ } else if (!method) {
+ return $.error("jQuery Waypoints needs a callback function or handler option.");
+ } else {
+ return $.error("The " + method + " method does not exist in jQuery Waypoints.");
+ }
+ };
+ $.fn[wp].defaults = {
+ context: window,
+ continuous: true,
+ enabled: true,
+ horizontal: false,
+ offset: 0,
+ triggerOnce: false
+ };
+ jQMethods = {
+ refresh: function() {
+ return $.each(contexts, function(i, context) {
+ return context.refresh();
+ });
+ },
+ viewportHeight: function() {
+ var _ref;
+
+ return (_ref = window.innerHeight) != null ? _ref : $w.height();
+ },
+ aggregate: function(contextSelector) {
+ var collection, waypoints, _ref;
+
+ collection = allWaypoints;
+ if (contextSelector) {
+ collection = (_ref = contexts[$(contextSelector)[0][contextKey]]) != null ? _ref.waypoints : void 0;
+ }
+ if (!collection) {
+ return [];
+ }
+ waypoints = {
+ horizontal: [],
+ vertical: []
+ };
+ $.each(waypoints, function(axis, arr) {
+ $.each(collection[axis], function(key, waypoint) {
+ return arr.push(waypoint);
+ });
+ arr.sort(function(a, b) {
+ return a.offset - b.offset;
+ });
+ waypoints[axis] = $.map(arr, function(waypoint) {
+ return waypoint.element;
+ });
+ return waypoints[axis] = $.unique(waypoints[axis]);
+ });
+ return waypoints;
+ },
+ above: function(contextSelector) {
+ if (contextSelector == null) {
+ contextSelector = window;
+ }
+ return jQMethods._filter(contextSelector, 'vertical', function(context, waypoint) {
+ return waypoint.offset <= context.oldScroll.y;
+ });
+ },
+ below: function(contextSelector) {
+ if (contextSelector == null) {
+ contextSelector = window;
+ }
+ return jQMethods._filter(contextSelector, 'vertical', function(context, waypoint) {
+ return waypoint.offset > context.oldScroll.y;
+ });
+ },
+ left: function(contextSelector) {
+ if (contextSelector == null) {
+ contextSelector = window;
+ }
+ return jQMethods._filter(contextSelector, 'horizontal', function(context, waypoint) {
+ return waypoint.offset <= context.oldScroll.x;
+ });
+ },
+ right: function(contextSelector) {
+ if (contextSelector == null) {
+ contextSelector = window;
+ }
+ return jQMethods._filter(contextSelector, 'horizontal', function(context, waypoint) {
+ return waypoint.offset > context.oldScroll.x;
+ });
+ },
+ enable: function() {
+ return jQMethods._invoke('enable');
+ },
+ disable: function() {
+ return jQMethods._invoke('disable');
+ },
+ destroy: function() {
+ return jQMethods._invoke('destroy');
+ },
+ extendFn: function(methodName, f) {
+ return methods[methodName] = f;
+ },
+ _invoke: function(method) {
+ var waypoints;
+
+ waypoints = $.extend({}, allWaypoints.vertical, allWaypoints.horizontal);
+ return $.each(waypoints, function(key, waypoint) {
+ waypoint[method]();
+ return true;
+ });
+ },
+ _filter: function(selector, axis, test) {
+ var context, waypoints;
+
+ context = contexts[$(selector)[0][contextKey]];
+ if (!context) {
+ return [];
+ }
+ waypoints = [];
+ $.each(context.waypoints[axis], function(i, waypoint) {
+ if (test(context, waypoint)) {
+ return waypoints.push(waypoint);
+ }
+ });
+ waypoints.sort(function(a, b) {
+ return a.offset - b.offset;
+ });
+ return $.map(waypoints, function(waypoint) {
+ return waypoint.element;
+ });
+ }
+ };
+ $[wps] = function() {
+ var args, method;
+
+ method = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
+ if (jQMethods[method]) {
+ return jQMethods[method].apply(null, args);
+ } else {
+ return jQMethods.aggregate.call(null, method);
+ }
+ };
+ $[wps].settings = {
+ resizeThrottle: 100,
+ scrollThrottle: 30
+ };
+ return $w.on('load.waypoints', function() {
+ return $[wps]('refresh');
+ });
+ });
+
+}).call(this);
diff --git a/django_code/cloudmanager/templates/js/waypoints.min.js b/django_code/cloudmanager/templates/js/waypoints.min.js
new file mode 100644
index 0000000..b9098f8
--- /dev/null
+++ b/django_code/cloudmanager/templates/js/waypoints.min.js
@@ -0,0 +1,8 @@
+// Generated by CoffeeScript 1.6.2
+/*!
+jQuery Waypoints - v2.0.5
+Copyright (c) 2011-2014 Caleb Troughton
+Licensed under the MIT license.
+https://github.com/imakewebthings/jquery-waypoints/blob/master/licenses.txt
+*/
+(function(){var t=[].indexOf||function(t){for(var e=0,n=this.length;e=0;s={horizontal:{},vertical:{}};f=1;c={};u="waypoints-context-id";p="resize.waypoints";y="scroll.waypoints";v=1;w="waypoints-waypoint-ids";g="waypoint";m="waypoints";o=function(){function t(t){var e=this;this.$element=t;this.element=t[0];this.didResize=false;this.didScroll=false;this.id="context"+f++;this.oldScroll={x:t.scrollLeft(),y:t.scrollTop()};this.waypoints={horizontal:{},vertical:{}};this.element[u]=this.id;c[this.id]=this;t.bind(y,function(){var t;if(!(e.didScroll||a)){e.didScroll=true;t=function(){e.doScroll();return e.didScroll=false};return r.setTimeout(t,n[m].settings.scrollThrottle)}});t.bind(p,function(){var t;if(!e.didResize){e.didResize=true;t=function(){n[m]("refresh");return e.didResize=false};return r.setTimeout(t,n[m].settings.resizeThrottle)}})}t.prototype.doScroll=function(){var t,e=this;t={horizontal:{newScroll:this.$element.scrollLeft(),oldScroll:this.oldScroll.x,forward:"right",backward:"left"},vertical:{newScroll:this.$element.scrollTop(),oldScroll:this.oldScroll.y,forward:"down",backward:"up"}};if(a&&(!t.vertical.oldScroll||!t.vertical.newScroll)){n[m]("refresh")}n.each(t,function(t,r){var i,o,l;l=[];o=r.newScroll>r.oldScroll;i=o?r.forward:r.backward;n.each(e.waypoints[t],function(t,e){var n,i;if(r.oldScroll<(n=e.offset)&&n<=r.newScroll){return l.push(e)}else if(r.newScroll<(i=e.offset)&&i<=r.oldScroll){return l.push(e)}});l.sort(function(t,e){return t.offset-e.offset});if(!o){l.reverse()}return n.each(l,function(t,e){if(e.options.continuous||t===l.length-1){return e.trigger([i])}})});return this.oldScroll={x:t.horizontal.newScroll,y:t.vertical.newScroll}};t.prototype.refresh=function(){var t,e,r,i=this;r=n.isWindow(this.element);e=this.$element.offset();this.doScroll();t={horizontal:{contextOffset:r?0:e.left,contextScroll:r?0:this.oldScroll.x,contextDimension:this.$element.width(),oldScroll:this.oldScroll.x,forward:"right",backward:"left",offsetProp:"left"},vertical:{contextOffset:r?0:e.top,contextScroll:r?0:this.oldScroll.y,contextDimension:r?n[m]("viewportHeight"):this.$element.height(),oldScroll:this.oldScroll.y,forward:"down",backward:"up",offsetProp:"top"}};return n.each(t,function(t,e){return n.each(i.waypoints[t],function(t,r){var i,o,l,s,f;i=r.options.offset;l=r.offset;o=n.isWindow(r.element)?0:r.$element.offset()[e.offsetProp];if(n.isFunction(i)){i=i.apply(r.element)}else if(typeof i==="string"){i=parseFloat(i);if(r.options.offset.indexOf("%")>-1){i=Math.ceil(e.contextDimension*i/100)}}r.offset=o-e.contextOffset+e.contextScroll-i;if(r.options.onlyOnScroll&&l!=null||!r.enabled){return}if(l!==null&&l<(s=e.oldScroll)&&s<=r.offset){return r.trigger([e.backward])}else if(l!==null&&l>(f=e.oldScroll)&&f>=r.offset){return r.trigger([e.forward])}else if(l===null&&e.oldScroll>=r.offset){return r.trigger([e.forward])}})})};t.prototype.checkEmpty=function(){if(n.isEmptyObject(this.waypoints.horizontal)&&n.isEmptyObject(this.waypoints.vertical)){this.$element.unbind([p,y].join(" "));return delete c[this.id]}};return t}();l=function(){function t(t,e,r){var i,o;if(r.offset==="bottom-in-view"){r.offset=function(){var t;t=n[m]("viewportHeight");if(!n.isWindow(e.element)){t=e.$element.height()}return t-n(this).outerHeight()}}this.$element=t;this.element=t[0];this.axis=r.horizontal?"horizontal":"vertical";this.callback=r.handler;this.context=e;this.enabled=r.enabled;this.id="waypoints"+v++;this.offset=null;this.options=r;e.waypoints[this.axis][this.id]=this;s[this.axis][this.id]=this;i=(o=this.element[w])!=null?o:[];i.push(this.id);this.element[w]=i}t.prototype.trigger=function(t){if(!this.enabled){return}if(this.callback!=null){this.callback.apply(this.element,t)}if(this.options.triggerOnce){return this.destroy()}};t.prototype.disable=function(){return this.enabled=false};t.prototype.enable=function(){this.context.refresh();return this.enabled=true};t.prototype.destroy=function(){delete s[this.axis][this.id];delete this.context.waypoints[this.axis][this.id];return this.context.checkEmpty()};t.getWaypointsByElement=function(t){var e,r;r=t[w];if(!r){return[]}e=n.extend({},s.horizontal,s.vertical);return n.map(r,function(t){return e[t]})};return t}();d={init:function(t,e){var r;e=n.extend({},n.fn[g].defaults,e);if((r=e.handler)==null){e.handler=t}this.each(function(){var t,r,i,s;t=n(this);i=(s=e.context)!=null?s:n.fn[g].defaults.context;if(!n.isWindow(i)){i=t.closest(i)}i=n(i);r=c[i[0][u]];if(!r){r=new o(i)}return new l(t,r,e)});n[m]("refresh");return this},disable:function(){return d._invoke.call(this,"disable")},enable:function(){return d._invoke.call(this,"enable")},destroy:function(){return d._invoke.call(this,"destroy")},prev:function(t,e){return d._traverse.call(this,t,e,function(t,e,n){if(e>0){return t.push(n[e-1])}})},next:function(t,e){return d._traverse.call(this,t,e,function(t,e,n){if(et.oldScroll.y})},left:function(t){if(t==null){t=r}return h._filter(t,"horizontal",function(t,e){return e.offset<=t.oldScroll.x})},right:function(t){if(t==null){t=r}return h._filter(t,"horizontal",function(t,e){return e.offset>t.oldScroll.x})},enable:function(){return h._invoke("enable")},disable:function(){return h._invoke("disable")},destroy:function(){return h._invoke("destroy")},extendFn:function(t,e){return d[t]=e},_invoke:function(t){var e;e=n.extend({},s.vertical,s.horizontal);return n.each(e,function(e,n){n[t]();return true})},_filter:function(t,e,r){var i,o;i=c[n(t)[0][u]];if(!i){return[]}o=[];n.each(i.waypoints[e],function(t,e){if(r(i,e)){return o.push(e)}});o.sort(function(t,e){return t.offset-e.offset});return n.map(o,function(t){return t.element})}};n[m]=function(){var t,n;n=arguments[0],t=2<=arguments.length?e.call(arguments,1):[];if(h[n]){return h[n].apply(null,t)}else{return h.aggregate.call(null,n)}};n[m].settings={resizeThrottle:100,scrollThrottle:30};return i.on("load.waypoints",function(){return n[m]("refresh")})})}).call(this);
\ No newline at end of file
diff --git a/django_code/cloudmanager/templates/js/wow.js b/django_code/cloudmanager/templates/js/wow.js
new file mode 100644
index 0000000..d71bafb
--- /dev/null
+++ b/django_code/cloudmanager/templates/js/wow.js
@@ -0,0 +1,456 @@
+(function() {
+ var MutationObserver, Util, WeakMap, getComputedStyle, getComputedStyleRX,
+ __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
+ __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
+
+ Util = (function() {
+ function Util() {}
+
+ Util.prototype.extend = function(custom, defaults) {
+ var key, value;
+ for (key in defaults) {
+ value = defaults[key];
+ if (custom[key] == null) {
+ custom[key] = value;
+ }
+ }
+ return custom;
+ };
+
+ Util.prototype.isMobile = function(agent) {
+ return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(agent);
+ };
+
+ Util.prototype.addEvent = function(elem, event, fn) {
+ if (elem.addEventListener != null) {
+ return elem.addEventListener(event, fn, false);
+ } else if (elem.attachEvent != null) {
+ return elem.attachEvent("on" + event, fn);
+ } else {
+ return elem[event] = fn;
+ }
+ };
+
+ Util.prototype.removeEvent = function(elem, event, fn) {
+ if (elem.removeEventListener != null) {
+ return elem.removeEventListener(event, fn, false);
+ } else if (elem.detachEvent != null) {
+ return elem.detachEvent("on" + event, fn);
+ } else {
+ return delete elem[event];
+ }
+ };
+
+ Util.prototype.innerHeight = function() {
+ if ('innerHeight' in window) {
+ return window.innerHeight;
+ } else {
+ return document.documentElement.clientHeight;
+ }
+ };
+
+ return Util;
+
+ })();
+
+ WeakMap = this.WeakMap || this.MozWeakMap || (WeakMap = (function() {
+ function WeakMap() {
+ this.keys = [];
+ this.values = [];
+ }
+
+ WeakMap.prototype.get = function(key) {
+ var i, item, _i, _len, _ref;
+ _ref = this.keys;
+ for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
+ item = _ref[i];
+ if (item === key) {
+ return this.values[i];
+ }
+ }
+ };
+
+ WeakMap.prototype.set = function(key, value) {
+ var i, item, _i, _len, _ref;
+ _ref = this.keys;
+ for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
+ item = _ref[i];
+ if (item === key) {
+ this.values[i] = value;
+ return;
+ }
+ }
+ this.keys.push(key);
+ return this.values.push(value);
+ };
+
+ return WeakMap;
+
+ })());
+
+ MutationObserver = this.MutationObserver || this.WebkitMutationObserver || this.MozMutationObserver || (MutationObserver = (function() {
+ function MutationObserver() {
+ if (typeof console !== "undefined" && console !== null) {
+ console.warn('MutationObserver is not supported by your browser.');
+ }
+ if (typeof console !== "undefined" && console !== null) {
+ console.warn('WOW.js cannot detect dom mutations, please call .sync() after loading new content.');
+ }
+ }
+
+ MutationObserver.notSupported = true;
+
+ MutationObserver.prototype.observe = function() {};
+
+ return MutationObserver;
+
+ })());
+
+ getComputedStyle = this.getComputedStyle || function(el, pseudo) {
+ this.getPropertyValue = function(prop) {
+ var _ref;
+ if (prop === 'float') {
+ prop = 'styleFloat';
+ }
+ if (getComputedStyleRX.test(prop)) {
+ prop.replace(getComputedStyleRX, function(_, char) {
+ return char.toUpperCase();
+ });
+ }
+ return ((_ref = el.currentStyle) != null ? _ref[prop] : void 0) || null;
+ };
+ return this;
+ };
+
+ getComputedStyleRX = /(\-([a-z]){1})/g;
+
+ this.WOW = (function() {
+ WOW.prototype.defaults = {
+ boxClass: 'wow',
+ animateClass: 'animated',
+ offset: 0,
+ mobile: true,
+ live: true
+ };
+
+ function WOW(options) {
+ if (options == null) {
+ options = {};
+ }
+ this.scrollCallback = __bind(this.scrollCallback, this);
+ this.scrollHandler = __bind(this.scrollHandler, this);
+ this.start = __bind(this.start, this);
+ this.scrolled = true;
+ this.config = this.util().extend(options, this.defaults);
+ this.animationNameCache = new WeakMap();
+ }
+
+ WOW.prototype.init = function() {
+ var _ref;
+ this.element = window.document.documentElement;
+ if ((_ref = document.readyState) === "interactive" || _ref === "complete") {
+ this.start();
+ } else {
+ this.util().addEvent(document, 'DOMContentLoaded', this.start);
+ }
+ return this.finished = [];
+ };
+
+ WOW.prototype.start = function() {
+ var box, _i, _len, _ref;
+ this.stopped = false;
+ this.boxes = (function() {
+ var _i, _len, _ref, _results;
+ _ref = this.element.querySelectorAll("." + this.config.boxClass);
+ _results = [];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ box = _ref[_i];
+ _results.push(box);
+ }
+ return _results;
+ }).call(this);
+ this.all = (function() {
+ var _i, _len, _ref, _results;
+ _ref = this.boxes;
+ _results = [];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ box = _ref[_i];
+ _results.push(box);
+ }
+ return _results;
+ }).call(this);
+ if (this.boxes.length) {
+ if (this.disabled()) {
+ this.resetStyle();
+ } else {
+ _ref = this.boxes;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ box = _ref[_i];
+ this.applyStyle(box, true);
+ }
+ }
+ }
+ if (!this.disabled()) {
+ this.util().addEvent(window, 'scroll', this.scrollHandler);
+ this.util().addEvent(window, 'resize', this.scrollHandler);
+ this.interval = setInterval(this.scrollCallback, 50);
+ }
+ if (this.config.live) {
+ return new MutationObserver((function(_this) {
+ return function(records) {
+ var node, record, _j, _len1, _results;
+ _results = [];
+ for (_j = 0, _len1 = records.length; _j < _len1; _j++) {
+ record = records[_j];
+ _results.push((function() {
+ var _k, _len2, _ref1, _results1;
+ _ref1 = record.addedNodes || [];
+ _results1 = [];
+ for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) {
+ node = _ref1[_k];
+ _results1.push(this.doSync(node));
+ }
+ return _results1;
+ }).call(_this));
+ }
+ return _results;
+ };
+ })(this)).observe(document.body, {
+ childList: true,
+ subtree: true
+ });
+ }
+ };
+
+ WOW.prototype.stop = function() {
+ this.stopped = true;
+ this.util().removeEvent(window, 'scroll', this.scrollHandler);
+ this.util().removeEvent(window, 'resize', this.scrollHandler);
+ if (this.interval != null) {
+ return clearInterval(this.interval);
+ }
+ };
+
+ WOW.prototype.sync = function(element) {
+ if (MutationObserver.notSupported) {
+ return this.doSync(this.element);
+ }
+ };
+
+ WOW.prototype.doSync = function(element) {
+ var box, _i, _len, _ref, _results;
+ if (element == null) {
+ element = this.element;
+ }
+ if (element.nodeType !== 1) {
+ return;
+ }
+ element = element.parentNode || element;
+ _ref = element.querySelectorAll("." + this.config.boxClass);
+ _results = [];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ box = _ref[_i];
+ if (__indexOf.call(this.all, box) < 0) {
+ this.boxes.push(box);
+ this.all.push(box);
+ if (this.stopped || this.disabled()) {
+ this.resetStyle();
+ } else {
+ this.applyStyle(box, true);
+ }
+ _results.push(this.scrolled = true);
+ } else {
+ _results.push(void 0);
+ }
+ }
+ return _results;
+ };
+
+ WOW.prototype.show = function(box) {
+ this.applyStyle(box);
+ return box.className = "" + box.className + " " + this.config.animateClass;
+ };
+
+ WOW.prototype.applyStyle = function(box, hidden) {
+ var delay, duration, iteration;
+ duration = box.getAttribute('data-wow-duration');
+ delay = box.getAttribute('data-wow-delay');
+ iteration = box.getAttribute('data-wow-iteration');
+ return this.animate((function(_this) {
+ return function() {
+ return _this.customStyle(box, hidden, duration, delay, iteration);
+ };
+ })(this));
+ };
+
+ WOW.prototype.animate = (function() {
+ if ('requestAnimationFrame' in window) {
+ return function(callback) {
+ return window.requestAnimationFrame(callback);
+ };
+ } else {
+ return function(callback) {
+ return callback();
+ };
+ }
+ })();
+
+ WOW.prototype.resetStyle = function() {
+ var box, _i, _len, _ref, _results;
+ _ref = this.boxes;
+ _results = [];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ box = _ref[_i];
+ _results.push(box.style.visibility = 'visible');
+ }
+ return _results;
+ };
+
+ WOW.prototype.customStyle = function(box, hidden, duration, delay, iteration) {
+ if (hidden) {
+ this.cacheAnimationName(box);
+ }
+ box.style.visibility = hidden ? 'hidden' : 'visible';
+ if (duration) {
+ this.vendorSet(box.style, {
+ animationDuration: duration
+ });
+ }
+ if (delay) {
+ this.vendorSet(box.style, {
+ animationDelay: delay
+ });
+ }
+ if (iteration) {
+ this.vendorSet(box.style, {
+ animationIterationCount: iteration
+ });
+ }
+ this.vendorSet(box.style, {
+ animationName: hidden ? 'none' : this.cachedAnimationName(box)
+ });
+ return box;
+ };
+
+ WOW.prototype.vendors = ["moz", "webkit"];
+
+ WOW.prototype.vendorSet = function(elem, properties) {
+ var name, value, vendor, _results;
+ _results = [];
+ for (name in properties) {
+ value = properties[name];
+ elem["" + name] = value;
+ _results.push((function() {
+ var _i, _len, _ref, _results1;
+ _ref = this.vendors;
+ _results1 = [];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ vendor = _ref[_i];
+ _results1.push(elem["" + vendor + (name.charAt(0).toUpperCase()) + (name.substr(1))] = value);
+ }
+ return _results1;
+ }).call(this));
+ }
+ return _results;
+ };
+
+ WOW.prototype.vendorCSS = function(elem, property) {
+ var result, style, vendor, _i, _len, _ref;
+ style = getComputedStyle(elem);
+ result = style.getPropertyCSSValue(property);
+ _ref = this.vendors;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ vendor = _ref[_i];
+ result = result || style.getPropertyCSSValue("-" + vendor + "-" + property);
+ }
+ return result;
+ };
+
+ WOW.prototype.animationName = function(box) {
+ var animationName;
+ try {
+ animationName = this.vendorCSS(box, 'animation-name').cssText;
+ } catch (_error) {
+ animationName = getComputedStyle(box).getPropertyValue('animation-name');
+ }
+ if (animationName === 'none') {
+ return '';
+ } else {
+ return animationName;
+ }
+ };
+
+ WOW.prototype.cacheAnimationName = function(box) {
+ return this.animationNameCache.set(box, this.animationName(box));
+ };
+
+ WOW.prototype.cachedAnimationName = function(box) {
+ return this.animationNameCache.get(box);
+ };
+
+ WOW.prototype.scrollHandler = function() {
+ return this.scrolled = true;
+ };
+
+ WOW.prototype.scrollCallback = function() {
+ var box;
+ if (this.scrolled) {
+ this.scrolled = false;
+ this.boxes = (function() {
+ var _i, _len, _ref, _results;
+ _ref = this.boxes;
+ _results = [];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ box = _ref[_i];
+ if (!(box)) {
+ continue;
+ }
+ if (this.isVisible(box)) {
+ this.show(box);
+ continue;
+ }
+ _results.push(box);
+ }
+ return _results;
+ }).call(this);
+ if (!(this.boxes.length || this.config.live)) {
+ return this.stop();
+ }
+ }
+ };
+
+ WOW.prototype.offsetTop = function(element) {
+ var top;
+ while (element.offsetTop === void 0) {
+ element = element.parentNode;
+ }
+ top = element.offsetTop;
+ while (element = element.offsetParent) {
+ top += element.offsetTop;
+ }
+ return top;
+ };
+
+ WOW.prototype.isVisible = function(box) {
+ var bottom, offset, top, viewBottom, viewTop;
+ offset = box.getAttribute('data-wow-offset') || this.config.offset;
+ viewTop = window.pageYOffset;
+ viewBottom = viewTop + Math.min(this.element.clientHeight, this.util().innerHeight()) - offset;
+ top = this.offsetTop(box);
+ bottom = top + box.clientHeight;
+ return top <= viewBottom && bottom >= viewTop;
+ };
+
+ WOW.prototype.util = function() {
+ return this._util != null ? this._util : this._util = new Util();
+ };
+
+ WOW.prototype.disabled = function() {
+ return !this.config.mobile && this.util().isMobile(navigator.userAgent);
+ };
+
+ return WOW;
+
+ })();
+
+}).call(this);
diff --git a/django_code/cloudmanager/templates/js/wow.min.js b/django_code/cloudmanager/templates/js/wow.min.js
new file mode 100644
index 0000000..2124a96
--- /dev/null
+++ b/django_code/cloudmanager/templates/js/wow.min.js
@@ -0,0 +1,2 @@
+/*! WOW - v1.0.2 - 2014-10-28
+* Copyright (c) 2014 Matthieu Aussaguel; Licensed MIT */(function(){var a,b,c,d,e,f=function(a,b){return function(){return a.apply(b,arguments)}},g=[].indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(b in this&&this[b]===a)return b;return-1};b=function(){function a(){}return a.prototype.extend=function(a,b){var c,d;for(c in b)d=b[c],null==a[c]&&(a[c]=d);return a},a.prototype.isMobile=function(a){return/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(a)},a.prototype.addEvent=function(a,b,c){return null!=a.addEventListener?a.addEventListener(b,c,!1):null!=a.attachEvent?a.attachEvent("on"+b,c):a[b]=c},a.prototype.removeEvent=function(a,b,c){return null!=a.removeEventListener?a.removeEventListener(b,c,!1):null!=a.detachEvent?a.detachEvent("on"+b,c):delete a[b]},a.prototype.innerHeight=function(){return"innerHeight"in window?window.innerHeight:document.documentElement.clientHeight},a}(),c=this.WeakMap||this.MozWeakMap||(c=function(){function a(){this.keys=[],this.values=[]}return a.prototype.get=function(a){var b,c,d,e,f;for(f=this.keys,b=d=0,e=f.length;e>d;b=++d)if(c=f[b],c===a)return this.values[b]},a.prototype.set=function(a,b){var c,d,e,f,g;for(g=this.keys,c=e=0,f=g.length;f>e;c=++e)if(d=g[c],d===a)return void(this.values[c]=b);return this.keys.push(a),this.values.push(b)},a}()),a=this.MutationObserver||this.WebkitMutationObserver||this.MozMutationObserver||(a=function(){function a(){"undefined"!=typeof console&&null!==console&&console.warn("MutationObserver is not supported by your browser."),"undefined"!=typeof console&&null!==console&&console.warn("WOW.js cannot detect dom mutations, please call .sync() after loading new content.")}return a.notSupported=!0,a.prototype.observe=function(){},a}()),d=this.getComputedStyle||function(a){return this.getPropertyValue=function(b){var c;return"float"===b&&(b="styleFloat"),e.test(b)&&b.replace(e,function(a,b){return b.toUpperCase()}),(null!=(c=a.currentStyle)?c[b]:void 0)||null},this},e=/(\-([a-z]){1})/g,this.WOW=function(){function e(a){null==a&&(a={}),this.scrollCallback=f(this.scrollCallback,this),this.scrollHandler=f(this.scrollHandler,this),this.start=f(this.start,this),this.scrolled=!0,this.config=this.util().extend(a,this.defaults),this.animationNameCache=new c}return e.prototype.defaults={boxClass:"wow",animateClass:"animated",offset:0,mobile:!0,live:!0},e.prototype.init=function(){var a;return this.element=window.document.documentElement,"interactive"===(a=document.readyState)||"complete"===a?this.start():this.util().addEvent(document,"DOMContentLoaded",this.start),this.finished=[]},e.prototype.start=function(){var b,c,d,e;if(this.stopped=!1,this.boxes=function(){var a,c,d,e;for(d=this.element.querySelectorAll("."+this.config.boxClass),e=[],a=0,c=d.length;c>a;a++)b=d[a],e.push(b);return e}.call(this),this.all=function(){var a,c,d,e;for(d=this.boxes,e=[],a=0,c=d.length;c>a;a++)b=d[a],e.push(b);return e}.call(this),this.boxes.length)if(this.disabled())this.resetStyle();else for(e=this.boxes,c=0,d=e.length;d>c;c++)b=e[c],this.applyStyle(b,!0);return this.disabled()||(this.util().addEvent(window,"scroll",this.scrollHandler),this.util().addEvent(window,"resize",this.scrollHandler),this.interval=setInterval(this.scrollCallback,50)),this.config.live?new a(function(a){return function(b){var c,d,e,f,g;for(g=[],e=0,f=b.length;f>e;e++)d=b[e],g.push(function(){var a,b,e,f;for(e=d.addedNodes||[],f=[],a=0,b=e.length;b>a;a++)c=e[a],f.push(this.doSync(c));return f}.call(a));return g}}(this)).observe(document.body,{childList:!0,subtree:!0}):void 0},e.prototype.stop=function(){return this.stopped=!0,this.util().removeEvent(window,"scroll",this.scrollHandler),this.util().removeEvent(window,"resize",this.scrollHandler),null!=this.interval?clearInterval(this.interval):void 0},e.prototype.sync=function(){return a.notSupported?this.doSync(this.element):void 0},e.prototype.doSync=function(a){var b,c,d,e,f;if(null==a&&(a=this.element),1===a.nodeType){for(a=a.parentNode||a,e=a.querySelectorAll("."+this.config.boxClass),f=[],c=0,d=e.length;d>c;c++)b=e[c],g.call(this.all,b)<0?(this.boxes.push(b),this.all.push(b),this.stopped||this.disabled()?this.resetStyle():this.applyStyle(b,!0),f.push(this.scrolled=!0)):f.push(void 0);return f}},e.prototype.show=function(a){return this.applyStyle(a),a.className=""+a.className+" "+this.config.animateClass},e.prototype.applyStyle=function(a,b){var c,d,e;return d=a.getAttribute("data-wow-duration"),c=a.getAttribute("data-wow-delay"),e=a.getAttribute("data-wow-iteration"),this.animate(function(f){return function(){return f.customStyle(a,b,d,c,e)}}(this))},e.prototype.animate=function(){return"requestAnimationFrame"in window?function(a){return window.requestAnimationFrame(a)}:function(a){return a()}}(),e.prototype.resetStyle=function(){var a,b,c,d,e;for(d=this.boxes,e=[],b=0,c=d.length;c>b;b++)a=d[b],e.push(a.style.visibility="visible");return e},e.prototype.customStyle=function(a,b,c,d,e){return b&&this.cacheAnimationName(a),a.style.visibility=b?"hidden":"visible",c&&this.vendorSet(a.style,{animationDuration:c}),d&&this.vendorSet(a.style,{animationDelay:d}),e&&this.vendorSet(a.style,{animationIterationCount:e}),this.vendorSet(a.style,{animationName:b?"none":this.cachedAnimationName(a)}),a},e.prototype.vendors=["moz","webkit"],e.prototype.vendorSet=function(a,b){var c,d,e,f;f=[];for(c in b)d=b[c],a[""+c]=d,f.push(function(){var b,f,g,h;for(g=this.vendors,h=[],b=0,f=g.length;f>b;b++)e=g[b],h.push(a[""+e+c.charAt(0).toUpperCase()+c.substr(1)]=d);return h}.call(this));return f},e.prototype.vendorCSS=function(a,b){var c,e,f,g,h,i;for(e=d(a),c=e.getPropertyCSSValue(b),i=this.vendors,g=0,h=i.length;h>g;g++)f=i[g],c=c||e.getPropertyCSSValue("-"+f+"-"+b);return c},e.prototype.animationName=function(a){var b;try{b=this.vendorCSS(a,"animation-name").cssText}catch(c){b=d(a).getPropertyValue("animation-name")}return"none"===b?"":b},e.prototype.cacheAnimationName=function(a){return this.animationNameCache.set(a,this.animationName(a))},e.prototype.cachedAnimationName=function(a){return this.animationNameCache.get(a)},e.prototype.scrollHandler=function(){return this.scrolled=!0},e.prototype.scrollCallback=function(){var a;return!this.scrolled||(this.scrolled=!1,this.boxes=function(){var b,c,d,e;for(d=this.boxes,e=[],b=0,c=d.length;c>b;b++)a=d[b],a&&(this.isVisible(a)?this.show(a):e.push(a));return e}.call(this),this.boxes.length||this.config.live)?void 0:this.stop()},e.prototype.offsetTop=function(a){for(var b;void 0===a.offsetTop;)a=a.parentNode;for(b=a.offsetTop;a=a.offsetParent;)b+=a.offsetTop;return b},e.prototype.isVisible=function(a){var b,c,d,e,f;return c=a.getAttribute("data-wow-offset")||this.config.offset,f=window.pageYOffset,e=f+Math.min(this.element.clientHeight,this.util().innerHeight())-c,d=this.offsetTop(a),b=d+a.clientHeight,e>=d&&b>=f},e.prototype.util=function(){return null!=this._util?this._util:this._util=new b},e.prototype.disabled=function(){return!this.config.mobile&&this.util().isMobile(navigator.userAgent)},e}()}).call(this);
\ No newline at end of file
diff --git a/django_code/django_code/cloudmanager/templates/Favicon.png b/django_code/django_code/cloudmanager/templates/Favicon.png
new file mode 100644
index 0000000..38b3f8b
Binary files /dev/null and b/django_code/django_code/cloudmanager/templates/Favicon.png differ
diff --git a/django_code/django_code/cloudmanager/templates/FontAwesome.otf b/django_code/django_code/cloudmanager/templates/FontAwesome.otf
new file mode 100644
index 0000000..401ec0f
Binary files /dev/null and b/django_code/django_code/cloudmanager/templates/FontAwesome.otf differ
diff --git a/django_code/django_code/cloudmanager/templates/about-bg.jpg b/django_code/django_code/cloudmanager/templates/about-bg.jpg
new file mode 100644
index 0000000..5b14c74
Binary files /dev/null and b/django_code/django_code/cloudmanager/templates/about-bg.jpg differ
diff --git a/django_code/django_code/cloudmanager/templates/admin/css/autocomplete.css b/django_code/django_code/cloudmanager/templates/admin/css/autocomplete.css
new file mode 100644
index 0000000..69c94e7
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/css/autocomplete.css
@@ -0,0 +1,275 @@
+select.admin-autocomplete {
+ width: 20em;
+}
+
+.select2-container--admin-autocomplete.select2-container {
+ min-height: 30px;
+}
+
+.select2-container--admin-autocomplete .select2-selection--single,
+.select2-container--admin-autocomplete .select2-selection--multiple {
+ min-height: 30px;
+ padding: 0;
+}
+
+.select2-container--admin-autocomplete.select2-container--focus .select2-selection,
+.select2-container--admin-autocomplete.select2-container--open .select2-selection {
+ border-color: var(--body-quiet-color);
+ min-height: 30px;
+}
+
+.select2-container--admin-autocomplete.select2-container--focus .select2-selection.select2-selection--single,
+.select2-container--admin-autocomplete.select2-container--open .select2-selection.select2-selection--single {
+ padding: 0;
+}
+
+.select2-container--admin-autocomplete.select2-container--focus .select2-selection.select2-selection--multiple,
+.select2-container--admin-autocomplete.select2-container--open .select2-selection.select2-selection--multiple {
+ padding: 0;
+}
+
+.select2-container--admin-autocomplete .select2-selection--single {
+ background-color: var(--body-bg);
+ border: 1px solid var(--border-color);
+ border-radius: 4px;
+}
+
+.select2-container--admin-autocomplete .select2-selection--single .select2-selection__rendered {
+ color: var(--body-fg);
+ line-height: 30px;
+}
+
+.select2-container--admin-autocomplete .select2-selection--single .select2-selection__clear {
+ cursor: pointer;
+ float: right;
+ font-weight: bold;
+}
+
+.select2-container--admin-autocomplete .select2-selection--single .select2-selection__placeholder {
+ color: var(--body-quiet-color);
+}
+
+.select2-container--admin-autocomplete .select2-selection--single .select2-selection__arrow {
+ height: 26px;
+ position: absolute;
+ top: 1px;
+ right: 1px;
+ width: 20px;
+}
+
+.select2-container--admin-autocomplete .select2-selection--single .select2-selection__arrow b {
+ border-color: #888 transparent transparent transparent;
+ border-style: solid;
+ border-width: 5px 4px 0 4px;
+ height: 0;
+ left: 50%;
+ margin-left: -4px;
+ margin-top: -2px;
+ position: absolute;
+ top: 50%;
+ width: 0;
+}
+
+.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--single .select2-selection__clear {
+ float: left;
+}
+
+.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--single .select2-selection__arrow {
+ left: 1px;
+ right: auto;
+}
+
+.select2-container--admin-autocomplete.select2-container--disabled .select2-selection--single {
+ background-color: var(--darkened-bg);
+ cursor: default;
+}
+
+.select2-container--admin-autocomplete.select2-container--disabled .select2-selection--single .select2-selection__clear {
+ display: none;
+}
+
+.select2-container--admin-autocomplete.select2-container--open .select2-selection--single .select2-selection__arrow b {
+ border-color: transparent transparent #888 transparent;
+ border-width: 0 4px 5px 4px;
+}
+
+.select2-container--admin-autocomplete .select2-selection--multiple {
+ background-color: var(--body-bg);
+ border: 1px solid var(--border-color);
+ border-radius: 4px;
+ cursor: text;
+}
+
+.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__rendered {
+ box-sizing: border-box;
+ list-style: none;
+ margin: 0;
+ padding: 0 10px 5px 5px;
+ width: 100%;
+ display: flex;
+ flex-wrap: wrap;
+}
+
+.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__rendered li {
+ list-style: none;
+}
+
+.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__placeholder {
+ color: var(--body-quiet-color);
+ margin-top: 5px;
+ float: left;
+}
+
+.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__clear {
+ cursor: pointer;
+ float: right;
+ font-weight: bold;
+ margin: 5px;
+ position: absolute;
+ right: 0;
+}
+
+.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__choice {
+ background-color: var(--darkened-bg);
+ border: 1px solid var(--border-color);
+ border-radius: 4px;
+ cursor: default;
+ float: left;
+ margin-right: 5px;
+ margin-top: 5px;
+ padding: 0 5px;
+}
+
+.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__choice__remove {
+ color: var(--body-quiet-color);
+ cursor: pointer;
+ display: inline-block;
+ font-weight: bold;
+ margin-right: 2px;
+}
+
+.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__choice__remove:hover {
+ color: var(--body-fg);
+}
+
+.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder, .select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-search--inline {
+ float: right;
+}
+
+.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
+ margin-left: 5px;
+ margin-right: auto;
+}
+
+.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
+ margin-left: 2px;
+ margin-right: auto;
+}
+
+.select2-container--admin-autocomplete.select2-container--focus .select2-selection--multiple {
+ border: solid var(--body-quiet-color) 1px;
+ outline: 0;
+}
+
+.select2-container--admin-autocomplete.select2-container--disabled .select2-selection--multiple {
+ background-color: var(--darkened-bg);
+ cursor: default;
+}
+
+.select2-container--admin-autocomplete.select2-container--disabled .select2-selection__choice__remove {
+ display: none;
+}
+
+.select2-container--admin-autocomplete.select2-container--open.select2-container--above .select2-selection--single, .select2-container--admin-autocomplete.select2-container--open.select2-container--above .select2-selection--multiple {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+
+.select2-container--admin-autocomplete.select2-container--open.select2-container--below .select2-selection--single, .select2-container--admin-autocomplete.select2-container--open.select2-container--below .select2-selection--multiple {
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+.select2-container--admin-autocomplete .select2-search--dropdown {
+ background: var(--darkened-bg);
+}
+
+.select2-container--admin-autocomplete .select2-search--dropdown .select2-search__field {
+ background: var(--body-bg);
+ color: var(--body-fg);
+ border: 1px solid var(--border-color);
+ border-radius: 4px;
+}
+
+.select2-container--admin-autocomplete .select2-search--inline .select2-search__field {
+ background: transparent;
+ color: var(--body-fg);
+ border: none;
+ outline: 0;
+ box-shadow: none;
+ -webkit-appearance: textfield;
+}
+
+.select2-container--admin-autocomplete .select2-results > .select2-results__options {
+ max-height: 200px;
+ overflow-y: auto;
+ color: var(--body-fg);
+ background: var(--body-bg);
+}
+
+.select2-container--admin-autocomplete .select2-results__option[role=group] {
+ padding: 0;
+}
+
+.select2-container--admin-autocomplete .select2-results__option[aria-disabled=true] {
+ color: var(--body-quiet-color);
+}
+
+.select2-container--admin-autocomplete .select2-results__option[aria-selected=true] {
+ background-color: var(--selected-bg);
+ color: var(--body-fg);
+}
+
+.select2-container--admin-autocomplete .select2-results__option .select2-results__option {
+ padding-left: 1em;
+}
+
+.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__group {
+ padding-left: 0;
+}
+
+.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -1em;
+ padding-left: 2em;
+}
+
+.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -2em;
+ padding-left: 3em;
+}
+
+.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -3em;
+ padding-left: 4em;
+}
+
+.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -4em;
+ padding-left: 5em;
+}
+
+.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -5em;
+ padding-left: 6em;
+}
+
+.select2-container--admin-autocomplete .select2-results__option--highlighted[aria-selected] {
+ background-color: var(--primary);
+ color: var(--primary-fg);
+}
+
+.select2-container--admin-autocomplete .select2-results__group {
+ cursor: default;
+ display: block;
+ padding: 6px;
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/css/base.css b/django_code/django_code/cloudmanager/templates/admin/css/base.css
new file mode 100644
index 0000000..93db7d0
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/css/base.css
@@ -0,0 +1,1145 @@
+/*
+ DJANGO Admin styles
+*/
+
+/* VARIABLE DEFINITIONS */
+html[data-theme="light"],
+:root {
+ --primary: #79aec8;
+ --secondary: #417690;
+ --accent: #f5dd5d;
+ --primary-fg: #fff;
+
+ --body-fg: #333;
+ --body-bg: #fff;
+ --body-quiet-color: #666;
+ --body-loud-color: #000;
+
+ --header-color: #ffc;
+ --header-branding-color: var(--accent);
+ --header-bg: var(--secondary);
+ --header-link-color: var(--primary-fg);
+
+ --breadcrumbs-fg: #c4dce8;
+ --breadcrumbs-link-fg: var(--body-bg);
+ --breadcrumbs-bg: var(--primary);
+
+ --link-fg: #417893;
+ --link-hover-color: #036;
+ --link-selected-fg: #5b80b2;
+
+ --hairline-color: #e8e8e8;
+ --border-color: #ccc;
+
+ --error-fg: #ba2121;
+
+ --message-success-bg: #dfd;
+ --message-warning-bg: #ffc;
+ --message-error-bg: #ffefef;
+
+ --darkened-bg: #f8f8f8; /* A bit darker than --body-bg */
+ --selected-bg: #e4e4e4; /* E.g. selected table cells */
+ --selected-row: #ffc;
+
+ --button-fg: #fff;
+ --button-bg: var(--primary);
+ --button-hover-bg: #609ab6;
+ --default-button-bg: var(--secondary);
+ --default-button-hover-bg: #205067;
+ --close-button-bg: #747474;
+ --close-button-hover-bg: #333;
+ --delete-button-bg: #ba2121;
+ --delete-button-hover-bg: #a41515;
+
+ --object-tools-fg: var(--button-fg);
+ --object-tools-bg: var(--close-button-bg);
+ --object-tools-hover-bg: var(--close-button-hover-bg);
+
+ --font-family-primary:
+ -apple-system,
+ BlinkMacSystemFont,
+ "Segoe UI",
+ system-ui,
+ Roboto,
+ "Helvetica Neue",
+ Arial,
+ sans-serif,
+ "Apple Color Emoji",
+ "Segoe UI Emoji",
+ "Segoe UI Symbol",
+ "Noto Color Emoji";
+ --font-family-monospace:
+ ui-monospace,
+ Menlo,
+ Monaco,
+ "Cascadia Mono",
+ "Segoe UI Mono",
+ "Roboto Mono",
+ "Oxygen Mono",
+ "Ubuntu Monospace",
+ "Source Code Pro",
+ "Fira Mono",
+ "Droid Sans Mono",
+ "Courier New",
+ monospace,
+ "Apple Color Emoji",
+ "Segoe UI Emoji",
+ "Segoe UI Symbol",
+ "Noto Color Emoji";
+}
+
+html, body {
+ height: 100%;
+}
+
+body {
+ margin: 0;
+ padding: 0;
+ font-size: 0.875rem;
+ font-family: var(--font-family-primary);
+ color: var(--body-fg);
+ background: var(--body-bg);
+}
+
+/* LINKS */
+
+a:link, a:visited {
+ color: var(--link-fg);
+ text-decoration: none;
+ transition: color 0.15s, background 0.15s;
+}
+
+a:focus, a:hover {
+ color: var(--link-hover-color);
+}
+
+a:focus {
+ text-decoration: underline;
+}
+
+a img {
+ border: none;
+}
+
+a.section:link, a.section:visited {
+ color: var(--header-link-color);
+ text-decoration: none;
+}
+
+a.section:focus, a.section:hover {
+ text-decoration: underline;
+}
+
+/* GLOBAL DEFAULTS */
+
+p, ol, ul, dl {
+ margin: .2em 0 .8em 0;
+}
+
+p {
+ padding: 0;
+ line-height: 140%;
+}
+
+h1,h2,h3,h4,h5 {
+ font-weight: bold;
+}
+
+h1 {
+ margin: 0 0 20px;
+ font-weight: 300;
+ font-size: 1.25rem;
+ color: var(--body-quiet-color);
+}
+
+h2 {
+ font-size: 1rem;
+ margin: 1em 0 .5em 0;
+}
+
+h2.subhead {
+ font-weight: normal;
+ margin-top: 0;
+}
+
+h3 {
+ font-size: 0.875rem;
+ margin: .8em 0 .3em 0;
+ color: var(--body-quiet-color);
+ font-weight: bold;
+}
+
+h4 {
+ font-size: 0.75rem;
+ margin: 1em 0 .8em 0;
+ padding-bottom: 3px;
+}
+
+h5 {
+ font-size: 0.625rem;
+ margin: 1.5em 0 .5em 0;
+ color: var(--body-quiet-color);
+ text-transform: uppercase;
+ letter-spacing: 1px;
+}
+
+ul > li {
+ list-style-type: square;
+ padding: 1px 0;
+}
+
+li ul {
+ margin-bottom: 0;
+}
+
+li, dt, dd {
+ font-size: 0.8125rem;
+ line-height: 1.25rem;
+}
+
+dt {
+ font-weight: bold;
+ margin-top: 4px;
+}
+
+dd {
+ margin-left: 0;
+}
+
+form {
+ margin: 0;
+ padding: 0;
+}
+
+fieldset {
+ margin: 0;
+ min-width: 0;
+ padding: 0;
+ border: none;
+ border-top: 1px solid var(--hairline-color);
+}
+
+blockquote {
+ font-size: 0.6875rem;
+ color: #777;
+ margin-left: 2px;
+ padding-left: 10px;
+ border-left: 5px solid #ddd;
+}
+
+code, pre {
+ font-family: var(--font-family-monospace);
+ color: var(--body-quiet-color);
+ font-size: 0.75rem;
+ overflow-x: auto;
+}
+
+pre.literal-block {
+ margin: 10px;
+ background: var(--darkened-bg);
+ padding: 6px 8px;
+}
+
+code strong {
+ color: #930;
+}
+
+hr {
+ clear: both;
+ color: var(--hairline-color);
+ background-color: var(--hairline-color);
+ height: 1px;
+ border: none;
+ margin: 0;
+ padding: 0;
+ line-height: 1px;
+}
+
+/* TEXT STYLES & MODIFIERS */
+
+.small {
+ font-size: 0.6875rem;
+}
+
+.mini {
+ font-size: 0.625rem;
+}
+
+.help, p.help, form p.help, div.help, form div.help, div.help li {
+ font-size: 0.6875rem;
+ color: var(--body-quiet-color);
+}
+
+div.help ul {
+ margin-bottom: 0;
+}
+
+.help-tooltip {
+ cursor: help;
+}
+
+p img, h1 img, h2 img, h3 img, h4 img, td img {
+ vertical-align: middle;
+}
+
+.quiet, a.quiet:link, a.quiet:visited {
+ color: var(--body-quiet-color);
+ font-weight: normal;
+}
+
+.clear {
+ clear: both;
+}
+
+.nowrap {
+ white-space: nowrap;
+}
+
+.hidden {
+ display: none !important;
+}
+
+/* TABLES */
+
+table {
+ border-collapse: collapse;
+ border-color: var(--border-color);
+}
+
+td, th {
+ font-size: 0.8125rem;
+ line-height: 1rem;
+ border-bottom: 1px solid var(--hairline-color);
+ vertical-align: top;
+ padding: 8px;
+}
+
+th {
+ font-weight: 600;
+ text-align: left;
+}
+
+thead th,
+tfoot td {
+ color: var(--body-quiet-color);
+ padding: 5px 10px;
+ font-size: 0.6875rem;
+ background: var(--body-bg);
+ border: none;
+ border-top: 1px solid var(--hairline-color);
+ border-bottom: 1px solid var(--hairline-color);
+}
+
+tfoot td {
+ border-bottom: none;
+ border-top: 1px solid var(--hairline-color);
+}
+
+thead th.required {
+ color: var(--body-loud-color);
+}
+
+tr.alt {
+ background: var(--darkened-bg);
+}
+
+tr:nth-child(odd), .row-form-errors {
+ background: var(--body-bg);
+}
+
+tr:nth-child(even),
+tr:nth-child(even) .errorlist,
+tr:nth-child(odd) + .row-form-errors,
+tr:nth-child(odd) + .row-form-errors .errorlist {
+ background: var(--darkened-bg);
+}
+
+/* SORTABLE TABLES */
+
+thead th {
+ padding: 5px 10px;
+ line-height: normal;
+ text-transform: uppercase;
+ background: var(--darkened-bg);
+}
+
+thead th a:link, thead th a:visited {
+ color: var(--body-quiet-color);
+}
+
+thead th.sorted {
+ background: var(--selected-bg);
+}
+
+thead th.sorted .text {
+ padding-right: 42px;
+}
+
+table thead th .text span {
+ padding: 8px 10px;
+ display: block;
+}
+
+table thead th .text a {
+ display: block;
+ cursor: pointer;
+ padding: 8px 10px;
+}
+
+table thead th .text a:focus, table thead th .text a:hover {
+ background: var(--selected-bg);
+}
+
+thead th.sorted a.sortremove {
+ visibility: hidden;
+}
+
+table thead th.sorted:hover a.sortremove {
+ visibility: visible;
+}
+
+table thead th.sorted .sortoptions {
+ display: block;
+ padding: 9px 5px 0 5px;
+ float: right;
+ text-align: right;
+}
+
+table thead th.sorted .sortpriority {
+ font-size: .8em;
+ min-width: 12px;
+ text-align: center;
+ vertical-align: 3px;
+ margin-left: 2px;
+ margin-right: 2px;
+}
+
+table thead th.sorted .sortoptions a {
+ position: relative;
+ width: 14px;
+ height: 14px;
+ display: inline-block;
+ background: url(../img/sorting-icons.svg) 0 0 no-repeat;
+ background-size: 14px auto;
+}
+
+table thead th.sorted .sortoptions a.sortremove {
+ background-position: 0 0;
+}
+
+table thead th.sorted .sortoptions a.sortremove:after {
+ content: '\\';
+ position: absolute;
+ top: -6px;
+ left: 3px;
+ font-weight: 200;
+ font-size: 1.125rem;
+ color: var(--body-quiet-color);
+}
+
+table thead th.sorted .sortoptions a.sortremove:focus:after,
+table thead th.sorted .sortoptions a.sortremove:hover:after {
+ color: var(--link-fg);
+}
+
+table thead th.sorted .sortoptions a.sortremove:focus,
+table thead th.sorted .sortoptions a.sortremove:hover {
+ background-position: 0 -14px;
+}
+
+table thead th.sorted .sortoptions a.ascending {
+ background-position: 0 -28px;
+}
+
+table thead th.sorted .sortoptions a.ascending:focus,
+table thead th.sorted .sortoptions a.ascending:hover {
+ background-position: 0 -42px;
+}
+
+table thead th.sorted .sortoptions a.descending {
+ top: 1px;
+ background-position: 0 -56px;
+}
+
+table thead th.sorted .sortoptions a.descending:focus,
+table thead th.sorted .sortoptions a.descending:hover {
+ background-position: 0 -70px;
+}
+
+/* FORM DEFAULTS */
+
+input, textarea, select, .form-row p, form .button {
+ margin: 2px 0;
+ padding: 2px 3px;
+ vertical-align: middle;
+ font-family: var(--font-family-primary);
+ font-weight: normal;
+ font-size: 0.8125rem;
+}
+.form-row div.help {
+ padding: 2px 3px;
+}
+
+textarea {
+ vertical-align: top;
+}
+
+input[type=text], input[type=password], input[type=email], input[type=url],
+input[type=number], input[type=tel], textarea, select, .vTextField {
+ border: 1px solid var(--border-color);
+ border-radius: 4px;
+ padding: 5px 6px;
+ margin-top: 0;
+ color: var(--body-fg);
+ background-color: var(--body-bg);
+}
+
+input[type=text]:focus, input[type=password]:focus, input[type=email]:focus,
+input[type=url]:focus, input[type=number]:focus, input[type=tel]:focus,
+textarea:focus, select:focus, .vTextField:focus {
+ border-color: var(--body-quiet-color);
+}
+
+select {
+ height: 1.875rem;
+}
+
+select[multiple] {
+ /* Allow HTML size attribute to override the height in the rule above. */
+ height: auto;
+ min-height: 150px;
+}
+
+/* FORM BUTTONS */
+
+.button, input[type=submit], input[type=button], .submit-row input, a.button {
+ background: var(--button-bg);
+ padding: 10px 15px;
+ border: none;
+ border-radius: 4px;
+ color: var(--button-fg);
+ cursor: pointer;
+ transition: background 0.15s;
+}
+
+a.button {
+ padding: 4px 5px;
+}
+
+.button:active, input[type=submit]:active, input[type=button]:active,
+.button:focus, input[type=submit]:focus, input[type=button]:focus,
+.button:hover, input[type=submit]:hover, input[type=button]:hover {
+ background: var(--button-hover-bg);
+}
+
+.button[disabled], input[type=submit][disabled], input[type=button][disabled] {
+ opacity: 0.4;
+}
+
+.button.default, input[type=submit].default, .submit-row input.default {
+ border: none;
+ font-weight: 400;
+ background: var(--default-button-bg);
+}
+
+.button.default:active, input[type=submit].default:active,
+.button.default:focus, input[type=submit].default:focus,
+.button.default:hover, input[type=submit].default:hover {
+ background: var(--default-button-hover-bg);
+}
+
+.button[disabled].default,
+input[type=submit][disabled].default,
+input[type=button][disabled].default {
+ opacity: 0.4;
+}
+
+
+/* MODULES */
+
+.module {
+ border: none;
+ margin-bottom: 30px;
+ background: var(--body-bg);
+}
+
+.module p, .module ul, .module h3, .module h4, .module dl, .module pre {
+ padding-left: 10px;
+ padding-right: 10px;
+}
+
+.module blockquote {
+ margin-left: 12px;
+}
+
+.module ul, .module ol {
+ margin-left: 1.5em;
+}
+
+.module h3 {
+ margin-top: .6em;
+}
+
+.module h2, .module caption, .inline-group h2 {
+ margin: 0;
+ padding: 8px;
+ font-weight: 400;
+ font-size: 0.8125rem;
+ text-align: left;
+ background: var(--primary);
+ color: var(--header-link-color);
+}
+
+.module caption,
+.inline-group h2 {
+ font-size: 0.75rem;
+ letter-spacing: 0.5px;
+ text-transform: uppercase;
+}
+
+.module table {
+ border-collapse: collapse;
+}
+
+/* MESSAGES & ERRORS */
+
+ul.messagelist {
+ padding: 0;
+ margin: 0;
+}
+
+ul.messagelist li {
+ display: block;
+ font-weight: 400;
+ font-size: 0.8125rem;
+ padding: 10px 10px 10px 65px;
+ margin: 0 0 10px 0;
+ background: var(--message-success-bg) url(../img/icon-yes.svg) 40px 12px no-repeat;
+ background-size: 16px auto;
+ color: var(--body-fg);
+ word-break: break-word;
+}
+
+ul.messagelist li.warning {
+ background: var(--message-warning-bg) url(../img/icon-alert.svg) 40px 14px no-repeat;
+ background-size: 14px auto;
+}
+
+ul.messagelist li.error {
+ background: var(--message-error-bg) url(../img/icon-no.svg) 40px 12px no-repeat;
+ background-size: 16px auto;
+}
+
+.errornote {
+ font-size: 0.875rem;
+ font-weight: 700;
+ display: block;
+ padding: 10px 12px;
+ margin: 0 0 10px 0;
+ color: var(--error-fg);
+ border: 1px solid var(--error-fg);
+ border-radius: 4px;
+ background-color: var(--body-bg);
+ background-position: 5px 12px;
+ overflow-wrap: break-word;
+}
+
+ul.errorlist {
+ margin: 0 0 4px;
+ padding: 0;
+ color: var(--error-fg);
+ background: var(--body-bg);
+}
+
+ul.errorlist li {
+ font-size: 0.8125rem;
+ display: block;
+ margin-bottom: 4px;
+ overflow-wrap: break-word;
+}
+
+ul.errorlist li:first-child {
+ margin-top: 0;
+}
+
+ul.errorlist li a {
+ color: inherit;
+ text-decoration: underline;
+}
+
+td ul.errorlist {
+ margin: 0;
+ padding: 0;
+}
+
+td ul.errorlist li {
+ margin: 0;
+}
+
+.form-row.errors {
+ margin: 0;
+ border: none;
+ border-bottom: 1px solid var(--hairline-color);
+ background: none;
+}
+
+.form-row.errors ul.errorlist li {
+ padding-left: 0;
+}
+
+.errors input, .errors select, .errors textarea,
+td ul.errorlist + input, td ul.errorlist + select, td ul.errorlist + textarea {
+ border: 1px solid var(--error-fg);
+}
+
+.description {
+ font-size: 0.75rem;
+ padding: 5px 0 0 12px;
+}
+
+/* BREADCRUMBS */
+
+div.breadcrumbs {
+ background: var(--breadcrumbs-bg);
+ padding: 10px 40px;
+ border: none;
+ color: var(--breadcrumbs-fg);
+ text-align: left;
+}
+
+div.breadcrumbs a {
+ color: var(--breadcrumbs-link-fg);
+}
+
+div.breadcrumbs a:focus, div.breadcrumbs a:hover {
+ color: var(--breadcrumbs-fg);
+}
+
+/* ACTION ICONS */
+
+.viewlink, .inlineviewlink {
+ padding-left: 16px;
+ background: url(../img/icon-viewlink.svg) 0 1px no-repeat;
+}
+
+.addlink {
+ padding-left: 16px;
+ background: url(../img/icon-addlink.svg) 0 1px no-repeat;
+}
+
+.changelink, .inlinechangelink {
+ padding-left: 16px;
+ background: url(../img/icon-changelink.svg) 0 1px no-repeat;
+}
+
+.deletelink {
+ padding-left: 16px;
+ background: url(../img/icon-deletelink.svg) 0 1px no-repeat;
+}
+
+a.deletelink:link, a.deletelink:visited {
+ color: #CC3434; /* XXX Probably unused? */
+}
+
+a.deletelink:focus, a.deletelink:hover {
+ color: #993333; /* XXX Probably unused? */
+ text-decoration: none;
+}
+
+/* OBJECT TOOLS */
+
+.object-tools {
+ font-size: 0.625rem;
+ font-weight: bold;
+ padding-left: 0;
+ float: right;
+ position: relative;
+ margin-top: -48px;
+}
+
+.object-tools li {
+ display: block;
+ float: left;
+ margin-left: 5px;
+ height: 1rem;
+}
+
+.object-tools a {
+ border-radius: 15px;
+}
+
+.object-tools a:link, .object-tools a:visited {
+ display: block;
+ float: left;
+ padding: 3px 12px;
+ background: var(--object-tools-bg);
+ color: var(--object-tools-fg);
+ font-weight: 400;
+ font-size: 0.6875rem;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+}
+
+.object-tools a:focus, .object-tools a:hover {
+ background-color: var(--object-tools-hover-bg);
+}
+
+.object-tools a:focus{
+ text-decoration: none;
+}
+
+.object-tools a.viewsitelink, .object-tools a.addlink {
+ background-repeat: no-repeat;
+ background-position: right 7px center;
+ padding-right: 26px;
+}
+
+.object-tools a.viewsitelink {
+ background-image: url(../img/tooltag-arrowright.svg);
+}
+
+.object-tools a.addlink {
+ background-image: url(../img/tooltag-add.svg);
+}
+
+/* OBJECT HISTORY */
+
+#change-history table {
+ width: 100%;
+}
+
+#change-history table tbody th {
+ width: 16em;
+}
+
+#change-history .paginator {
+ color: var(--body-quiet-color);
+ border-bottom: 1px solid var(--hairline-color);
+ background: var(--body-bg);
+ overflow: hidden;
+}
+
+/* PAGE STRUCTURE */
+
+#container {
+ position: relative;
+ width: 100%;
+ min-width: 980px;
+ padding: 0;
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+}
+
+#container > div {
+ flex-shrink: 0;
+}
+
+#container > .main {
+ display: flex;
+ flex: 1 0 auto;
+}
+
+.main > .content {
+ flex: 1 0;
+ max-width: 100%;
+}
+
+.skip-to-content-link {
+ position: absolute;
+ top: -999px;
+ margin: 5px;
+ padding: 5px;
+ background: var(--body-bg);
+ z-index: 1;
+}
+
+.skip-to-content-link:focus {
+ left: 0px;
+ top: 0px;
+}
+
+#content {
+ padding: 20px 40px;
+}
+
+.dashboard #content {
+ width: 600px;
+}
+
+#content-main {
+ float: left;
+ width: 100%;
+}
+
+#content-related {
+ float: right;
+ width: 260px;
+ position: relative;
+ margin-right: -300px;
+}
+
+#footer {
+ clear: both;
+ padding: 10px;
+}
+
+/* COLUMN TYPES */
+
+.colMS {
+ margin-right: 300px;
+}
+
+.colSM {
+ margin-left: 300px;
+}
+
+.colSM #content-related {
+ float: left;
+ margin-right: 0;
+ margin-left: -300px;
+}
+
+.colSM #content-main {
+ float: right;
+}
+
+.popup .colM {
+ width: auto;
+}
+
+/* HEADER */
+
+#header {
+ width: auto;
+ height: auto;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 10px 40px;
+ background: var(--header-bg);
+ color: var(--header-color);
+ overflow: hidden;
+}
+
+#header a:link, #header a:visited, #logout-form button {
+ color: var(--header-link-color);
+}
+
+#header a:focus , #header a:hover {
+ text-decoration: underline;
+}
+
+#branding {
+ display: flex;
+}
+
+#branding h1 {
+ padding: 0;
+ margin: 0;
+ margin-inline-end: 20px;
+ font-weight: 300;
+ font-size: 1.5rem;
+ color: var(--header-branding-color);
+}
+
+#branding h1 a:link, #branding h1 a:visited {
+ color: var(--accent);
+}
+
+#branding h2 {
+ padding: 0 10px;
+ font-size: 0.875rem;
+ margin: -8px 0 8px 0;
+ font-weight: normal;
+ color: var(--header-color);
+}
+
+#branding a:hover {
+ text-decoration: none;
+}
+
+#logout-form {
+ display: inline;
+}
+
+#logout-form button {
+ background: none;
+ border: 0;
+ cursor: pointer;
+ font-family: var(--font-family-primary);
+}
+
+#user-tools {
+ float: right;
+ margin: 0 0 0 20px;
+ text-align: right;
+}
+
+#user-tools, #logout-form button{
+ padding: 0;
+ font-weight: 300;
+ font-size: 0.6875rem;
+ letter-spacing: 0.5px;
+ text-transform: uppercase;
+}
+
+#user-tools a, #logout-form button {
+ border-bottom: 1px solid rgba(255, 255, 255, 0.25);
+}
+
+#user-tools a:focus, #user-tools a:hover,
+#logout-form button:active, #logout-form button:hover {
+ text-decoration: none;
+ border-bottom: 0;
+}
+
+#logout-form button:active, #logout-form button:hover {
+ margin-bottom: 1px;
+}
+
+/* SIDEBAR */
+
+#content-related {
+ background: var(--darkened-bg);
+}
+
+#content-related .module {
+ background: none;
+}
+
+#content-related h3 {
+ color: var(--body-quiet-color);
+ padding: 0 16px;
+ margin: 0 0 16px;
+}
+
+#content-related h4 {
+ font-size: 0.8125rem;
+}
+
+#content-related p {
+ padding-left: 16px;
+ padding-right: 16px;
+}
+
+#content-related .actionlist {
+ padding: 0;
+ margin: 16px;
+}
+
+#content-related .actionlist li {
+ line-height: 1.2;
+ margin-bottom: 10px;
+ padding-left: 18px;
+}
+
+#content-related .module h2 {
+ background: none;
+ padding: 16px;
+ margin-bottom: 16px;
+ border-bottom: 1px solid var(--hairline-color);
+ font-size: 1.125rem;
+ color: var(--body-fg);
+}
+
+.delete-confirmation form input[type="submit"] {
+ background: var(--delete-button-bg);
+ border-radius: 4px;
+ padding: 10px 15px;
+ color: var(--button-fg);
+}
+
+.delete-confirmation form input[type="submit"]:active,
+.delete-confirmation form input[type="submit"]:focus,
+.delete-confirmation form input[type="submit"]:hover {
+ background: var(--delete-button-hover-bg);
+}
+
+.delete-confirmation form .cancel-link {
+ display: inline-block;
+ vertical-align: middle;
+ height: 0.9375rem;
+ line-height: 0.9375rem;
+ border-radius: 4px;
+ padding: 10px 15px;
+ color: var(--button-fg);
+ background: var(--close-button-bg);
+ margin: 0 0 0 10px;
+}
+
+.delete-confirmation form .cancel-link:active,
+.delete-confirmation form .cancel-link:focus,
+.delete-confirmation form .cancel-link:hover {
+ background: var(--close-button-hover-bg);
+}
+
+/* POPUP */
+.popup #content {
+ padding: 20px;
+}
+
+.popup #container {
+ min-width: 0;
+}
+
+.popup #header {
+ padding: 10px 20px;
+}
+
+/* PAGINATOR */
+
+.paginator {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ font-size: 0.8125rem;
+ padding-top: 10px;
+ padding-bottom: 10px;
+ line-height: 22px;
+ margin: 0;
+ border-top: 1px solid var(--hairline-color);
+ width: 100%;
+}
+
+.paginator a:link, .paginator a:visited {
+ padding: 2px 6px;
+ background: var(--button-bg);
+ text-decoration: none;
+ color: var(--button-fg);
+}
+
+.paginator a.showall {
+ border: none;
+ background: none;
+ color: var(--link-fg);
+}
+
+.paginator a.showall:focus, .paginator a.showall:hover {
+ background: none;
+ color: var(--link-hover-color);
+}
+
+.paginator .end {
+ margin-right: 6px;
+}
+
+.paginator .this-page {
+ padding: 2px 6px;
+ font-weight: bold;
+ font-size: 0.8125rem;
+ vertical-align: top;
+}
+
+.paginator a:focus, .paginator a:hover {
+ color: white;
+ background: var(--link-hover-color);
+}
+
+.paginator input {
+ margin-left: auto;
+}
+
+.base-svgs {
+ display: none;
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/css/changelists.css b/django_code/django_code/cloudmanager/templates/admin/css/changelists.css
new file mode 100644
index 0000000..a754513
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/css/changelists.css
@@ -0,0 +1,328 @@
+/* CHANGELISTS */
+
+#changelist {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+}
+
+#changelist .changelist-form-container {
+ flex: 1 1 auto;
+ min-width: 0;
+}
+
+#changelist table {
+ width: 100%;
+}
+
+.change-list .hiddenfields { display:none; }
+
+.change-list .filtered table {
+ border-right: none;
+}
+
+.change-list .filtered {
+ min-height: 400px;
+}
+
+.change-list .filtered .results, .change-list .filtered .paginator,
+.filtered #toolbar, .filtered div.xfull {
+ width: auto;
+}
+
+.change-list .filtered table tbody th {
+ padding-right: 1em;
+}
+
+#changelist-form .results {
+ overflow-x: auto;
+ width: 100%;
+}
+
+#changelist .toplinks {
+ border-bottom: 1px solid var(--hairline-color);
+}
+
+#changelist .paginator {
+ color: var(--body-quiet-color);
+ border-bottom: 1px solid var(--hairline-color);
+ background: var(--body-bg);
+ overflow: hidden;
+}
+
+/* CHANGELIST TABLES */
+
+#changelist table thead th {
+ padding: 0;
+ white-space: nowrap;
+ vertical-align: middle;
+}
+
+#changelist table thead th.action-checkbox-column {
+ width: 1.5em;
+ text-align: center;
+}
+
+#changelist table tbody td.action-checkbox {
+ text-align: center;
+}
+
+#changelist table tfoot {
+ color: var(--body-quiet-color);
+}
+
+/* TOOLBAR */
+
+#toolbar {
+ padding: 8px 10px;
+ margin-bottom: 15px;
+ border-top: 1px solid var(--hairline-color);
+ border-bottom: 1px solid var(--hairline-color);
+ background: var(--darkened-bg);
+ color: var(--body-quiet-color);
+}
+
+#toolbar form input {
+ border-radius: 4px;
+ font-size: 0.875rem;
+ padding: 5px;
+ color: var(--body-fg);
+}
+
+#toolbar #searchbar {
+ height: 1.1875rem;
+ border: 1px solid var(--border-color);
+ padding: 2px 5px;
+ margin: 0;
+ vertical-align: top;
+ font-size: 0.8125rem;
+ max-width: 100%;
+}
+
+#toolbar #searchbar:focus {
+ border-color: var(--body-quiet-color);
+}
+
+#toolbar form input[type="submit"] {
+ border: 1px solid var(--border-color);
+ font-size: 0.8125rem;
+ padding: 4px 8px;
+ margin: 0;
+ vertical-align: middle;
+ background: var(--body-bg);
+ box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset;
+ cursor: pointer;
+ color: var(--body-fg);
+}
+
+#toolbar form input[type="submit"]:focus,
+#toolbar form input[type="submit"]:hover {
+ border-color: var(--body-quiet-color);
+}
+
+#changelist-search img {
+ vertical-align: middle;
+ margin-right: 4px;
+}
+
+#changelist-search .help {
+ word-break: break-word;
+}
+
+/* FILTER COLUMN */
+
+#changelist-filter {
+ flex: 0 0 240px;
+ order: 1;
+ background: var(--darkened-bg);
+ border-left: none;
+ margin: 0 0 0 30px;
+}
+
+#changelist-filter h2 {
+ font-size: 0.875rem;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ padding: 5px 15px;
+ margin-bottom: 12px;
+ border-bottom: none;
+}
+
+#changelist-filter h3,
+#changelist-filter details summary {
+ font-weight: 400;
+ padding: 0 15px;
+ margin-bottom: 10px;
+}
+
+#changelist-filter details summary > * {
+ display: inline;
+}
+
+#changelist-filter details > summary {
+ list-style-type: none;
+}
+
+#changelist-filter details > summary::-webkit-details-marker {
+ display: none;
+}
+
+#changelist-filter details > summary::before {
+ content: '→';
+ font-weight: bold;
+ color: var(--link-hover-color);
+}
+
+#changelist-filter details[open] > summary::before {
+ content: '↓';
+}
+
+#changelist-filter ul {
+ margin: 5px 0;
+ padding: 0 15px 15px;
+ border-bottom: 1px solid var(--hairline-color);
+}
+
+#changelist-filter ul:last-child {
+ border-bottom: none;
+}
+
+#changelist-filter li {
+ list-style-type: none;
+ margin-left: 0;
+ padding-left: 0;
+}
+
+#changelist-filter a {
+ display: block;
+ color: var(--body-quiet-color);
+ word-break: break-word;
+}
+
+#changelist-filter li.selected {
+ border-left: 5px solid var(--hairline-color);
+ padding-left: 10px;
+ margin-left: -15px;
+}
+
+#changelist-filter li.selected a {
+ color: var(--link-selected-fg);
+}
+
+#changelist-filter a:focus, #changelist-filter a:hover,
+#changelist-filter li.selected a:focus,
+#changelist-filter li.selected a:hover {
+ color: var(--link-hover-color);
+}
+
+#changelist-filter #changelist-filter-clear a {
+ font-size: 0.8125rem;
+ padding-bottom: 10px;
+ border-bottom: 1px solid var(--hairline-color);
+}
+
+/* DATE DRILLDOWN */
+
+.change-list .toplinks {
+ display: flex;
+ padding-bottom: 5px;
+ flex-wrap: wrap;
+ gap: 3px 17px;
+ font-weight: bold;
+}
+
+.change-list .toplinks a {
+ font-size: 0.8125rem;
+}
+
+.change-list .toplinks .date-back {
+ color: var(--body-quiet-color);
+}
+
+.change-list .toplinks .date-back:focus,
+.change-list .toplinks .date-back:hover {
+ color: var(--link-hover-color);
+}
+
+/* ACTIONS */
+
+.filtered .actions {
+ border-right: none;
+}
+
+#changelist table input {
+ margin: 0;
+ vertical-align: baseline;
+}
+
+/* Once the :has() pseudo-class is supported by all browsers, the tr.selected
+ selector and the JS adding the class can be removed. */
+#changelist tbody tr.selected {
+ background-color: var(--selected-row);
+}
+
+#changelist tbody tr:has(.action-select:checked) {
+ background-color: var(--selected-row);
+}
+
+#changelist .actions {
+ padding: 10px;
+ background: var(--body-bg);
+ border-top: none;
+ border-bottom: none;
+ line-height: 1.5rem;
+ color: var(--body-quiet-color);
+ width: 100%;
+}
+
+#changelist .actions span.all,
+#changelist .actions span.action-counter,
+#changelist .actions span.clear,
+#changelist .actions span.question {
+ font-size: 0.8125rem;
+ margin: 0 0.5em;
+}
+
+#changelist .actions:last-child {
+ border-bottom: none;
+}
+
+#changelist .actions select {
+ vertical-align: top;
+ height: 1.5rem;
+ color: var(--body-fg);
+ border: 1px solid var(--border-color);
+ border-radius: 4px;
+ font-size: 0.875rem;
+ padding: 0 0 0 4px;
+ margin: 0;
+ margin-left: 10px;
+}
+
+#changelist .actions select:focus {
+ border-color: var(--body-quiet-color);
+}
+
+#changelist .actions label {
+ display: inline-block;
+ vertical-align: middle;
+ font-size: 0.8125rem;
+}
+
+#changelist .actions .button {
+ font-size: 0.8125rem;
+ border: 1px solid var(--border-color);
+ border-radius: 4px;
+ background: var(--body-bg);
+ box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset;
+ cursor: pointer;
+ height: 1.5rem;
+ line-height: 1;
+ padding: 4px 8px;
+ margin: 0;
+ color: var(--body-fg);
+}
+
+#changelist .actions .button:focus, #changelist .actions .button:hover {
+ border-color: var(--body-quiet-color);
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/css/dark_mode.css b/django_code/django_code/cloudmanager/templates/admin/css/dark_mode.css
new file mode 100644
index 0000000..6d08233
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/css/dark_mode.css
@@ -0,0 +1,137 @@
+@media (prefers-color-scheme: dark) {
+ :root {
+ --primary: #264b5d;
+ --primary-fg: #f7f7f7;
+
+ --body-fg: #eeeeee;
+ --body-bg: #121212;
+ --body-quiet-color: #e0e0e0;
+ --body-loud-color: #ffffff;
+
+ --breadcrumbs-link-fg: #e0e0e0;
+ --breadcrumbs-bg: var(--primary);
+
+ --link-fg: #81d4fa;
+ --link-hover-color: #4ac1f7;
+ --link-selected-fg: #6f94c6;
+
+ --hairline-color: #272727;
+ --border-color: #353535;
+
+ --error-fg: #e35f5f;
+ --message-success-bg: #006b1b;
+ --message-warning-bg: #583305;
+ --message-error-bg: #570808;
+
+ --darkened-bg: #212121;
+ --selected-bg: #1b1b1b;
+ --selected-row: #00363a;
+
+ --close-button-bg: #333333;
+ --close-button-hover-bg: #666666;
+ }
+ }
+
+
+html[data-theme="dark"] {
+ --primary: #264b5d;
+ --primary-fg: #f7f7f7;
+
+ --body-fg: #eeeeee;
+ --body-bg: #121212;
+ --body-quiet-color: #e0e0e0;
+ --body-loud-color: #ffffff;
+
+ --breadcrumbs-link-fg: #e0e0e0;
+ --breadcrumbs-bg: var(--primary);
+
+ --link-fg: #81d4fa;
+ --link-hover-color: #4ac1f7;
+ --link-selected-fg: #6f94c6;
+
+ --hairline-color: #272727;
+ --border-color: #353535;
+
+ --error-fg: #e35f5f;
+ --message-success-bg: #006b1b;
+ --message-warning-bg: #583305;
+ --message-error-bg: #570808;
+
+ --darkened-bg: #212121;
+ --selected-bg: #1b1b1b;
+ --selected-row: #00363a;
+
+ --close-button-bg: #333333;
+ --close-button-hover-bg: #666666;
+}
+
+/* THEME SWITCH */
+.theme-toggle {
+ cursor: pointer;
+ border: none;
+ padding: 0;
+ background: transparent;
+ vertical-align: middle;
+ margin-inline-start: 5px;
+ margin-top: -1px;
+}
+
+.theme-toggle svg {
+ vertical-align: middle;
+ height: 1rem;
+ width: 1rem;
+ display: none;
+}
+
+/*
+Fully hide screen reader text so we only show the one matching the current
+theme.
+*/
+.theme-toggle .visually-hidden {
+ display: none;
+}
+
+html[data-theme="auto"] .theme-toggle .theme-label-when-auto {
+ display: block;
+}
+
+html[data-theme="dark"] .theme-toggle .theme-label-when-dark {
+ display: block;
+}
+
+html[data-theme="light"] .theme-toggle .theme-label-when-light {
+ display: block;
+}
+
+/* ICONS */
+.theme-toggle svg.theme-icon-when-auto,
+.theme-toggle svg.theme-icon-when-dark,
+.theme-toggle svg.theme-icon-when-light {
+ fill: var(--header-link-color);
+ color: var(--header-bg);
+}
+
+html[data-theme="auto"] .theme-toggle svg.theme-icon-when-auto {
+ display: block;
+}
+
+html[data-theme="dark"] .theme-toggle svg.theme-icon-when-dark {
+ display: block;
+}
+
+html[data-theme="light"] .theme-toggle svg.theme-icon-when-light {
+ display: block;
+}
+
+.visually-hidden {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ overflow: hidden;
+ clip: rect(0,0,0,0);
+ white-space: nowrap;
+ border: 0;
+ color: var(--body-fg);
+ background-color: var(--body-bg);
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/css/dashboard.css b/django_code/django_code/cloudmanager/templates/admin/css/dashboard.css
new file mode 100644
index 0000000..242b81a
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/css/dashboard.css
@@ -0,0 +1,29 @@
+/* DASHBOARD */
+.dashboard td, .dashboard th {
+ word-break: break-word;
+}
+
+.dashboard .module table th {
+ width: 100%;
+}
+
+.dashboard .module table td {
+ white-space: nowrap;
+}
+
+.dashboard .module table td a {
+ display: block;
+ padding-right: .6em;
+}
+
+/* RECENT ACTIONS MODULE */
+
+.module ul.actionlist {
+ margin-left: 0;
+}
+
+ul.actionlist li {
+ list-style-type: none;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/css/forms.css b/django_code/django_code/cloudmanager/templates/admin/css/forms.css
new file mode 100644
index 0000000..9a8dad0
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/css/forms.css
@@ -0,0 +1,534 @@
+@import url('widgets.css');
+
+/* FORM ROWS */
+
+.form-row {
+ overflow: hidden;
+ padding: 10px;
+ font-size: 0.8125rem;
+ border-bottom: 1px solid var(--hairline-color);
+}
+
+.form-row img, .form-row input {
+ vertical-align: middle;
+}
+
+.form-row label input[type="checkbox"] {
+ margin-top: 0;
+ vertical-align: 0;
+}
+
+form .form-row p {
+ padding-left: 0;
+}
+
+.flex-container {
+ display: flex;
+}
+
+.form-multiline {
+ flex-wrap: wrap;
+}
+
+.form-multiline > div {
+ padding-bottom: 10px;
+}
+
+/* FORM LABELS */
+
+label {
+ font-weight: normal;
+ color: var(--body-quiet-color);
+ font-size: 0.8125rem;
+}
+
+.required label, label.required {
+ font-weight: bold;
+ color: var(--body-fg);
+}
+
+/* RADIO BUTTONS */
+
+form div.radiolist div {
+ padding-right: 7px;
+}
+
+form div.radiolist.inline div {
+ display: inline-block;
+}
+
+form div.radiolist label {
+ width: auto;
+}
+
+form div.radiolist input[type="radio"] {
+ margin: -2px 4px 0 0;
+ padding: 0;
+}
+
+form ul.inline {
+ margin-left: 0;
+ padding: 0;
+}
+
+form ul.inline li {
+ float: left;
+ padding-right: 7px;
+}
+
+/* ALIGNED FIELDSETS */
+
+.aligned label {
+ display: block;
+ padding: 4px 10px 0 0;
+ min-width: 160px;
+ width: 160px;
+ word-wrap: break-word;
+ line-height: 1;
+}
+
+.aligned label:not(.vCheckboxLabel):after {
+ content: '';
+ display: inline-block;
+ vertical-align: middle;
+ height: 1.625rem;
+}
+
+.aligned label + p, .aligned .checkbox-row + div.help, .aligned label + div.readonly {
+ padding: 6px 0;
+ margin-top: 0;
+ margin-bottom: 0;
+ margin-left: 0;
+ overflow-wrap: break-word;
+}
+
+.aligned ul label {
+ display: inline;
+ float: none;
+ width: auto;
+}
+
+.aligned .form-row input {
+ margin-bottom: 0;
+}
+
+.colMS .aligned .vLargeTextField, .colMS .aligned .vXMLLargeTextField {
+ width: 350px;
+}
+
+form .aligned ul {
+ margin-left: 160px;
+ padding-left: 10px;
+}
+
+form .aligned div.radiolist {
+ display: inline-block;
+ margin: 0;
+ padding: 0;
+}
+
+form .aligned p.help,
+form .aligned div.help {
+ margin-top: 0;
+ margin-left: 160px;
+ padding-left: 10px;
+}
+
+form .aligned p.date div.help.timezonewarning,
+form .aligned p.datetime div.help.timezonewarning,
+form .aligned p.time div.help.timezonewarning {
+ margin-left: 0;
+ padding-left: 0;
+ font-weight: normal;
+}
+
+form .aligned p.help:last-child,
+form .aligned div.help:last-child {
+ margin-bottom: 0;
+ padding-bottom: 0;
+}
+
+form .aligned input + p.help,
+form .aligned textarea + p.help,
+form .aligned select + p.help,
+form .aligned input + div.help,
+form .aligned textarea + div.help,
+form .aligned select + div.help {
+ margin-left: 160px;
+ padding-left: 10px;
+}
+
+form .aligned ul li {
+ list-style: none;
+}
+
+form .aligned table p {
+ margin-left: 0;
+ padding-left: 0;
+}
+
+.aligned .vCheckboxLabel {
+ float: none;
+ width: auto;
+ display: inline-block;
+ vertical-align: -3px;
+ padding: 0 0 5px 5px;
+}
+
+.aligned .vCheckboxLabel + p.help,
+.aligned .vCheckboxLabel + div.help {
+ margin-top: -4px;
+}
+
+.colM .aligned .vLargeTextField, .colM .aligned .vXMLLargeTextField {
+ width: 610px;
+}
+
+fieldset .fieldBox {
+ margin-right: 20px;
+}
+
+/* WIDE FIELDSETS */
+
+.wide label {
+ width: 200px;
+}
+
+form .wide p,
+form .wide ul.errorlist,
+form .wide input + p.help,
+form .wide input + div.help {
+ margin-left: 200px;
+}
+
+form .wide p.help,
+form .wide div.help {
+ padding-left: 50px;
+}
+
+form div.help ul {
+ padding-left: 0;
+ margin-left: 0;
+}
+
+.colM fieldset.wide .vLargeTextField, .colM fieldset.wide .vXMLLargeTextField {
+ width: 450px;
+}
+
+/* COLLAPSED FIELDSETS */
+
+fieldset.collapsed * {
+ display: none;
+}
+
+fieldset.collapsed h2, fieldset.collapsed {
+ display: block;
+}
+
+fieldset.collapsed {
+ border: 1px solid var(--hairline-color);
+ border-radius: 4px;
+ overflow: hidden;
+}
+
+fieldset.collapsed h2 {
+ background: var(--darkened-bg);
+ color: var(--body-quiet-color);
+}
+
+fieldset .collapse-toggle {
+ color: var(--header-link-color);
+}
+
+fieldset.collapsed .collapse-toggle {
+ background: transparent;
+ display: inline;
+ color: var(--link-fg);
+}
+
+/* MONOSPACE TEXTAREAS */
+
+fieldset.monospace textarea {
+ font-family: var(--font-family-monospace);
+}
+
+/* SUBMIT ROW */
+
+.submit-row {
+ padding: 12px 14px 12px;
+ margin: 0 0 20px;
+ background: var(--darkened-bg);
+ border: 1px solid var(--hairline-color);
+ border-radius: 4px;
+ overflow: hidden;
+ display: flex;
+ gap: 10px;
+ flex-wrap: wrap;
+}
+
+body.popup .submit-row {
+ overflow: auto;
+}
+
+.submit-row input {
+ height: 2.1875rem;
+ line-height: 0.9375rem;
+}
+
+.submit-row input, .submit-row a {
+ margin: 0;
+}
+
+.submit-row input.default {
+ text-transform: uppercase;
+}
+
+.submit-row a.deletelink {
+ margin-left: auto;
+}
+
+.submit-row a.deletelink {
+ display: block;
+ background: var(--delete-button-bg);
+ border-radius: 4px;
+ padding: 0.625rem 0.9375rem;
+ height: 0.9375rem;
+ line-height: 0.9375rem;
+ color: var(--button-fg);
+}
+
+.submit-row a.closelink {
+ display: inline-block;
+ background: var(--close-button-bg);
+ border-radius: 4px;
+ padding: 10px 15px;
+ height: 0.9375rem;
+ line-height: 0.9375rem;
+ color: var(--button-fg);
+}
+
+.submit-row a.deletelink:focus,
+.submit-row a.deletelink:hover,
+.submit-row a.deletelink:active {
+ background: var(--delete-button-hover-bg);
+ text-decoration: none;
+}
+
+.submit-row a.closelink:focus,
+.submit-row a.closelink:hover,
+.submit-row a.closelink:active {
+ background: var(--close-button-hover-bg);
+ text-decoration: none;
+}
+
+/* CUSTOM FORM FIELDS */
+
+.vSelectMultipleField {
+ vertical-align: top;
+}
+
+.vCheckboxField {
+ border: none;
+}
+
+.vDateField, .vTimeField {
+ margin-right: 2px;
+ margin-bottom: 4px;
+}
+
+.vDateField {
+ min-width: 6.85em;
+}
+
+.vTimeField {
+ min-width: 4.7em;
+}
+
+.vURLField {
+ width: 30em;
+}
+
+.vLargeTextField, .vXMLLargeTextField {
+ width: 48em;
+}
+
+.flatpages-flatpage #id_content {
+ height: 40.2em;
+}
+
+.module table .vPositiveSmallIntegerField {
+ width: 2.2em;
+}
+
+.vIntegerField {
+ width: 5em;
+}
+
+.vBigIntegerField {
+ width: 10em;
+}
+
+.vForeignKeyRawIdAdminField {
+ width: 5em;
+}
+
+.vTextField, .vUUIDField {
+ width: 20em;
+}
+
+/* INLINES */
+
+.inline-group {
+ padding: 0;
+ margin: 0 0 30px;
+}
+
+.inline-group thead th {
+ padding: 8px 10px;
+}
+
+.inline-group .aligned label {
+ width: 160px;
+}
+
+.inline-related {
+ position: relative;
+}
+
+.inline-related h3 {
+ margin: 0;
+ color: var(--body-quiet-color);
+ padding: 5px;
+ font-size: 0.8125rem;
+ background: var(--darkened-bg);
+ border-top: 1px solid var(--hairline-color);
+ border-bottom: 1px solid var(--hairline-color);
+}
+
+.inline-related h3 span.delete {
+ float: right;
+}
+
+.inline-related h3 span.delete label {
+ margin-left: 2px;
+ font-size: 0.6875rem;
+}
+
+.inline-related fieldset {
+ margin: 0;
+ background: var(--body-bg);
+ border: none;
+ width: 100%;
+}
+
+.inline-related fieldset.module h3 {
+ margin: 0;
+ padding: 2px 5px 3px 5px;
+ font-size: 0.6875rem;
+ text-align: left;
+ font-weight: bold;
+ background: #bcd;
+ color: var(--body-bg);
+}
+
+.inline-group .tabular fieldset.module {
+ border: none;
+}
+
+.inline-related.tabular fieldset.module table {
+ width: 100%;
+ overflow-x: scroll;
+}
+
+.last-related fieldset {
+ border: none;
+}
+
+.inline-group .tabular tr.has_original td {
+ padding-top: 2em;
+}
+
+.inline-group .tabular tr td.original {
+ padding: 2px 0 0 0;
+ width: 0;
+ _position: relative;
+}
+
+.inline-group .tabular th.original {
+ width: 0px;
+ padding: 0;
+}
+
+.inline-group .tabular td.original p {
+ position: absolute;
+ left: 0;
+ height: 1.1em;
+ padding: 2px 9px;
+ overflow: hidden;
+ font-size: 0.5625rem;
+ font-weight: bold;
+ color: var(--body-quiet-color);
+ _width: 700px;
+}
+
+.inline-group ul.tools {
+ padding: 0;
+ margin: 0;
+ list-style: none;
+}
+
+.inline-group ul.tools li {
+ display: inline;
+ padding: 0 5px;
+}
+
+.inline-group div.add-row,
+.inline-group .tabular tr.add-row td {
+ color: var(--body-quiet-color);
+ background: var(--darkened-bg);
+ padding: 8px 10px;
+ border-bottom: 1px solid var(--hairline-color);
+}
+
+.inline-group .tabular tr.add-row td {
+ padding: 8px 10px;
+ border-bottom: 1px solid var(--hairline-color);
+}
+
+.inline-group ul.tools a.add,
+.inline-group div.add-row a,
+.inline-group .tabular tr.add-row td a {
+ background: url(../img/icon-addlink.svg) 0 1px no-repeat;
+ padding-left: 16px;
+ font-size: 0.75rem;
+}
+
+.empty-form {
+ display: none;
+}
+
+/* RELATED FIELD ADD ONE / LOOKUP */
+
+.related-lookup {
+ margin-left: 5px;
+ display: inline-block;
+ vertical-align: middle;
+ background-repeat: no-repeat;
+ background-size: 14px;
+}
+
+.related-lookup {
+ width: 1rem;
+ height: 1rem;
+ background-image: url(../img/search.svg);
+}
+
+form .related-widget-wrapper ul {
+ display: inline-block;
+ margin-left: 0;
+ padding-left: 0;
+}
+
+.clearable-file-input input {
+ margin-top: 0;
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/css/login.css b/django_code/django_code/cloudmanager/templates/admin/css/login.css
new file mode 100644
index 0000000..389772f
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/css/login.css
@@ -0,0 +1,61 @@
+/* LOGIN FORM */
+
+.login {
+ background: var(--darkened-bg);
+ height: auto;
+}
+
+.login #header {
+ height: auto;
+ padding: 15px 16px;
+ justify-content: center;
+}
+
+.login #header h1 {
+ font-size: 1.125rem;
+ margin: 0;
+}
+
+.login #header h1 a {
+ color: var(--header-link-color);
+}
+
+.login #content {
+ padding: 20px 20px 0;
+}
+
+.login #container {
+ background: var(--body-bg);
+ border: 1px solid var(--hairline-color);
+ border-radius: 4px;
+ overflow: hidden;
+ width: 28em;
+ min-width: 300px;
+ margin: 100px auto;
+ height: auto;
+}
+
+.login .form-row {
+ padding: 4px 0;
+}
+
+.login .form-row label {
+ display: block;
+ line-height: 2em;
+}
+
+.login .form-row #id_username, .login .form-row #id_password {
+ padding: 8px;
+ width: 100%;
+ box-sizing: border-box;
+}
+
+.login .submit-row {
+ padding: 1em 0 0 0;
+ margin: 0;
+ text-align: center;
+}
+
+.login .password-reset-link {
+ text-align: center;
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/css/nav_sidebar.css b/django_code/django_code/cloudmanager/templates/admin/css/nav_sidebar.css
new file mode 100644
index 0000000..f76e6ce
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/css/nav_sidebar.css
@@ -0,0 +1,144 @@
+.sticky {
+ position: sticky;
+ top: 0;
+ max-height: 100vh;
+}
+
+.toggle-nav-sidebar {
+ z-index: 20;
+ left: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex: 0 0 23px;
+ width: 23px;
+ border: 0;
+ border-right: 1px solid var(--hairline-color);
+ background-color: var(--body-bg);
+ cursor: pointer;
+ font-size: 1.25rem;
+ color: var(--link-fg);
+ padding: 0;
+}
+
+[dir="rtl"] .toggle-nav-sidebar {
+ border-left: 1px solid var(--hairline-color);
+ border-right: 0;
+}
+
+.toggle-nav-sidebar:hover,
+.toggle-nav-sidebar:focus {
+ background-color: var(--darkened-bg);
+}
+
+#nav-sidebar {
+ z-index: 15;
+ flex: 0 0 275px;
+ left: -276px;
+ margin-left: -276px;
+ border-top: 1px solid transparent;
+ border-right: 1px solid var(--hairline-color);
+ background-color: var(--body-bg);
+ overflow: auto;
+}
+
+[dir="rtl"] #nav-sidebar {
+ border-left: 1px solid var(--hairline-color);
+ border-right: 0;
+ left: 0;
+ margin-left: 0;
+ right: -276px;
+ margin-right: -276px;
+}
+
+.toggle-nav-sidebar::before {
+ content: '\00BB';
+}
+
+.main.shifted .toggle-nav-sidebar::before {
+ content: '\00AB';
+}
+
+.main > #nav-sidebar {
+ visibility: hidden;
+}
+
+.main.shifted > #nav-sidebar {
+ margin-left: 0;
+ visibility: visible;
+}
+
+[dir="rtl"] .main.shifted > #nav-sidebar {
+ margin-right: 0;
+}
+
+#nav-sidebar .module th {
+ width: 100%;
+ overflow-wrap: anywhere;
+}
+
+#nav-sidebar .module th,
+#nav-sidebar .module caption {
+ padding-left: 16px;
+}
+
+#nav-sidebar .module td {
+ white-space: nowrap;
+}
+
+[dir="rtl"] #nav-sidebar .module th,
+[dir="rtl"] #nav-sidebar .module caption {
+ padding-left: 8px;
+ padding-right: 16px;
+}
+
+#nav-sidebar .current-app .section:link,
+#nav-sidebar .current-app .section:visited {
+ color: var(--header-color);
+ font-weight: bold;
+}
+
+#nav-sidebar .current-model {
+ background: var(--selected-row);
+}
+
+.main > #nav-sidebar + .content {
+ max-width: calc(100% - 23px);
+}
+
+.main.shifted > #nav-sidebar + .content {
+ max-width: calc(100% - 299px);
+}
+
+@media (max-width: 767px) {
+ #nav-sidebar, #toggle-nav-sidebar {
+ display: none;
+ }
+
+ .main > #nav-sidebar + .content,
+ .main.shifted > #nav-sidebar + .content {
+ max-width: 100%;
+ }
+}
+
+#nav-filter {
+ width: 100%;
+ box-sizing: border-box;
+ padding: 2px 5px;
+ margin: 5px 0;
+ border: 1px solid var(--border-color);
+ background-color: var(--darkened-bg);
+ color: var(--body-fg);
+}
+
+#nav-filter:focus {
+ border-color: var(--body-quiet-color);
+}
+
+#nav-filter.no-results {
+ background: var(--message-error-bg);
+}
+
+#nav-sidebar table {
+ width: 100%;
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/css/responsive.css b/django_code/django_code/cloudmanager/templates/admin/css/responsive.css
new file mode 100644
index 0000000..1d0a188
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/css/responsive.css
@@ -0,0 +1,999 @@
+/* Tablets */
+
+input[type="submit"], button {
+ -webkit-appearance: none;
+ appearance: none;
+}
+
+@media (max-width: 1024px) {
+ /* Basic */
+
+ html {
+ -webkit-text-size-adjust: 100%;
+ }
+
+ td, th {
+ padding: 10px;
+ font-size: 0.875rem;
+ }
+
+ .small {
+ font-size: 0.75rem;
+ }
+
+ /* Layout */
+
+ #container {
+ min-width: 0;
+ }
+
+ #content {
+ padding: 15px 20px 20px;
+ }
+
+ div.breadcrumbs {
+ padding: 10px 30px;
+ }
+
+ /* Header */
+
+ #header {
+ flex-direction: column;
+ padding: 15px 30px;
+ justify-content: flex-start;
+ }
+
+ #branding h1 {
+ margin: 0 0 8px;
+ line-height: 1.2;
+ }
+
+ #user-tools {
+ margin: 0;
+ font-weight: 400;
+ line-height: 1.85;
+ text-align: left;
+ }
+
+ #user-tools a {
+ display: inline-block;
+ line-height: 1.4;
+ }
+
+ /* Dashboard */
+
+ .dashboard #content {
+ width: auto;
+ }
+
+ #content-related {
+ margin-right: -290px;
+ }
+
+ .colSM #content-related {
+ margin-left: -290px;
+ }
+
+ .colMS {
+ margin-right: 290px;
+ }
+
+ .colSM {
+ margin-left: 290px;
+ }
+
+ .dashboard .module table td a {
+ padding-right: 0;
+ }
+
+ td .changelink, td .addlink {
+ font-size: 0.8125rem;
+ }
+
+ /* Changelist */
+
+ #toolbar {
+ border: none;
+ padding: 15px;
+ }
+
+ #changelist-search > div {
+ display: flex;
+ flex-wrap: nowrap;
+ max-width: 480px;
+ }
+
+ #changelist-search label {
+ line-height: 1.375rem;
+ }
+
+ #toolbar form #searchbar {
+ flex: 1 0 auto;
+ width: 0;
+ height: 1.375rem;
+ margin: 0 10px 0 6px;
+ }
+
+ #toolbar form input[type=submit] {
+ flex: 0 1 auto;
+ }
+
+ #changelist-search .quiet {
+ width: 0;
+ flex: 1 0 auto;
+ margin: 5px 0 0 25px;
+ }
+
+ #changelist .actions {
+ display: flex;
+ flex-wrap: wrap;
+ padding: 15px 0;
+ }
+
+ #changelist .actions label {
+ display: flex;
+ }
+
+ #changelist .actions select {
+ background: var(--body-bg);
+ }
+
+ #changelist .actions .button {
+ min-width: 48px;
+ margin: 0 10px;
+ }
+
+ #changelist .actions span.all,
+ #changelist .actions span.clear,
+ #changelist .actions span.question,
+ #changelist .actions span.action-counter {
+ font-size: 0.6875rem;
+ margin: 0 10px 0 0;
+ }
+
+ #changelist-filter {
+ flex-basis: 200px;
+ }
+
+ .change-list .filtered .results,
+ .change-list .filtered .paginator,
+ .filtered #toolbar,
+ .filtered .actions,
+
+ #changelist .paginator {
+ border-top-color: var(--hairline-color); /* XXX Is this used at all? */
+ }
+
+ #changelist .results + .paginator {
+ border-top: none;
+ }
+
+ /* Forms */
+
+ label {
+ font-size: 0.875rem;
+ }
+
+ .form-row input[type=text],
+ .form-row input[type=password],
+ .form-row input[type=email],
+ .form-row input[type=url],
+ .form-row input[type=tel],
+ .form-row input[type=number],
+ .form-row textarea,
+ .form-row select,
+ .form-row .vTextField {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 6px 8px;
+ min-height: 2.25rem;
+ font-size: 0.875rem;
+ }
+
+ .form-row select {
+ height: 2.25rem;
+ }
+
+ .form-row select[multiple] {
+ height: auto;
+ min-height: 0;
+ }
+
+ fieldset .fieldBox + .fieldBox {
+ margin-top: 10px;
+ padding-top: 10px;
+ border-top: 1px solid var(--hairline-color);
+ }
+
+ textarea {
+ max-width: 100%;
+ max-height: 120px;
+ }
+
+ .aligned label {
+ padding-top: 6px;
+ }
+
+ .aligned .related-lookup,
+ .aligned .datetimeshortcuts,
+ .aligned .related-lookup + strong {
+ align-self: center;
+ margin-left: 15px;
+ }
+
+ form .aligned div.radiolist {
+ margin-left: 2px;
+ }
+
+ .submit-row {
+ padding: 8px;
+ }
+
+ .submit-row a.deletelink {
+ padding: 10px 7px;
+ }
+
+ .button, input[type=submit], input[type=button], .submit-row input, a.button {
+ padding: 7px;
+ }
+
+ /* Related widget */
+
+ .related-widget-wrapper {
+ float: none;
+ }
+
+ .related-widget-wrapper-link + .selector {
+ max-width: calc(100% - 30px);
+ margin-right: 15px;
+ }
+
+ select + .related-widget-wrapper-link,
+ .related-widget-wrapper-link + .related-widget-wrapper-link {
+ margin-left: 10px;
+ }
+
+ /* Selector */
+
+ .selector {
+ display: flex;
+ width: 100%;
+ }
+
+ .selector .selector-filter {
+ display: flex;
+ align-items: center;
+ }
+
+ .selector .selector-filter label {
+ margin: 0 8px 0 0;
+ }
+
+ .selector .selector-filter input {
+ width: auto;
+ min-height: 0;
+ flex: 1 1;
+ }
+
+ .selector-available, .selector-chosen {
+ width: auto;
+ flex: 1 1;
+ display: flex;
+ flex-direction: column;
+ }
+
+ .selector select {
+ width: 100%;
+ flex: 1 0 auto;
+ margin-bottom: 5px;
+ }
+
+ .selector ul.selector-chooser {
+ width: 26px;
+ height: 52px;
+ padding: 2px 0;
+ margin: auto 15px;
+ border-radius: 20px;
+ transform: translateY(-10px);
+ }
+
+ .selector-add, .selector-remove {
+ width: 20px;
+ height: 20px;
+ background-size: 20px auto;
+ }
+
+ .selector-add {
+ background-position: 0 -120px;
+ }
+
+ .selector-remove {
+ background-position: 0 -80px;
+ }
+
+ a.selector-chooseall, a.selector-clearall {
+ align-self: center;
+ }
+
+ .stacked {
+ flex-direction: column;
+ max-width: 480px;
+ }
+
+ .stacked > * {
+ flex: 0 1 auto;
+ }
+
+ .stacked select {
+ margin-bottom: 0;
+ }
+
+ .stacked .selector-available, .stacked .selector-chosen {
+ width: auto;
+ }
+
+ .stacked ul.selector-chooser {
+ width: 52px;
+ height: 26px;
+ padding: 0 2px;
+ margin: 15px auto;
+ transform: none;
+ }
+
+ .stacked .selector-chooser li {
+ padding: 3px;
+ }
+
+ .stacked .selector-add, .stacked .selector-remove {
+ background-size: 20px auto;
+ }
+
+ .stacked .selector-add {
+ background-position: 0 -40px;
+ }
+
+ .stacked .active.selector-add {
+ background-position: 0 -40px;
+ }
+
+ .active.selector-add:focus, .active.selector-add:hover {
+ background-position: 0 -140px;
+ }
+
+ .stacked .active.selector-add:focus, .stacked .active.selector-add:hover {
+ background-position: 0 -60px;
+ }
+
+ .stacked .selector-remove {
+ background-position: 0 0;
+ }
+
+ .stacked .active.selector-remove {
+ background-position: 0 0;
+ }
+
+ .active.selector-remove:focus, .active.selector-remove:hover {
+ background-position: 0 -100px;
+ }
+
+ .stacked .active.selector-remove:focus, .stacked .active.selector-remove:hover {
+ background-position: 0 -20px;
+ }
+
+ .help-tooltip, .selector .help-icon {
+ display: none;
+ }
+
+ .datetime input {
+ width: 50%;
+ max-width: 120px;
+ }
+
+ .datetime span {
+ font-size: 0.8125rem;
+ }
+
+ .datetime .timezonewarning {
+ display: block;
+ font-size: 0.6875rem;
+ color: var(--body-quiet-color);
+ }
+
+ .datetimeshortcuts {
+ color: var(--border-color); /* XXX Redundant, .datetime span also sets #ccc */
+ }
+
+ .form-row .datetime input.vDateField, .form-row .datetime input.vTimeField {
+ width: 75%;
+ }
+
+ .inline-group {
+ overflow: auto;
+ }
+
+ /* Messages */
+
+ ul.messagelist li {
+ padding-left: 55px;
+ background-position: 30px 12px;
+ }
+
+ ul.messagelist li.error {
+ background-position: 30px 12px;
+ }
+
+ ul.messagelist li.warning {
+ background-position: 30px 14px;
+ }
+
+ /* Login */
+
+ .login #header {
+ padding: 15px 20px;
+ }
+
+ .login #branding h1 {
+ margin: 0;
+ }
+
+ /* GIS */
+
+ div.olMap {
+ max-width: calc(100vw - 30px);
+ max-height: 300px;
+ }
+
+ .olMap + .clear_features {
+ display: block;
+ margin-top: 10px;
+ }
+
+ /* Docs */
+
+ .module table.xfull {
+ width: 100%;
+ }
+
+ pre.literal-block {
+ overflow: auto;
+ }
+}
+
+/* Mobile */
+
+@media (max-width: 767px) {
+ /* Layout */
+
+ #header, #content, #footer {
+ padding: 15px;
+ }
+
+ #footer:empty {
+ padding: 0;
+ }
+
+ div.breadcrumbs {
+ padding: 10px 15px;
+ }
+
+ /* Dashboard */
+
+ .colMS, .colSM {
+ margin: 0;
+ }
+
+ #content-related, .colSM #content-related {
+ width: 100%;
+ margin: 0;
+ }
+
+ #content-related .module {
+ margin-bottom: 0;
+ }
+
+ #content-related .module h2 {
+ padding: 10px 15px;
+ font-size: 1rem;
+ }
+
+ /* Changelist */
+
+ #changelist {
+ align-items: stretch;
+ flex-direction: column;
+ }
+
+ #toolbar {
+ padding: 10px;
+ }
+
+ #changelist-filter {
+ margin-left: 0;
+ }
+
+ #changelist .actions label {
+ flex: 1 1;
+ }
+
+ #changelist .actions select {
+ flex: 1 0;
+ width: 100%;
+ }
+
+ #changelist .actions span {
+ flex: 1 0 100%;
+ }
+
+ #changelist-filter {
+ position: static;
+ width: auto;
+ margin-top: 30px;
+ }
+
+ .object-tools {
+ float: none;
+ margin: 0 0 15px;
+ padding: 0;
+ overflow: hidden;
+ }
+
+ .object-tools li {
+ height: auto;
+ margin-left: 0;
+ }
+
+ .object-tools li + li {
+ margin-left: 15px;
+ }
+
+ /* Forms */
+
+ .form-row {
+ padding: 15px 0;
+ }
+
+ .aligned .form-row,
+ .aligned .form-row > div {
+ max-width: 100vw;
+ }
+
+ .aligned .form-row > div {
+ width: calc(100vw - 30px);
+ }
+
+ .flex-container {
+ flex-flow: column;
+ }
+
+ .flex-container.checkbox-row {
+ flex-flow: row;
+ }
+
+ textarea {
+ max-width: none;
+ }
+
+ .vURLField {
+ width: auto;
+ }
+
+ fieldset .fieldBox + .fieldBox {
+ margin-top: 15px;
+ padding-top: 15px;
+ }
+
+ fieldset.collapsed .form-row {
+ display: none;
+ }
+
+ .aligned label {
+ width: 100%;
+ min-width: auto;
+ padding: 0 0 10px;
+ }
+
+ .aligned label:after {
+ max-height: 0;
+ }
+
+ .aligned .form-row input,
+ .aligned .form-row select,
+ .aligned .form-row textarea {
+ flex: 1 1 auto;
+ max-width: 100%;
+ }
+
+ .aligned .checkbox-row input {
+ flex: 0 1 auto;
+ margin: 0;
+ }
+
+ .aligned .vCheckboxLabel {
+ flex: 1 0;
+ padding: 1px 0 0 5px;
+ }
+
+ .aligned label + p,
+ .aligned label + div.help,
+ .aligned label + div.readonly {
+ padding: 0;
+ margin-left: 0;
+ }
+
+ .aligned p.file-upload {
+ font-size: 0.8125rem;
+ }
+
+ span.clearable-file-input {
+ margin-left: 15px;
+ }
+
+ span.clearable-file-input label {
+ font-size: 0.8125rem;
+ padding-bottom: 0;
+ }
+
+ .aligned .timezonewarning {
+ flex: 1 0 100%;
+ margin-top: 5px;
+ }
+
+ form .aligned .form-row div.help {
+ width: 100%;
+ margin: 5px 0 0;
+ padding: 0;
+ }
+
+ form .aligned ul,
+ form .aligned ul.errorlist {
+ margin-left: 0;
+ padding-left: 0;
+ }
+
+ form .aligned div.radiolist {
+ margin-top: 5px;
+ margin-right: 15px;
+ margin-bottom: -3px;
+ }
+
+ form .aligned div.radiolist:not(.inline) div + div {
+ margin-top: 5px;
+ }
+
+ /* Related widget */
+
+ .related-widget-wrapper {
+ width: 100%;
+ display: flex;
+ align-items: flex-start;
+ }
+
+ .related-widget-wrapper .selector {
+ order: 1;
+ }
+
+ .related-widget-wrapper > a {
+ order: 2;
+ }
+
+ .related-widget-wrapper .radiolist ~ a {
+ align-self: flex-end;
+ }
+
+ .related-widget-wrapper > select ~ a {
+ align-self: center;
+ }
+
+ select + .related-widget-wrapper-link,
+ .related-widget-wrapper-link + .related-widget-wrapper-link {
+ margin-left: 15px;
+ }
+
+ /* Selector */
+
+ .selector {
+ flex-direction: column;
+ }
+
+ .selector > * {
+ float: none;
+ }
+
+ .selector-available, .selector-chosen {
+ margin-bottom: 0;
+ flex: 1 1 auto;
+ }
+
+ .selector select {
+ max-height: 96px;
+ }
+
+ .selector ul.selector-chooser {
+ display: block;
+ float: none;
+ width: 52px;
+ height: 26px;
+ padding: 0 2px;
+ margin: 15px auto 20px;
+ transform: none;
+ }
+
+ .selector ul.selector-chooser li {
+ float: left;
+ }
+
+ .selector-remove {
+ background-position: 0 0;
+ }
+
+ .active.selector-remove:focus, .active.selector-remove:hover {
+ background-position: 0 -20px;
+ }
+
+ .selector-add {
+ background-position: 0 -40px;
+ }
+
+ .active.selector-add:focus, .active.selector-add:hover {
+ background-position: 0 -60px;
+ }
+
+ /* Inlines */
+
+ .inline-group[data-inline-type="stacked"] .inline-related {
+ border: 1px solid var(--hairline-color);
+ border-radius: 4px;
+ margin-top: 15px;
+ overflow: auto;
+ }
+
+ .inline-group[data-inline-type="stacked"] .inline-related > * {
+ box-sizing: border-box;
+ }
+
+ .inline-group[data-inline-type="stacked"] .inline-related .module {
+ padding: 0 10px;
+ }
+
+ .inline-group[data-inline-type="stacked"] .inline-related .module .form-row {
+ border-top: 1px solid var(--hairline-color);
+ border-bottom: none;
+ }
+
+ .inline-group[data-inline-type="stacked"] .inline-related .module .form-row:first-child {
+ border-top: none;
+ }
+
+ .inline-group[data-inline-type="stacked"] .inline-related h3 {
+ padding: 10px;
+ border-top-width: 0;
+ border-bottom-width: 2px;
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ }
+
+ .inline-group[data-inline-type="stacked"] .inline-related h3 .inline_label {
+ margin-right: auto;
+ }
+
+ .inline-group[data-inline-type="stacked"] .inline-related h3 span.delete {
+ float: none;
+ flex: 1 1 100%;
+ margin-top: 5px;
+ }
+
+ .inline-group[data-inline-type="stacked"] .aligned .form-row > div:not([class]) {
+ width: 100%;
+ }
+
+ .inline-group[data-inline-type="stacked"] .aligned label {
+ width: 100%;
+ }
+
+ .inline-group[data-inline-type="stacked"] div.add-row {
+ margin-top: 15px;
+ border: 1px solid var(--hairline-color);
+ border-radius: 4px;
+ }
+
+ .inline-group div.add-row,
+ .inline-group .tabular tr.add-row td {
+ padding: 0;
+ }
+
+ .inline-group div.add-row a,
+ .inline-group .tabular tr.add-row td a {
+ display: block;
+ padding: 8px 10px 8px 26px;
+ background-position: 8px 9px;
+ }
+
+ /* Submit row */
+
+ .submit-row {
+ padding: 10px;
+ margin: 0 0 15px;
+ flex-direction: column;
+ gap: 8px;
+ }
+
+ .submit-row input, .submit-row input.default, .submit-row a {
+ text-align: center;
+ }
+
+ .submit-row a.closelink {
+ padding: 10px 0;
+ text-align: center;
+ }
+
+ .submit-row a.deletelink {
+ margin: 0;
+ }
+
+ /* Messages */
+
+ ul.messagelist li {
+ padding-left: 40px;
+ background-position: 15px 12px;
+ }
+
+ ul.messagelist li.error {
+ background-position: 15px 12px;
+ }
+
+ ul.messagelist li.warning {
+ background-position: 15px 14px;
+ }
+
+ /* Paginator */
+
+ .paginator .this-page, .paginator a:link, .paginator a:visited {
+ padding: 4px 10px;
+ }
+
+ /* Login */
+
+ body.login {
+ padding: 0 15px;
+ }
+
+ .login #container {
+ width: auto;
+ max-width: 480px;
+ margin: 50px auto;
+ }
+
+ .login #header,
+ .login #content {
+ padding: 15px;
+ }
+
+ .login #content-main {
+ float: none;
+ }
+
+ .login .form-row {
+ padding: 0;
+ }
+
+ .login .form-row + .form-row {
+ margin-top: 15px;
+ }
+
+ .login .form-row label {
+ margin: 0 0 5px;
+ line-height: 1.2;
+ }
+
+ .login .submit-row {
+ padding: 15px 0 0;
+ }
+
+ .login br {
+ display: none;
+ }
+
+ .login .submit-row input {
+ margin: 0;
+ text-transform: uppercase;
+ }
+
+ .errornote {
+ margin: 0 0 20px;
+ padding: 8px 12px;
+ font-size: 0.8125rem;
+ }
+
+ /* Calendar and clock */
+
+ .calendarbox, .clockbox {
+ position: fixed !important;
+ top: 50% !important;
+ left: 50% !important;
+ transform: translate(-50%, -50%);
+ margin: 0;
+ border: none;
+ overflow: visible;
+ }
+
+ .calendarbox:before, .clockbox:before {
+ content: '';
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ width: 100vw;
+ height: 100vh;
+ background: rgba(0, 0, 0, 0.75);
+ transform: translate(-50%, -50%);
+ }
+
+ .calendarbox > *, .clockbox > * {
+ position: relative;
+ z-index: 1;
+ }
+
+ .calendarbox > div:first-child {
+ z-index: 2;
+ }
+
+ .calendarbox .calendar, .clockbox h2 {
+ border-radius: 4px 4px 0 0;
+ overflow: hidden;
+ }
+
+ .calendarbox .calendar-cancel, .clockbox .calendar-cancel {
+ border-radius: 0 0 4px 4px;
+ overflow: hidden;
+ }
+
+ .calendar-shortcuts {
+ padding: 10px 0;
+ font-size: 0.75rem;
+ line-height: 0.75rem;
+ }
+
+ .calendar-shortcuts a {
+ margin: 0 4px;
+ }
+
+ .timelist a {
+ background: var(--body-bg);
+ padding: 4px;
+ }
+
+ .calendar-cancel {
+ padding: 8px 10px;
+ }
+
+ .clockbox h2 {
+ padding: 8px 15px;
+ }
+
+ .calendar caption {
+ padding: 10px;
+ }
+
+ .calendarbox .calendarnav-previous, .calendarbox .calendarnav-next {
+ z-index: 1;
+ top: 10px;
+ }
+
+ /* History */
+
+ table#change-history tbody th, table#change-history tbody td {
+ font-size: 0.8125rem;
+ word-break: break-word;
+ }
+
+ table#change-history tbody th {
+ width: auto;
+ }
+
+ /* Docs */
+
+ table.model tbody th, table.model tbody td {
+ font-size: 0.8125rem;
+ word-break: break-word;
+ }
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/css/responsive_rtl.css b/django_code/django_code/cloudmanager/templates/admin/css/responsive_rtl.css
new file mode 100644
index 0000000..31dc8ff
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/css/responsive_rtl.css
@@ -0,0 +1,84 @@
+/* TABLETS */
+
+@media (max-width: 1024px) {
+ [dir="rtl"] .colMS {
+ margin-right: 0;
+ }
+
+ [dir="rtl"] #user-tools {
+ text-align: right;
+ }
+
+ [dir="rtl"] #changelist .actions label {
+ padding-left: 10px;
+ padding-right: 0;
+ }
+
+ [dir="rtl"] #changelist .actions select {
+ margin-left: 0;
+ margin-right: 15px;
+ }
+
+ [dir="rtl"] .change-list .filtered .results,
+ [dir="rtl"] .change-list .filtered .paginator,
+ [dir="rtl"] .filtered #toolbar,
+ [dir="rtl"] .filtered div.xfull,
+ [dir="rtl"] .filtered .actions,
+ [dir="rtl"] #changelist-filter {
+ margin-left: 0;
+ }
+
+ [dir="rtl"] .inline-group ul.tools a.add,
+ [dir="rtl"] .inline-group div.add-row a,
+ [dir="rtl"] .inline-group .tabular tr.add-row td a {
+ padding: 8px 26px 8px 10px;
+ background-position: calc(100% - 8px) 9px;
+ }
+
+ [dir="rtl"] .related-widget-wrapper-link + .selector {
+ margin-right: 0;
+ margin-left: 15px;
+ }
+
+ [dir="rtl"] .selector .selector-filter label {
+ margin-right: 0;
+ margin-left: 8px;
+ }
+
+ [dir="rtl"] .object-tools li {
+ float: right;
+ }
+
+ [dir="rtl"] .object-tools li + li {
+ margin-left: 0;
+ margin-right: 15px;
+ }
+
+ [dir="rtl"] .dashboard .module table td a {
+ padding-left: 0;
+ padding-right: 16px;
+ }
+}
+
+/* MOBILE */
+
+@media (max-width: 767px) {
+ [dir="rtl"] .aligned .related-lookup,
+ [dir="rtl"] .aligned .datetimeshortcuts {
+ margin-left: 0;
+ margin-right: 15px;
+ }
+
+ [dir="rtl"] .aligned ul,
+ [dir="rtl"] form .aligned ul.errorlist {
+ margin-right: 0;
+ }
+
+ [dir="rtl"] #changelist-filter {
+ margin-left: 0;
+ margin-right: 0;
+ }
+ [dir="rtl"] .aligned .vCheckboxLabel {
+ padding: 1px 5px 0 0;
+ }
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/css/rtl.css b/django_code/django_code/cloudmanager/templates/admin/css/rtl.css
new file mode 100644
index 0000000..c349a93
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/css/rtl.css
@@ -0,0 +1,298 @@
+/* GLOBAL */
+
+th {
+ text-align: right;
+}
+
+.module h2, .module caption {
+ text-align: right;
+}
+
+.module ul, .module ol {
+ margin-left: 0;
+ margin-right: 1.5em;
+}
+
+.viewlink, .addlink, .changelink {
+ padding-left: 0;
+ padding-right: 16px;
+ background-position: 100% 1px;
+}
+
+.deletelink {
+ padding-left: 0;
+ padding-right: 16px;
+ background-position: 100% 1px;
+}
+
+.object-tools {
+ float: left;
+}
+
+thead th:first-child,
+tfoot td:first-child {
+ border-left: none;
+}
+
+/* LAYOUT */
+
+#user-tools {
+ right: auto;
+ left: 0;
+ text-align: left;
+}
+
+div.breadcrumbs {
+ text-align: right;
+}
+
+#content-main {
+ float: right;
+}
+
+#content-related {
+ float: left;
+ margin-left: -300px;
+ margin-right: auto;
+}
+
+.colMS {
+ margin-left: 300px;
+ margin-right: 0;
+}
+
+/* SORTABLE TABLES */
+
+table thead th.sorted .sortoptions {
+ float: left;
+}
+
+thead th.sorted .text {
+ padding-right: 0;
+ padding-left: 42px;
+}
+
+/* dashboard styles */
+
+.dashboard .module table td a {
+ padding-left: .6em;
+ padding-right: 16px;
+}
+
+/* changelists styles */
+
+.change-list .filtered table {
+ border-left: none;
+ border-right: 0px none;
+}
+
+#changelist-filter {
+ border-left: none;
+ border-right: none;
+ margin-left: 0;
+ margin-right: 30px;
+}
+
+#changelist-filter li.selected {
+ border-left: none;
+ padding-left: 10px;
+ margin-left: 0;
+ border-right: 5px solid var(--hairline-color);
+ padding-right: 10px;
+ margin-right: -15px;
+}
+
+#changelist table tbody td:first-child, #changelist table tbody th:first-child {
+ border-right: none;
+ border-left: none;
+}
+
+.paginator .end {
+ margin-left: 6px;
+ margin-right: 0;
+}
+
+.paginator input {
+ margin-left: 0;
+ margin-right: auto;
+}
+
+/* FORMS */
+
+.aligned label {
+ padding: 0 0 3px 1em;
+}
+
+.submit-row a.deletelink {
+ margin-left: 0;
+ margin-right: auto;
+}
+
+.vDateField, .vTimeField {
+ margin-left: 2px;
+}
+
+.aligned .form-row input {
+ margin-left: 5px;
+}
+
+form .aligned ul {
+ margin-right: 163px;
+ padding-right: 10px;
+ margin-left: 0;
+ padding-left: 0;
+}
+
+form ul.inline li {
+ float: right;
+ padding-right: 0;
+ padding-left: 7px;
+}
+
+form .aligned p.help,
+form .aligned div.help {
+ margin-right: 160px;
+ padding-right: 10px;
+}
+
+form div.help ul,
+form .aligned .checkbox-row + .help,
+form .aligned p.date div.help.timezonewarning,
+form .aligned p.datetime div.help.timezonewarning,
+form .aligned p.time div.help.timezonewarning {
+ margin-right: 0;
+ padding-right: 0;
+}
+
+form .wide p.help, form .wide div.help {
+ padding-left: 0;
+ padding-right: 50px;
+}
+
+form .wide p,
+form .wide ul.errorlist,
+form .wide input + p.help,
+form .wide input + div.help {
+ margin-right: 200px;
+ margin-left: 0px;
+}
+
+.submit-row {
+ text-align: right;
+}
+
+fieldset .fieldBox {
+ margin-left: 20px;
+ margin-right: 0;
+}
+
+.errorlist li {
+ background-position: 100% 12px;
+ padding: 0;
+}
+
+.errornote {
+ background-position: 100% 12px;
+ padding: 10px 12px;
+}
+
+/* WIDGETS */
+
+.calendarnav-previous {
+ top: 0;
+ left: auto;
+ right: 10px;
+ background: url(../img/calendar-icons.svg) 0 -30px no-repeat;
+}
+
+.calendarbox .calendarnav-previous:focus,
+.calendarbox .calendarnav-previous:hover {
+ background-position: 0 -45px;
+}
+
+.calendarnav-next {
+ top: 0;
+ right: auto;
+ left: 10px;
+ background: url(../img/calendar-icons.svg) 0 0 no-repeat;
+}
+
+.calendarbox .calendarnav-next:focus,
+.calendarbox .calendarnav-next:hover {
+ background-position: 0 -15px;
+}
+
+.calendar caption, .calendarbox h2 {
+ text-align: center;
+}
+
+.selector {
+ float: right;
+}
+
+.selector .selector-filter {
+ text-align: right;
+}
+
+.selector-add {
+ background: url(../img/selector-icons.svg) 0 -64px no-repeat;
+}
+
+.active.selector-add:focus, .active.selector-add:hover {
+ background-position: 0 -80px;
+}
+
+.selector-remove {
+ background: url(../img/selector-icons.svg) 0 -96px no-repeat;
+}
+
+.active.selector-remove:focus, .active.selector-remove:hover {
+ background-position: 0 -112px;
+}
+
+a.selector-chooseall {
+ background: url(../img/selector-icons.svg) right -128px no-repeat;
+}
+
+a.active.selector-chooseall:focus, a.active.selector-chooseall:hover {
+ background-position: 100% -144px;
+}
+
+a.selector-clearall {
+ background: url(../img/selector-icons.svg) 0 -160px no-repeat;
+}
+
+a.active.selector-clearall:focus, a.active.selector-clearall:hover {
+ background-position: 0 -176px;
+}
+
+.inline-deletelink {
+ float: left;
+}
+
+form .form-row p.datetime {
+ overflow: hidden;
+}
+
+.related-widget-wrapper {
+ float: right;
+}
+
+/* MISC */
+
+.inline-related h2, .inline-group h2 {
+ text-align: right
+}
+
+.inline-related h3 span.delete {
+ padding-right: 20px;
+ padding-left: inherit;
+ left: 10px;
+ right: inherit;
+ float:left;
+}
+
+.inline-related h3 span.delete label {
+ margin-left: inherit;
+ margin-right: 2px;
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/css/vendor/select2/LICENSE-SELECT2.md b/django_code/django_code/cloudmanager/templates/admin/css/vendor/select2/LICENSE-SELECT2.md
new file mode 100644
index 0000000..8cb8a2b
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/css/vendor/select2/LICENSE-SELECT2.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2012-2017 Kevin Brown, Igor Vaynberg, and Select2 contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/django_code/django_code/cloudmanager/templates/admin/css/vendor/select2/select2.css b/django_code/django_code/cloudmanager/templates/admin/css/vendor/select2/select2.css
new file mode 100644
index 0000000..750b320
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/css/vendor/select2/select2.css
@@ -0,0 +1,481 @@
+.select2-container {
+ box-sizing: border-box;
+ display: inline-block;
+ margin: 0;
+ position: relative;
+ vertical-align: middle; }
+ .select2-container .select2-selection--single {
+ box-sizing: border-box;
+ cursor: pointer;
+ display: block;
+ height: 28px;
+ user-select: none;
+ -webkit-user-select: none; }
+ .select2-container .select2-selection--single .select2-selection__rendered {
+ display: block;
+ padding-left: 8px;
+ padding-right: 20px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap; }
+ .select2-container .select2-selection--single .select2-selection__clear {
+ position: relative; }
+ .select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered {
+ padding-right: 8px;
+ padding-left: 20px; }
+ .select2-container .select2-selection--multiple {
+ box-sizing: border-box;
+ cursor: pointer;
+ display: block;
+ min-height: 32px;
+ user-select: none;
+ -webkit-user-select: none; }
+ .select2-container .select2-selection--multiple .select2-selection__rendered {
+ display: inline-block;
+ overflow: hidden;
+ padding-left: 8px;
+ text-overflow: ellipsis;
+ white-space: nowrap; }
+ .select2-container .select2-search--inline {
+ float: left; }
+ .select2-container .select2-search--inline .select2-search__field {
+ box-sizing: border-box;
+ border: none;
+ font-size: 100%;
+ margin-top: 5px;
+ padding: 0; }
+ .select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button {
+ -webkit-appearance: none; }
+
+.select2-dropdown {
+ background-color: white;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ box-sizing: border-box;
+ display: block;
+ position: absolute;
+ left: -100000px;
+ width: 100%;
+ z-index: 1051; }
+
+.select2-results {
+ display: block; }
+
+.select2-results__options {
+ list-style: none;
+ margin: 0;
+ padding: 0; }
+
+.select2-results__option {
+ padding: 6px;
+ user-select: none;
+ -webkit-user-select: none; }
+ .select2-results__option[aria-selected] {
+ cursor: pointer; }
+
+.select2-container--open .select2-dropdown {
+ left: 0; }
+
+.select2-container--open .select2-dropdown--above {
+ border-bottom: none;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0; }
+
+.select2-container--open .select2-dropdown--below {
+ border-top: none;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0; }
+
+.select2-search--dropdown {
+ display: block;
+ padding: 4px; }
+ .select2-search--dropdown .select2-search__field {
+ padding: 4px;
+ width: 100%;
+ box-sizing: border-box; }
+ .select2-search--dropdown .select2-search__field::-webkit-search-cancel-button {
+ -webkit-appearance: none; }
+ .select2-search--dropdown.select2-search--hide {
+ display: none; }
+
+.select2-close-mask {
+ border: 0;
+ margin: 0;
+ padding: 0;
+ display: block;
+ position: fixed;
+ left: 0;
+ top: 0;
+ min-height: 100%;
+ min-width: 100%;
+ height: auto;
+ width: auto;
+ opacity: 0;
+ z-index: 99;
+ background-color: #fff;
+ filter: alpha(opacity=0); }
+
+.select2-hidden-accessible {
+ border: 0 !important;
+ clip: rect(0 0 0 0) !important;
+ -webkit-clip-path: inset(50%) !important;
+ clip-path: inset(50%) !important;
+ height: 1px !important;
+ overflow: hidden !important;
+ padding: 0 !important;
+ position: absolute !important;
+ width: 1px !important;
+ white-space: nowrap !important; }
+
+.select2-container--default .select2-selection--single {
+ background-color: #fff;
+ border: 1px solid #aaa;
+ border-radius: 4px; }
+ .select2-container--default .select2-selection--single .select2-selection__rendered {
+ color: #444;
+ line-height: 28px; }
+ .select2-container--default .select2-selection--single .select2-selection__clear {
+ cursor: pointer;
+ float: right;
+ font-weight: bold; }
+ .select2-container--default .select2-selection--single .select2-selection__placeholder {
+ color: #999; }
+ .select2-container--default .select2-selection--single .select2-selection__arrow {
+ height: 26px;
+ position: absolute;
+ top: 1px;
+ right: 1px;
+ width: 20px; }
+ .select2-container--default .select2-selection--single .select2-selection__arrow b {
+ border-color: #888 transparent transparent transparent;
+ border-style: solid;
+ border-width: 5px 4px 0 4px;
+ height: 0;
+ left: 50%;
+ margin-left: -4px;
+ margin-top: -2px;
+ position: absolute;
+ top: 50%;
+ width: 0; }
+
+.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear {
+ float: left; }
+
+.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow {
+ left: 1px;
+ right: auto; }
+
+.select2-container--default.select2-container--disabled .select2-selection--single {
+ background-color: #eee;
+ cursor: default; }
+ .select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear {
+ display: none; }
+
+.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b {
+ border-color: transparent transparent #888 transparent;
+ border-width: 0 4px 5px 4px; }
+
+.select2-container--default .select2-selection--multiple {
+ background-color: white;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ cursor: text; }
+ .select2-container--default .select2-selection--multiple .select2-selection__rendered {
+ box-sizing: border-box;
+ list-style: none;
+ margin: 0;
+ padding: 0 5px;
+ width: 100%; }
+ .select2-container--default .select2-selection--multiple .select2-selection__rendered li {
+ list-style: none; }
+ .select2-container--default .select2-selection--multiple .select2-selection__clear {
+ cursor: pointer;
+ float: right;
+ font-weight: bold;
+ margin-top: 5px;
+ margin-right: 10px;
+ padding: 1px; }
+ .select2-container--default .select2-selection--multiple .select2-selection__choice {
+ background-color: #e4e4e4;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ cursor: default;
+ float: left;
+ margin-right: 5px;
+ margin-top: 5px;
+ padding: 0 5px; }
+ .select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
+ color: #999;
+ cursor: pointer;
+ display: inline-block;
+ font-weight: bold;
+ margin-right: 2px; }
+ .select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
+ color: #333; }
+
+.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline {
+ float: right; }
+
+.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
+ margin-left: 5px;
+ margin-right: auto; }
+
+.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
+ margin-left: 2px;
+ margin-right: auto; }
+
+.select2-container--default.select2-container--focus .select2-selection--multiple {
+ border: solid black 1px;
+ outline: 0; }
+
+.select2-container--default.select2-container--disabled .select2-selection--multiple {
+ background-color: #eee;
+ cursor: default; }
+
+.select2-container--default.select2-container--disabled .select2-selection__choice__remove {
+ display: none; }
+
+.select2-container--default.select2-container--open.select2-container--above .select2-selection--single, .select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0; }
+
+.select2-container--default.select2-container--open.select2-container--below .select2-selection--single, .select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple {
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0; }
+
+.select2-container--default .select2-search--dropdown .select2-search__field {
+ border: 1px solid #aaa; }
+
+.select2-container--default .select2-search--inline .select2-search__field {
+ background: transparent;
+ border: none;
+ outline: 0;
+ box-shadow: none;
+ -webkit-appearance: textfield; }
+
+.select2-container--default .select2-results > .select2-results__options {
+ max-height: 200px;
+ overflow-y: auto; }
+
+.select2-container--default .select2-results__option[role=group] {
+ padding: 0; }
+
+.select2-container--default .select2-results__option[aria-disabled=true] {
+ color: #999; }
+
+.select2-container--default .select2-results__option[aria-selected=true] {
+ background-color: #ddd; }
+
+.select2-container--default .select2-results__option .select2-results__option {
+ padding-left: 1em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__group {
+ padding-left: 0; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -1em;
+ padding-left: 2em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -2em;
+ padding-left: 3em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -3em;
+ padding-left: 4em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -4em;
+ padding-left: 5em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -5em;
+ padding-left: 6em; }
+
+.select2-container--default .select2-results__option--highlighted[aria-selected] {
+ background-color: #5897fb;
+ color: white; }
+
+.select2-container--default .select2-results__group {
+ cursor: default;
+ display: block;
+ padding: 6px; }
+
+.select2-container--classic .select2-selection--single {
+ background-color: #f7f7f7;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ outline: 0;
+ background-image: -webkit-linear-gradient(top, white 50%, #eeeeee 100%);
+ background-image: -o-linear-gradient(top, white 50%, #eeeeee 100%);
+ background-image: linear-gradient(to bottom, white 50%, #eeeeee 100%);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }
+ .select2-container--classic .select2-selection--single:focus {
+ border: 1px solid #5897fb; }
+ .select2-container--classic .select2-selection--single .select2-selection__rendered {
+ color: #444;
+ line-height: 28px; }
+ .select2-container--classic .select2-selection--single .select2-selection__clear {
+ cursor: pointer;
+ float: right;
+ font-weight: bold;
+ margin-right: 10px; }
+ .select2-container--classic .select2-selection--single .select2-selection__placeholder {
+ color: #999; }
+ .select2-container--classic .select2-selection--single .select2-selection__arrow {
+ background-color: #ddd;
+ border: none;
+ border-left: 1px solid #aaa;
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+ height: 26px;
+ position: absolute;
+ top: 1px;
+ right: 1px;
+ width: 20px;
+ background-image: -webkit-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
+ background-image: -o-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
+ background-image: linear-gradient(to bottom, #eeeeee 50%, #cccccc 100%);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0); }
+ .select2-container--classic .select2-selection--single .select2-selection__arrow b {
+ border-color: #888 transparent transparent transparent;
+ border-style: solid;
+ border-width: 5px 4px 0 4px;
+ height: 0;
+ left: 50%;
+ margin-left: -4px;
+ margin-top: -2px;
+ position: absolute;
+ top: 50%;
+ width: 0; }
+
+.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear {
+ float: left; }
+
+.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow {
+ border: none;
+ border-right: 1px solid #aaa;
+ border-radius: 0;
+ border-top-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+ left: 1px;
+ right: auto; }
+
+.select2-container--classic.select2-container--open .select2-selection--single {
+ border: 1px solid #5897fb; }
+ .select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow {
+ background: transparent;
+ border: none; }
+ .select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b {
+ border-color: transparent transparent #888 transparent;
+ border-width: 0 4px 5px 4px; }
+
+.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single {
+ border-top: none;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ background-image: -webkit-linear-gradient(top, white 0%, #eeeeee 50%);
+ background-image: -o-linear-gradient(top, white 0%, #eeeeee 50%);
+ background-image: linear-gradient(to bottom, white 0%, #eeeeee 50%);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }
+
+.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single {
+ border-bottom: none;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+ background-image: -webkit-linear-gradient(top, #eeeeee 50%, white 100%);
+ background-image: -o-linear-gradient(top, #eeeeee 50%, white 100%);
+ background-image: linear-gradient(to bottom, #eeeeee 50%, white 100%);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0); }
+
+.select2-container--classic .select2-selection--multiple {
+ background-color: white;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ cursor: text;
+ outline: 0; }
+ .select2-container--classic .select2-selection--multiple:focus {
+ border: 1px solid #5897fb; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__rendered {
+ list-style: none;
+ margin: 0;
+ padding: 0 5px; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__clear {
+ display: none; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__choice {
+ background-color: #e4e4e4;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ cursor: default;
+ float: left;
+ margin-right: 5px;
+ margin-top: 5px;
+ padding: 0 5px; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__choice__remove {
+ color: #888;
+ cursor: pointer;
+ display: inline-block;
+ font-weight: bold;
+ margin-right: 2px; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover {
+ color: #555; }
+
+.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
+ float: right;
+ margin-left: 5px;
+ margin-right: auto; }
+
+.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
+ margin-left: 2px;
+ margin-right: auto; }
+
+.select2-container--classic.select2-container--open .select2-selection--multiple {
+ border: 1px solid #5897fb; }
+
+.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple {
+ border-top: none;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0; }
+
+.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple {
+ border-bottom: none;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0; }
+
+.select2-container--classic .select2-search--dropdown .select2-search__field {
+ border: 1px solid #aaa;
+ outline: 0; }
+
+.select2-container--classic .select2-search--inline .select2-search__field {
+ outline: 0;
+ box-shadow: none; }
+
+.select2-container--classic .select2-dropdown {
+ background-color: white;
+ border: 1px solid transparent; }
+
+.select2-container--classic .select2-dropdown--above {
+ border-bottom: none; }
+
+.select2-container--classic .select2-dropdown--below {
+ border-top: none; }
+
+.select2-container--classic .select2-results > .select2-results__options {
+ max-height: 200px;
+ overflow-y: auto; }
+
+.select2-container--classic .select2-results__option[role=group] {
+ padding: 0; }
+
+.select2-container--classic .select2-results__option[aria-disabled=true] {
+ color: grey; }
+
+.select2-container--classic .select2-results__option--highlighted[aria-selected] {
+ background-color: #3875d7;
+ color: white; }
+
+.select2-container--classic .select2-results__group {
+ cursor: default;
+ display: block;
+ padding: 6px; }
+
+.select2-container--classic.select2-container--open .select2-dropdown {
+ border-color: #5897fb; }
diff --git a/django_code/django_code/cloudmanager/templates/admin/css/vendor/select2/select2.min.css b/django_code/django_code/cloudmanager/templates/admin/css/vendor/select2/select2.min.css
new file mode 100644
index 0000000..7c18ad5
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/css/vendor/select2/select2.min.css
@@ -0,0 +1 @@
+.select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{position:relative}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline-block;overflow:hidden;padding-left:8px;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-search--inline{float:left}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;padding:0}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:white;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option[aria-selected]{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0 !important;clip:rect(0 0 0 0) !important;-webkit-clip-path:inset(50%) !important;clip-path:inset(50%) !important;height:1px !important;overflow:hidden !important;padding:0 !important;position:absolute !important;width:1px !important;white-space:nowrap !important}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--default .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text}.select2-container--default .select2-selection--multiple .select2-selection__rendered{box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--default .select2-selection--multiple .select2-selection__rendered li{list-style:none}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-top:5px;margin-right:10px;padding:1px}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{color:#999;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#333}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice,.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline{float:right}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid black 1px;outline:0}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--default .select2-search--dropdown .select2-search__field{border:1px solid #aaa}.select2-container--default .select2-search--inline .select2-search__field{background:transparent;border:none;outline:0;box-shadow:none;-webkit-appearance:textfield}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--default .select2-results__option[role=group]{padding:0}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#5897fb;color:white}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:#f7f7f7;border:1px solid #aaa;border-radius:4px;outline:0;background-image:-webkit-linear-gradient(top, #fff 50%, #eee 100%);background-image:-o-linear-gradient(top, #fff 50%, #eee 100%);background-image:linear-gradient(to bottom, #fff 50%, #eee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-right:10px}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eee 50%, #ccc 100%);background-image:-o-linear-gradient(top, #eee 50%, #ccc 100%);background-image:linear-gradient(to bottom, #eee 50%, #ccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0)}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, #fff 0%, #eee 50%);background-image:-o-linear-gradient(top, #fff 0%, #eee 50%);background-image:linear-gradient(to bottom, #fff 0%, #eee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eee 50%, #fff 100%);background-image:-o-linear-gradient(top, #eee 50%, #fff 100%);background-image:linear-gradient(to bottom, #eee 50%, #fff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;outline:0}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--multiple .select2-selection__rendered{list-style:none;margin:0;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{color:#888;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{float:right;margin-left:5px;margin-right:auto}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;box-shadow:none}.select2-container--classic .select2-dropdown{background-color:#fff;border:1px solid transparent}.select2-container--classic .select2-dropdown--above{border-bottom:none}.select2-container--classic .select2-dropdown--below{border-top:none}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--classic .select2-results__option[role=group]{padding:0}.select2-container--classic .select2-results__option[aria-disabled=true]{color:grey}.select2-container--classic .select2-results__option--highlighted[aria-selected]{background-color:#3875d7;color:#fff}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb}
diff --git a/django_code/django_code/cloudmanager/templates/admin/css/widgets.css b/django_code/django_code/cloudmanager/templates/admin/css/widgets.css
new file mode 100644
index 0000000..1104e8b
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/css/widgets.css
@@ -0,0 +1,604 @@
+/* SELECTOR (FILTER INTERFACE) */
+
+.selector {
+ width: 800px;
+ float: left;
+ display: flex;
+}
+
+.selector select {
+ width: 380px;
+ height: 17.2em;
+ flex: 1 0 auto;
+}
+
+.selector-available, .selector-chosen {
+ width: 380px;
+ text-align: center;
+ margin-bottom: 5px;
+ display: flex;
+ flex-direction: column;
+}
+
+.selector-available h2, .selector-chosen h2 {
+ border: 1px solid var(--border-color);
+ border-radius: 4px 4px 0 0;
+}
+
+.selector-chosen .list-footer-display {
+ border: 1px solid var(--border-color);
+ border-top: none;
+ border-radius: 0 0 4px 4px;
+ margin: 0 0 10px;
+ padding: 8px;
+ text-align: center;
+ background: var(--primary);
+ color: var(--header-link-color);
+ cursor: pointer;
+}
+.selector-chosen .list-footer-display__clear {
+ color: var(--breadcrumbs-fg);
+}
+
+.selector-chosen h2 {
+ background: var(--primary);
+ color: var(--header-link-color);
+}
+
+.selector .selector-available h2 {
+ background: var(--darkened-bg);
+ color: var(--body-quiet-color);
+}
+
+.selector .selector-filter {
+ border: 1px solid var(--border-color);
+ border-width: 0 1px;
+ padding: 8px;
+ color: var(--body-quiet-color);
+ font-size: 0.625rem;
+ margin: 0;
+ text-align: left;
+}
+
+.selector .selector-filter label,
+.inline-group .aligned .selector .selector-filter label {
+ float: left;
+ margin: 7px 0 0;
+ width: 18px;
+ height: 18px;
+ padding: 0;
+ overflow: hidden;
+ line-height: 1;
+ min-width: auto;
+}
+
+.selector .selector-available input,
+.selector .selector-chosen input {
+ width: 320px;
+ margin-left: 8px;
+}
+
+.selector ul.selector-chooser {
+ align-self: center;
+ width: 22px;
+ background-color: var(--selected-bg);
+ border-radius: 10px;
+ margin: 0 5px;
+ padding: 0;
+ transform: translateY(-17px);
+}
+
+.selector-chooser li {
+ margin: 0;
+ padding: 3px;
+ list-style-type: none;
+}
+
+.selector select {
+ padding: 0 10px;
+ margin: 0 0 10px;
+ border-radius: 0 0 4px 4px;
+}
+.selector .selector-chosen--with-filtered select {
+ margin: 0;
+ border-radius: 0;
+ height: 14em;
+}
+
+.selector .selector-chosen:not(.selector-chosen--with-filtered) .list-footer-display {
+ display: none;
+}
+
+.selector-add, .selector-remove {
+ width: 16px;
+ height: 16px;
+ display: block;
+ text-indent: -3000px;
+ overflow: hidden;
+ cursor: default;
+ opacity: 0.55;
+}
+
+.active.selector-add, .active.selector-remove {
+ opacity: 1;
+}
+
+.active.selector-add:hover, .active.selector-remove:hover {
+ cursor: pointer;
+}
+
+.selector-add {
+ background: url(../img/selector-icons.svg) 0 -96px no-repeat;
+}
+
+.active.selector-add:focus, .active.selector-add:hover {
+ background-position: 0 -112px;
+}
+
+.selector-remove {
+ background: url(../img/selector-icons.svg) 0 -64px no-repeat;
+}
+
+.active.selector-remove:focus, .active.selector-remove:hover {
+ background-position: 0 -80px;
+}
+
+a.selector-chooseall, a.selector-clearall {
+ display: inline-block;
+ height: 16px;
+ text-align: left;
+ margin: 1px auto 3px;
+ overflow: hidden;
+ font-weight: bold;
+ line-height: 16px;
+ color: var(--body-quiet-color);
+ text-decoration: none;
+ opacity: 0.55;
+}
+
+a.active.selector-chooseall:focus, a.active.selector-clearall:focus,
+a.active.selector-chooseall:hover, a.active.selector-clearall:hover {
+ color: var(--link-fg);
+}
+
+a.active.selector-chooseall, a.active.selector-clearall {
+ opacity: 1;
+}
+
+a.active.selector-chooseall:hover, a.active.selector-clearall:hover {
+ cursor: pointer;
+}
+
+a.selector-chooseall {
+ padding: 0 18px 0 0;
+ background: url(../img/selector-icons.svg) right -160px no-repeat;
+ cursor: default;
+}
+
+a.active.selector-chooseall:focus, a.active.selector-chooseall:hover {
+ background-position: 100% -176px;
+}
+
+a.selector-clearall {
+ padding: 0 0 0 18px;
+ background: url(../img/selector-icons.svg) 0 -128px no-repeat;
+ cursor: default;
+}
+
+a.active.selector-clearall:focus, a.active.selector-clearall:hover {
+ background-position: 0 -144px;
+}
+
+/* STACKED SELECTORS */
+
+.stacked {
+ float: left;
+ width: 490px;
+ display: block;
+}
+
+.stacked select {
+ width: 480px;
+ height: 10.1em;
+}
+
+.stacked .selector-available, .stacked .selector-chosen {
+ width: 480px;
+}
+
+.stacked .selector-available {
+ margin-bottom: 0;
+}
+
+.stacked .selector-available input {
+ width: 422px;
+}
+
+.stacked ul.selector-chooser {
+ height: 22px;
+ width: 50px;
+ margin: 0 0 10px 40%;
+ background-color: #eee;
+ border-radius: 10px;
+ transform: none;
+}
+
+.stacked .selector-chooser li {
+ float: left;
+ padding: 3px 3px 3px 5px;
+}
+
+.stacked .selector-chooseall, .stacked .selector-clearall {
+ display: none;
+}
+
+.stacked .selector-add {
+ background: url(../img/selector-icons.svg) 0 -32px no-repeat;
+ cursor: default;
+}
+
+.stacked .active.selector-add {
+ background-position: 0 -32px;
+ cursor: pointer;
+}
+
+.stacked .active.selector-add:focus, .stacked .active.selector-add:hover {
+ background-position: 0 -48px;
+ cursor: pointer;
+}
+
+.stacked .selector-remove {
+ background: url(../img/selector-icons.svg) 0 0 no-repeat;
+ cursor: default;
+}
+
+.stacked .active.selector-remove {
+ background-position: 0 0px;
+ cursor: pointer;
+}
+
+.stacked .active.selector-remove:focus, .stacked .active.selector-remove:hover {
+ background-position: 0 -16px;
+ cursor: pointer;
+}
+
+.selector .help-icon {
+ background: url(../img/icon-unknown.svg) 0 0 no-repeat;
+ display: inline-block;
+ vertical-align: middle;
+ margin: -2px 0 0 2px;
+ width: 13px;
+ height: 13px;
+}
+
+.selector .selector-chosen .help-icon {
+ background: url(../img/icon-unknown-alt.svg) 0 0 no-repeat;
+}
+
+.selector .search-label-icon {
+ background: url(../img/search.svg) 0 0 no-repeat;
+ display: inline-block;
+ height: 1.125rem;
+ width: 1.125rem;
+}
+
+/* DATE AND TIME */
+
+p.datetime {
+ line-height: 20px;
+ margin: 0;
+ padding: 0;
+ color: var(--body-quiet-color);
+ font-weight: bold;
+}
+
+.datetime span {
+ white-space: nowrap;
+ font-weight: normal;
+ font-size: 0.6875rem;
+ color: var(--body-quiet-color);
+}
+
+.datetime input, .form-row .datetime input.vDateField, .form-row .datetime input.vTimeField {
+ margin-left: 5px;
+ margin-bottom: 4px;
+}
+
+table p.datetime {
+ font-size: 0.6875rem;
+ margin-left: 0;
+ padding-left: 0;
+}
+
+.datetimeshortcuts .clock-icon, .datetimeshortcuts .date-icon {
+ position: relative;
+ display: inline-block;
+ vertical-align: middle;
+ height: 16px;
+ width: 16px;
+ overflow: hidden;
+}
+
+.datetimeshortcuts .clock-icon {
+ background: url(../img/icon-clock.svg) 0 0 no-repeat;
+}
+
+.datetimeshortcuts a:focus .clock-icon,
+.datetimeshortcuts a:hover .clock-icon {
+ background-position: 0 -16px;
+}
+
+.datetimeshortcuts .date-icon {
+ background: url(../img/icon-calendar.svg) 0 0 no-repeat;
+ top: -1px;
+}
+
+.datetimeshortcuts a:focus .date-icon,
+.datetimeshortcuts a:hover .date-icon {
+ background-position: 0 -16px;
+}
+
+.timezonewarning {
+ font-size: 0.6875rem;
+ color: var(--body-quiet-color);
+}
+
+/* URL */
+
+p.url {
+ line-height: 20px;
+ margin: 0;
+ padding: 0;
+ color: var(--body-quiet-color);
+ font-size: 0.6875rem;
+ font-weight: bold;
+}
+
+.url a {
+ font-weight: normal;
+}
+
+/* FILE UPLOADS */
+
+p.file-upload {
+ line-height: 20px;
+ margin: 0;
+ padding: 0;
+ color: var(--body-quiet-color);
+ font-size: 0.6875rem;
+ font-weight: bold;
+}
+
+.file-upload a {
+ font-weight: normal;
+}
+
+.file-upload .deletelink {
+ margin-left: 5px;
+}
+
+span.clearable-file-input label {
+ color: var(--body-fg);
+ font-size: 0.6875rem;
+ display: inline;
+ float: none;
+}
+
+/* CALENDARS & CLOCKS */
+
+.calendarbox, .clockbox {
+ margin: 5px auto;
+ font-size: 0.75rem;
+ width: 19em;
+ text-align: center;
+ background: var(--body-bg);
+ color: var(--body-fg);
+ border: 1px solid var(--hairline-color);
+ border-radius: 4px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
+ overflow: hidden;
+ position: relative;
+}
+
+.clockbox {
+ width: auto;
+}
+
+.calendar {
+ margin: 0;
+ padding: 0;
+}
+
+.calendar table {
+ margin: 0;
+ padding: 0;
+ border-collapse: collapse;
+ background: white;
+ width: 100%;
+}
+
+.calendar caption, .calendarbox h2 {
+ margin: 0;
+ text-align: center;
+ border-top: none;
+ font-weight: 700;
+ font-size: 0.75rem;
+ color: #333;
+ background: var(--accent);
+}
+
+.calendar th {
+ padding: 8px 5px;
+ background: var(--darkened-bg);
+ border-bottom: 1px solid var(--border-color);
+ font-weight: 400;
+ font-size: 0.75rem;
+ text-align: center;
+ color: var(--body-quiet-color);
+}
+
+.calendar td {
+ font-weight: 400;
+ font-size: 0.75rem;
+ text-align: center;
+ padding: 0;
+ border-top: 1px solid var(--hairline-color);
+ border-bottom: none;
+}
+
+.calendar td.selected a {
+ background: var(--primary);
+ color: var(--button-fg);
+}
+
+.calendar td.nonday {
+ background: var(--darkened-bg);
+}
+
+.calendar td.today a {
+ font-weight: 700;
+}
+
+.calendar td a, .timelist a {
+ display: block;
+ font-weight: 400;
+ padding: 6px;
+ text-decoration: none;
+ color: var(--body-quiet-color);
+}
+
+.calendar td a:focus, .timelist a:focus,
+.calendar td a:hover, .timelist a:hover {
+ background: var(--primary);
+ color: white;
+}
+
+.calendar td a:active, .timelist a:active {
+ background: var(--header-bg);
+ color: white;
+}
+
+.calendarnav {
+ font-size: 0.625rem;
+ text-align: center;
+ color: #ccc;
+ margin: 0;
+ padding: 1px 3px;
+}
+
+.calendarnav a:link, #calendarnav a:visited,
+#calendarnav a:focus, #calendarnav a:hover {
+ color: var(--body-quiet-color);
+}
+
+.calendar-shortcuts {
+ background: var(--body-bg);
+ color: var(--body-quiet-color);
+ font-size: 0.6875rem;
+ line-height: 0.6875rem;
+ border-top: 1px solid var(--hairline-color);
+ padding: 8px 0;
+}
+
+.calendarbox .calendarnav-previous, .calendarbox .calendarnav-next {
+ display: block;
+ position: absolute;
+ top: 8px;
+ width: 15px;
+ height: 15px;
+ text-indent: -9999px;
+ padding: 0;
+}
+
+.calendarnav-previous {
+ left: 10px;
+ background: url(../img/calendar-icons.svg) 0 0 no-repeat;
+}
+
+.calendarbox .calendarnav-previous:focus,
+.calendarbox .calendarnav-previous:hover {
+ background-position: 0 -15px;
+}
+
+.calendarnav-next {
+ right: 10px;
+ background: url(../img/calendar-icons.svg) 0 -30px no-repeat;
+}
+
+.calendarbox .calendarnav-next:focus,
+.calendarbox .calendarnav-next:hover {
+ background-position: 0 -45px;
+}
+
+.calendar-cancel {
+ margin: 0;
+ padding: 4px 0;
+ font-size: 0.75rem;
+ background: #eee;
+ border-top: 1px solid var(--border-color);
+ color: var(--body-fg);
+}
+
+.calendar-cancel:focus, .calendar-cancel:hover {
+ background: #ddd;
+}
+
+.calendar-cancel a {
+ color: black;
+ display: block;
+}
+
+ul.timelist, .timelist li {
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+}
+
+.timelist a {
+ padding: 2px;
+}
+
+/* EDIT INLINE */
+
+.inline-deletelink {
+ float: right;
+ text-indent: -9999px;
+ background: url(../img/inline-delete.svg) 0 0 no-repeat;
+ width: 16px;
+ height: 16px;
+ border: 0px none;
+}
+
+.inline-deletelink:focus, .inline-deletelink:hover {
+ cursor: pointer;
+}
+
+/* RELATED WIDGET WRAPPER */
+.related-widget-wrapper {
+ float: left; /* display properly in form rows with multiple fields */
+ overflow: hidden; /* clear floated contents */
+}
+
+.related-widget-wrapper-link {
+ opacity: 0.3;
+}
+
+.related-widget-wrapper-link:link {
+ opacity: .8;
+}
+
+.related-widget-wrapper-link:link:focus,
+.related-widget-wrapper-link:link:hover {
+ opacity: 1;
+}
+
+select + .related-widget-wrapper-link,
+.related-widget-wrapper-link + .related-widget-wrapper-link {
+ margin-left: 7px;
+}
+
+/* GIS MAPS */
+.dj_map {
+ width: 600px;
+ height: 400px;
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/img/LICENSE b/django_code/django_code/cloudmanager/templates/admin/img/LICENSE
new file mode 100644
index 0000000..a4faaa1
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/img/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Code Charm Ltd
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/django_code/django_code/cloudmanager/templates/admin/img/README.txt b/django_code/django_code/cloudmanager/templates/admin/img/README.txt
new file mode 100644
index 0000000..4eb2e49
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/img/README.txt
@@ -0,0 +1,7 @@
+All icons are taken from Font Awesome (http://fontawesome.io/) project.
+The Font Awesome font is licensed under the SIL OFL 1.1:
+- https://scripts.sil.org/OFL
+
+SVG icons source: https://github.com/encharm/Font-Awesome-SVG-PNG
+Font-Awesome-SVG-PNG is licensed under the MIT license (see file license
+in current folder).
diff --git a/django_code/django_code/cloudmanager/templates/admin/img/calendar-icons.svg b/django_code/django_code/cloudmanager/templates/admin/img/calendar-icons.svg
new file mode 100644
index 0000000..dbf21c3
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/img/calendar-icons.svg
@@ -0,0 +1,14 @@
+
diff --git a/django_code/django_code/cloudmanager/templates/admin/img/gis/move_vertex_off.svg b/django_code/django_code/cloudmanager/templates/admin/img/gis/move_vertex_off.svg
new file mode 100644
index 0000000..228854f
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/img/gis/move_vertex_off.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/django_code/django_code/cloudmanager/templates/admin/img/gis/move_vertex_on.svg b/django_code/django_code/cloudmanager/templates/admin/img/gis/move_vertex_on.svg
new file mode 100644
index 0000000..96b87fd
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/img/gis/move_vertex_on.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/django_code/django_code/cloudmanager/templates/admin/img/icon-addlink.svg b/django_code/django_code/cloudmanager/templates/admin/img/icon-addlink.svg
new file mode 100644
index 0000000..e004fb1
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/img/icon-addlink.svg
@@ -0,0 +1,3 @@
+
diff --git a/django_code/django_code/cloudmanager/templates/admin/img/icon-alert.svg b/django_code/django_code/cloudmanager/templates/admin/img/icon-alert.svg
new file mode 100644
index 0000000..e51ea83
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/img/icon-alert.svg
@@ -0,0 +1,3 @@
+
diff --git a/django_code/django_code/cloudmanager/templates/admin/img/icon-calendar.svg b/django_code/django_code/cloudmanager/templates/admin/img/icon-calendar.svg
new file mode 100644
index 0000000..97910a9
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/img/icon-calendar.svg
@@ -0,0 +1,9 @@
+
diff --git a/django_code/django_code/cloudmanager/templates/admin/img/icon-changelink.svg b/django_code/django_code/cloudmanager/templates/admin/img/icon-changelink.svg
new file mode 100644
index 0000000..bbb137a
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/img/icon-changelink.svg
@@ -0,0 +1,3 @@
+
diff --git a/django_code/django_code/cloudmanager/templates/admin/img/icon-clock.svg b/django_code/django_code/cloudmanager/templates/admin/img/icon-clock.svg
new file mode 100644
index 0000000..bf9985d
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/img/icon-clock.svg
@@ -0,0 +1,9 @@
+
diff --git a/django_code/django_code/cloudmanager/templates/admin/img/icon-deletelink.svg b/django_code/django_code/cloudmanager/templates/admin/img/icon-deletelink.svg
new file mode 100644
index 0000000..4059b15
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/img/icon-deletelink.svg
@@ -0,0 +1,3 @@
+
diff --git a/django_code/django_code/cloudmanager/templates/admin/img/icon-no.svg b/django_code/django_code/cloudmanager/templates/admin/img/icon-no.svg
new file mode 100644
index 0000000..2e0d383
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/img/icon-no.svg
@@ -0,0 +1,3 @@
+
diff --git a/django_code/django_code/cloudmanager/templates/admin/img/icon-unknown-alt.svg b/django_code/django_code/cloudmanager/templates/admin/img/icon-unknown-alt.svg
new file mode 100644
index 0000000..1c6b99f
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/img/icon-unknown-alt.svg
@@ -0,0 +1,3 @@
+
diff --git a/django_code/django_code/cloudmanager/templates/admin/img/icon-unknown.svg b/django_code/django_code/cloudmanager/templates/admin/img/icon-unknown.svg
new file mode 100644
index 0000000..50b4f97
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/img/icon-unknown.svg
@@ -0,0 +1,3 @@
+
diff --git a/django_code/django_code/cloudmanager/templates/admin/img/icon-viewlink.svg b/django_code/django_code/cloudmanager/templates/admin/img/icon-viewlink.svg
new file mode 100644
index 0000000..a1ca1d3
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/img/icon-viewlink.svg
@@ -0,0 +1,3 @@
+
diff --git a/django_code/django_code/cloudmanager/templates/admin/img/icon-yes.svg b/django_code/django_code/cloudmanager/templates/admin/img/icon-yes.svg
new file mode 100644
index 0000000..5883d87
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/img/icon-yes.svg
@@ -0,0 +1,3 @@
+
diff --git a/django_code/django_code/cloudmanager/templates/admin/img/inline-delete.svg b/django_code/django_code/cloudmanager/templates/admin/img/inline-delete.svg
new file mode 100644
index 0000000..17d1ad6
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/img/inline-delete.svg
@@ -0,0 +1,3 @@
+
diff --git a/django_code/django_code/cloudmanager/templates/admin/img/search.svg b/django_code/django_code/cloudmanager/templates/admin/img/search.svg
new file mode 100644
index 0000000..c8c69b2
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/img/search.svg
@@ -0,0 +1,3 @@
+
diff --git a/django_code/django_code/cloudmanager/templates/admin/img/selector-icons.svg b/django_code/django_code/cloudmanager/templates/admin/img/selector-icons.svg
new file mode 100644
index 0000000..926b8e2
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/img/selector-icons.svg
@@ -0,0 +1,34 @@
+
diff --git a/django_code/django_code/cloudmanager/templates/admin/img/sorting-icons.svg b/django_code/django_code/cloudmanager/templates/admin/img/sorting-icons.svg
new file mode 100644
index 0000000..7c31ec9
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/img/sorting-icons.svg
@@ -0,0 +1,19 @@
+
diff --git a/django_code/django_code/cloudmanager/templates/admin/img/tooltag-add.svg b/django_code/django_code/cloudmanager/templates/admin/img/tooltag-add.svg
new file mode 100644
index 0000000..1ca64ae
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/img/tooltag-add.svg
@@ -0,0 +1,3 @@
+
diff --git a/django_code/django_code/cloudmanager/templates/admin/img/tooltag-arrowright.svg b/django_code/django_code/cloudmanager/templates/admin/img/tooltag-arrowright.svg
new file mode 100644
index 0000000..b664d61
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/img/tooltag-arrowright.svg
@@ -0,0 +1,3 @@
+
diff --git a/django_code/django_code/cloudmanager/templates/admin/js/SelectBox.js b/django_code/django_code/cloudmanager/templates/admin/js/SelectBox.js
new file mode 100644
index 0000000..3db4ec7
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/js/SelectBox.js
@@ -0,0 +1,116 @@
+'use strict';
+{
+ const SelectBox = {
+ cache: {},
+ init: function(id) {
+ const box = document.getElementById(id);
+ SelectBox.cache[id] = [];
+ const cache = SelectBox.cache[id];
+ for (const node of box.options) {
+ cache.push({value: node.value, text: node.text, displayed: 1});
+ }
+ },
+ redisplay: function(id) {
+ // Repopulate HTML select box from cache
+ const box = document.getElementById(id);
+ const scroll_value_from_top = box.scrollTop;
+ box.innerHTML = '';
+ for (const node of SelectBox.cache[id]) {
+ if (node.displayed) {
+ const new_option = new Option(node.text, node.value, false, false);
+ // Shows a tooltip when hovering over the option
+ new_option.title = node.text;
+ box.appendChild(new_option);
+ }
+ }
+ box.scrollTop = scroll_value_from_top;
+ },
+ filter: function(id, text) {
+ // Redisplay the HTML select box, displaying only the choices containing ALL
+ // the words in text. (It's an AND search.)
+ const tokens = text.toLowerCase().split(/\s+/);
+ for (const node of SelectBox.cache[id]) {
+ node.displayed = 1;
+ const node_text = node.text.toLowerCase();
+ for (const token of tokens) {
+ if (!node_text.includes(token)) {
+ node.displayed = 0;
+ break; // Once the first token isn't found we're done
+ }
+ }
+ }
+ SelectBox.redisplay(id);
+ },
+ get_hidden_node_count(id) {
+ const cache = SelectBox.cache[id] || [];
+ return cache.filter(node => node.displayed === 0).length;
+ },
+ delete_from_cache: function(id, value) {
+ let delete_index = null;
+ const cache = SelectBox.cache[id];
+ for (const [i, node] of cache.entries()) {
+ if (node.value === value) {
+ delete_index = i;
+ break;
+ }
+ }
+ cache.splice(delete_index, 1);
+ },
+ add_to_cache: function(id, option) {
+ SelectBox.cache[id].push({value: option.value, text: option.text, displayed: 1});
+ },
+ cache_contains: function(id, value) {
+ // Check if an item is contained in the cache
+ for (const node of SelectBox.cache[id]) {
+ if (node.value === value) {
+ return true;
+ }
+ }
+ return false;
+ },
+ move: function(from, to) {
+ const from_box = document.getElementById(from);
+ for (const option of from_box.options) {
+ const option_value = option.value;
+ if (option.selected && SelectBox.cache_contains(from, option_value)) {
+ SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1});
+ SelectBox.delete_from_cache(from, option_value);
+ }
+ }
+ SelectBox.redisplay(from);
+ SelectBox.redisplay(to);
+ },
+ move_all: function(from, to) {
+ const from_box = document.getElementById(from);
+ for (const option of from_box.options) {
+ const option_value = option.value;
+ if (SelectBox.cache_contains(from, option_value)) {
+ SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1});
+ SelectBox.delete_from_cache(from, option_value);
+ }
+ }
+ SelectBox.redisplay(from);
+ SelectBox.redisplay(to);
+ },
+ sort: function(id) {
+ SelectBox.cache[id].sort(function(a, b) {
+ a = a.text.toLowerCase();
+ b = b.text.toLowerCase();
+ if (a > b) {
+ return 1;
+ }
+ if (a < b) {
+ return -1;
+ }
+ return 0;
+ } );
+ },
+ select_all: function(id) {
+ const box = document.getElementById(id);
+ for (const option of box.options) {
+ option.selected = true;
+ }
+ }
+ };
+ window.SelectBox = SelectBox;
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/js/SelectFilter2.js b/django_code/django_code/cloudmanager/templates/admin/js/SelectFilter2.js
new file mode 100644
index 0000000..9a4e0a3
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/js/SelectFilter2.js
@@ -0,0 +1,283 @@
+/*global SelectBox, gettext, interpolate, quickElement, SelectFilter*/
+/*
+SelectFilter2 - Turns a multiple-select box into a filter interface.
+
+Requires core.js and SelectBox.js.
+*/
+'use strict';
+{
+ window.SelectFilter = {
+ init: function(field_id, field_name, is_stacked) {
+ if (field_id.match(/__prefix__/)) {
+ // Don't initialize on empty forms.
+ return;
+ }
+ const from_box = document.getElementById(field_id);
+ from_box.id += '_from'; // change its ID
+ from_box.className = 'filtered';
+
+ for (const p of from_box.parentNode.getElementsByTagName('p')) {
+ if (p.classList.contains("info")) {
+ // Remove , because it just gets in the way.
+ from_box.parentNode.removeChild(p);
+ } else if (p.classList.contains("help")) {
+ // Move help text up to the top so it isn't below the select
+ // boxes or wrapped off on the side to the right of the add
+ // button:
+ from_box.parentNode.insertBefore(p, from_box.parentNode.firstChild);
+ }
+ }
+
+ //
or
+ const selector_div = quickElement('div', from_box.parentNode);
+ selector_div.className = is_stacked ? 'selector stacked' : 'selector';
+
+ //
+ const selector_available = quickElement('div', selector_div);
+ selector_available.className = 'selector-available';
+ const title_available = quickElement('h2', selector_available, interpolate(gettext('Available %s') + ' ', [field_name]));
+ quickElement(
+ 'span', title_available, '',
+ 'class', 'help help-tooltip help-icon',
+ 'title', interpolate(
+ gettext(
+ 'This is the list of available %s. You may choose some by ' +
+ 'selecting them in the box below and then clicking the ' +
+ '"Choose" arrow between the two boxes.'
+ ),
+ [field_name]
+ )
+ );
+
+ const filter_p = quickElement('p', selector_available, '', 'id', field_id + '_filter');
+ filter_p.className = 'selector-filter';
+
+ const search_filter_label = quickElement('label', filter_p, '', 'for', field_id + '_input');
+
+ quickElement(
+ 'span', search_filter_label, '',
+ 'class', 'help-tooltip search-label-icon',
+ 'title', interpolate(gettext("Type into this box to filter down the list of available %s."), [field_name])
+ );
+
+ filter_p.appendChild(document.createTextNode(' '));
+
+ const filter_input = quickElement('input', filter_p, '', 'type', 'text', 'placeholder', gettext("Filter"));
+ filter_input.id = field_id + '_input';
+
+ selector_available.appendChild(from_box);
+ const choose_all = quickElement('a', selector_available, gettext('Choose all'), 'title', interpolate(gettext('Click to choose all %s at once.'), [field_name]), 'href', '#', 'id', field_id + '_add_all_link');
+ choose_all.className = 'selector-chooseall';
+
+ //
+ const selector_chooser = quickElement('ul', selector_div);
+ selector_chooser.className = 'selector-chooser';
+ const add_link = quickElement('a', quickElement('li', selector_chooser), gettext('Choose'), 'title', gettext('Choose'), 'href', '#', 'id', field_id + '_add_link');
+ add_link.className = 'selector-add';
+ const remove_link = quickElement('a', quickElement('li', selector_chooser), gettext('Remove'), 'title', gettext('Remove'), 'href', '#', 'id', field_id + '_remove_link');
+ remove_link.className = 'selector-remove';
+
+ //
+ const selector_chosen = quickElement('div', selector_div, '', 'id', field_id + '_selector_chosen');
+ selector_chosen.className = 'selector-chosen';
+ const title_chosen = quickElement('h2', selector_chosen, interpolate(gettext('Chosen %s') + ' ', [field_name]));
+ quickElement(
+ 'span', title_chosen, '',
+ 'class', 'help help-tooltip help-icon',
+ 'title', interpolate(
+ gettext(
+ 'This is the list of chosen %s. You may remove some by ' +
+ 'selecting them in the box below and then clicking the ' +
+ '"Remove" arrow between the two boxes.'
+ ),
+ [field_name]
+ )
+ );
+
+ const filter_selected_p = quickElement('p', selector_chosen, '', 'id', field_id + '_filter_selected');
+ filter_selected_p.className = 'selector-filter';
+
+ const search_filter_selected_label = quickElement('label', filter_selected_p, '', 'for', field_id + '_selected_input');
+
+ quickElement(
+ 'span', search_filter_selected_label, '',
+ 'class', 'help-tooltip search-label-icon',
+ 'title', interpolate(gettext("Type into this box to filter down the list of selected %s."), [field_name])
+ );
+
+ filter_selected_p.appendChild(document.createTextNode(' '));
+
+ const filter_selected_input = quickElement('input', filter_selected_p, '', 'type', 'text', 'placeholder', gettext("Filter"));
+ filter_selected_input.id = field_id + '_selected_input';
+
+ const to_box = quickElement('select', selector_chosen, '', 'id', field_id + '_to', 'multiple', '', 'size', from_box.size, 'name', from_box.name);
+ to_box.className = 'filtered';
+
+ const warning_footer = quickElement('div', selector_chosen, '', 'class', 'list-footer-display');
+ quickElement('span', warning_footer, '', 'id', field_id + '_list-footer-display-text');
+ quickElement('span', warning_footer, ' (click to clear)', 'class', 'list-footer-display__clear');
+
+ const clear_all = quickElement('a', selector_chosen, gettext('Remove all'), 'title', interpolate(gettext('Click to remove all chosen %s at once.'), [field_name]), 'href', '#', 'id', field_id + '_remove_all_link');
+ clear_all.className = 'selector-clearall';
+
+ from_box.name = from_box.name + '_old';
+
+ // Set up the JavaScript event handlers for the select box filter interface
+ const move_selection = function(e, elem, move_func, from, to) {
+ if (elem.classList.contains('active')) {
+ move_func(from, to);
+ SelectFilter.refresh_icons(field_id);
+ SelectFilter.refresh_filtered_selects(field_id);
+ SelectFilter.refresh_filtered_warning(field_id);
+ }
+ e.preventDefault();
+ };
+ choose_all.addEventListener('click', function(e) {
+ move_selection(e, this, SelectBox.move_all, field_id + '_from', field_id + '_to');
+ });
+ add_link.addEventListener('click', function(e) {
+ move_selection(e, this, SelectBox.move, field_id + '_from', field_id + '_to');
+ });
+ remove_link.addEventListener('click', function(e) {
+ move_selection(e, this, SelectBox.move, field_id + '_to', field_id + '_from');
+ });
+ clear_all.addEventListener('click', function(e) {
+ move_selection(e, this, SelectBox.move_all, field_id + '_to', field_id + '_from');
+ });
+ warning_footer.addEventListener('click', function(e) {
+ filter_selected_input.value = '';
+ SelectBox.filter(field_id + '_to', '');
+ SelectFilter.refresh_filtered_warning(field_id);
+ SelectFilter.refresh_icons(field_id);
+ });
+ filter_input.addEventListener('keypress', function(e) {
+ SelectFilter.filter_key_press(e, field_id, '_from', '_to');
+ });
+ filter_input.addEventListener('keyup', function(e) {
+ SelectFilter.filter_key_up(e, field_id, '_from');
+ });
+ filter_input.addEventListener('keydown', function(e) {
+ SelectFilter.filter_key_down(e, field_id, '_from', '_to');
+ });
+ filter_selected_input.addEventListener('keypress', function(e) {
+ SelectFilter.filter_key_press(e, field_id, '_to', '_from');
+ });
+ filter_selected_input.addEventListener('keyup', function(e) {
+ SelectFilter.filter_key_up(e, field_id, '_to', '_selected_input');
+ });
+ filter_selected_input.addEventListener('keydown', function(e) {
+ SelectFilter.filter_key_down(e, field_id, '_to', '_from');
+ });
+ selector_div.addEventListener('change', function(e) {
+ if (e.target.tagName === 'SELECT') {
+ SelectFilter.refresh_icons(field_id);
+ }
+ });
+ selector_div.addEventListener('dblclick', function(e) {
+ if (e.target.tagName === 'OPTION') {
+ if (e.target.closest('select').id === field_id + '_to') {
+ SelectBox.move(field_id + '_to', field_id + '_from');
+ } else {
+ SelectBox.move(field_id + '_from', field_id + '_to');
+ }
+ SelectFilter.refresh_icons(field_id);
+ }
+ });
+ from_box.closest('form').addEventListener('submit', function() {
+ SelectBox.filter(field_id + '_to', '');
+ SelectBox.select_all(field_id + '_to');
+ });
+ SelectBox.init(field_id + '_from');
+ SelectBox.init(field_id + '_to');
+ // Move selected from_box options to to_box
+ SelectBox.move(field_id + '_from', field_id + '_to');
+
+ // Initial icon refresh
+ SelectFilter.refresh_icons(field_id);
+ },
+ any_selected: function(field) {
+ // Temporarily add the required attribute and check validity.
+ field.required = true;
+ const any_selected = field.checkValidity();
+ field.required = false;
+ return any_selected;
+ },
+ refresh_filtered_warning: function(field_id) {
+ const count = SelectBox.get_hidden_node_count(field_id + '_to');
+ const selector = document.getElementById(field_id + '_selector_chosen');
+ const warning = document.getElementById(field_id + '_list-footer-display-text');
+ selector.className = selector.className.replace('selector-chosen--with-filtered', '');
+ warning.textContent = interpolate(ngettext(
+ '%s selected option not visible',
+ '%s selected options not visible',
+ count
+ ), [count]);
+ if(count > 0) {
+ selector.className += ' selector-chosen--with-filtered';
+ }
+ },
+ refresh_filtered_selects: function(field_id) {
+ SelectBox.filter(field_id + '_from', document.getElementById(field_id + "_input").value);
+ SelectBox.filter(field_id + '_to', document.getElementById(field_id + "_selected_input").value);
+ },
+ refresh_icons: function(field_id) {
+ const from = document.getElementById(field_id + '_from');
+ const to = document.getElementById(field_id + '_to');
+ // Active if at least one item is selected
+ document.getElementById(field_id + '_add_link').classList.toggle('active', SelectFilter.any_selected(from));
+ document.getElementById(field_id + '_remove_link').classList.toggle('active', SelectFilter.any_selected(to));
+ // Active if the corresponding box isn't empty
+ document.getElementById(field_id + '_add_all_link').classList.toggle('active', from.querySelector('option'));
+ document.getElementById(field_id + '_remove_all_link').classList.toggle('active', to.querySelector('option'));
+ SelectFilter.refresh_filtered_warning(field_id);
+ },
+ filter_key_press: function(event, field_id, source, target) {
+ const source_box = document.getElementById(field_id + source);
+ // don't submit form if user pressed Enter
+ if ((event.which && event.which === 13) || (event.keyCode && event.keyCode === 13)) {
+ source_box.selectedIndex = 0;
+ SelectBox.move(field_id + source, field_id + target);
+ source_box.selectedIndex = 0;
+ event.preventDefault();
+ }
+ },
+ filter_key_up: function(event, field_id, source, filter_input) {
+ const input = filter_input || '_input';
+ const source_box = document.getElementById(field_id + source);
+ const temp = source_box.selectedIndex;
+ SelectBox.filter(field_id + source, document.getElementById(field_id + input).value);
+ source_box.selectedIndex = temp;
+ SelectFilter.refresh_filtered_warning(field_id);
+ SelectFilter.refresh_icons(field_id);
+ },
+ filter_key_down: function(event, field_id, source, target) {
+ const source_box = document.getElementById(field_id + source);
+ // right key (39) or left key (37)
+ const direction = source === '_from' ? 39 : 37;
+ // right arrow -- move across
+ if ((event.which && event.which === direction) || (event.keyCode && event.keyCode === direction)) {
+ const old_index = source_box.selectedIndex;
+ SelectBox.move(field_id + source, field_id + target);
+ SelectFilter.refresh_filtered_selects(field_id);
+ SelectFilter.refresh_filtered_warning(field_id);
+ source_box.selectedIndex = (old_index === source_box.length) ? source_box.length - 1 : old_index;
+ return;
+ }
+ // down arrow -- wrap around
+ if ((event.which && event.which === 40) || (event.keyCode && event.keyCode === 40)) {
+ source_box.selectedIndex = (source_box.length === source_box.selectedIndex + 1) ? 0 : source_box.selectedIndex + 1;
+ }
+ // up arrow -- wrap around
+ if ((event.which && event.which === 38) || (event.keyCode && event.keyCode === 38)) {
+ source_box.selectedIndex = (source_box.selectedIndex === 0) ? source_box.length - 1 : source_box.selectedIndex - 1;
+ }
+ }
+ };
+
+ window.addEventListener('load', function(e) {
+ document.querySelectorAll('select.selectfilter, select.selectfilterstacked').forEach(function(el) {
+ const data = el.dataset;
+ SelectFilter.init(el.id, data.fieldName, parseInt(data.isStacked, 10));
+ });
+ });
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/js/actions.js b/django_code/django_code/cloudmanager/templates/admin/js/actions.js
new file mode 100644
index 0000000..20a5c14
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/js/actions.js
@@ -0,0 +1,201 @@
+/*global gettext, interpolate, ngettext*/
+'use strict';
+{
+ function show(selector) {
+ document.querySelectorAll(selector).forEach(function(el) {
+ el.classList.remove('hidden');
+ });
+ }
+
+ function hide(selector) {
+ document.querySelectorAll(selector).forEach(function(el) {
+ el.classList.add('hidden');
+ });
+ }
+
+ function showQuestion(options) {
+ hide(options.acrossClears);
+ show(options.acrossQuestions);
+ hide(options.allContainer);
+ }
+
+ function showClear(options) {
+ show(options.acrossClears);
+ hide(options.acrossQuestions);
+ document.querySelector(options.actionContainer).classList.remove(options.selectedClass);
+ show(options.allContainer);
+ hide(options.counterContainer);
+ }
+
+ function reset(options) {
+ hide(options.acrossClears);
+ hide(options.acrossQuestions);
+ hide(options.allContainer);
+ show(options.counterContainer);
+ }
+
+ function clearAcross(options) {
+ reset(options);
+ const acrossInputs = document.querySelectorAll(options.acrossInput);
+ acrossInputs.forEach(function(acrossInput) {
+ acrossInput.value = 0;
+ });
+ document.querySelector(options.actionContainer).classList.remove(options.selectedClass);
+ }
+
+ function checker(actionCheckboxes, options, checked) {
+ if (checked) {
+ showQuestion(options);
+ } else {
+ reset(options);
+ }
+ actionCheckboxes.forEach(function(el) {
+ el.checked = checked;
+ el.closest('tr').classList.toggle(options.selectedClass, checked);
+ });
+ }
+
+ function updateCounter(actionCheckboxes, options) {
+ const sel = Array.from(actionCheckboxes).filter(function(el) {
+ return el.checked;
+ }).length;
+ const counter = document.querySelector(options.counterContainer);
+ // data-actions-icnt is defined in the generated HTML
+ // and contains the total amount of objects in the queryset
+ const actions_icnt = Number(counter.dataset.actionsIcnt);
+ counter.textContent = interpolate(
+ ngettext('%(sel)s of %(cnt)s selected', '%(sel)s of %(cnt)s selected', sel), {
+ sel: sel,
+ cnt: actions_icnt
+ }, true);
+ const allToggle = document.getElementById(options.allToggleId);
+ allToggle.checked = sel === actionCheckboxes.length;
+ if (allToggle.checked) {
+ showQuestion(options);
+ } else {
+ clearAcross(options);
+ }
+ }
+
+ const defaults = {
+ actionContainer: "div.actions",
+ counterContainer: "span.action-counter",
+ allContainer: "div.actions span.all",
+ acrossInput: "div.actions input.select-across",
+ acrossQuestions: "div.actions span.question",
+ acrossClears: "div.actions span.clear",
+ allToggleId: "action-toggle",
+ selectedClass: "selected"
+ };
+
+ window.Actions = function(actionCheckboxes, options) {
+ options = Object.assign({}, defaults, options);
+ let list_editable_changed = false;
+ let lastChecked = null;
+ let shiftPressed = false;
+
+ document.addEventListener('keydown', (event) => {
+ shiftPressed = event.shiftKey;
+ });
+
+ document.addEventListener('keyup', (event) => {
+ shiftPressed = event.shiftKey;
+ });
+
+ document.getElementById(options.allToggleId).addEventListener('click', function(event) {
+ checker(actionCheckboxes, options, this.checked);
+ updateCounter(actionCheckboxes, options);
+ });
+
+ document.querySelectorAll(options.acrossQuestions + " a").forEach(function(el) {
+ el.addEventListener('click', function(event) {
+ event.preventDefault();
+ const acrossInputs = document.querySelectorAll(options.acrossInput);
+ acrossInputs.forEach(function(acrossInput) {
+ acrossInput.value = 1;
+ });
+ showClear(options);
+ });
+ });
+
+ document.querySelectorAll(options.acrossClears + " a").forEach(function(el) {
+ el.addEventListener('click', function(event) {
+ event.preventDefault();
+ document.getElementById(options.allToggleId).checked = false;
+ clearAcross(options);
+ checker(actionCheckboxes, options, false);
+ updateCounter(actionCheckboxes, options);
+ });
+ });
+
+ function affectedCheckboxes(target, withModifier) {
+ const multiSelect = (lastChecked && withModifier && lastChecked !== target);
+ if (!multiSelect) {
+ return [target];
+ }
+ const checkboxes = Array.from(actionCheckboxes);
+ const targetIndex = checkboxes.findIndex(el => el === target);
+ const lastCheckedIndex = checkboxes.findIndex(el => el === lastChecked);
+ const startIndex = Math.min(targetIndex, lastCheckedIndex);
+ const endIndex = Math.max(targetIndex, lastCheckedIndex);
+ const filtered = checkboxes.filter((el, index) => (startIndex <= index) && (index <= endIndex));
+ return filtered;
+ };
+
+ Array.from(document.getElementById('result_list').tBodies).forEach(function(el) {
+ el.addEventListener('change', function(event) {
+ const target = event.target;
+ if (target.classList.contains('action-select')) {
+ const checkboxes = affectedCheckboxes(target, shiftPressed);
+ checker(checkboxes, options, target.checked);
+ updateCounter(actionCheckboxes, options);
+ lastChecked = target;
+ } else {
+ list_editable_changed = true;
+ }
+ });
+ });
+
+ document.querySelector('#changelist-form button[name=index]').addEventListener('click', function(event) {
+ if (list_editable_changed) {
+ const confirmed = confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost."));
+ if (!confirmed) {
+ event.preventDefault();
+ }
+ }
+ });
+
+ const el = document.querySelector('#changelist-form input[name=_save]');
+ // The button does not exist if no fields are editable.
+ if (el) {
+ el.addEventListener('click', function(event) {
+ if (document.querySelector('[name=action]').value) {
+ const text = list_editable_changed
+ ? gettext("You have selected an action, but you haven’t saved your changes to individual fields yet. Please click OK to save. You’ll need to re-run the action.")
+ : gettext("You have selected an action, and you haven’t made any changes on individual fields. You’re probably looking for the Go button rather than the Save button.");
+ if (!confirm(text)) {
+ event.preventDefault();
+ }
+ }
+ });
+ }
+ };
+
+ // Call function fn when the DOM is loaded and ready. If it is already
+ // loaded, call the function now.
+ // http://youmightnotneedjquery.com/#ready
+ function ready(fn) {
+ if (document.readyState !== 'loading') {
+ fn();
+ } else {
+ document.addEventListener('DOMContentLoaded', fn);
+ }
+ }
+
+ ready(function() {
+ const actionsEls = document.querySelectorAll('tr input.action-select');
+ if (actionsEls.length > 0) {
+ Actions(actionsEls);
+ }
+ });
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/js/admin/DateTimeShortcuts.js b/django_code/django_code/cloudmanager/templates/admin/js/admin/DateTimeShortcuts.js
new file mode 100644
index 0000000..aa1cae9
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/js/admin/DateTimeShortcuts.js
@@ -0,0 +1,408 @@
+/*global Calendar, findPosX, findPosY, get_format, gettext, gettext_noop, interpolate, ngettext, quickElement*/
+// Inserts shortcut buttons after all of the following:
+//
+//
+'use strict';
+{
+ const DateTimeShortcuts = {
+ calendars: [],
+ calendarInputs: [],
+ clockInputs: [],
+ clockHours: {
+ default_: [
+ [gettext_noop('Now'), -1],
+ [gettext_noop('Midnight'), 0],
+ [gettext_noop('6 a.m.'), 6],
+ [gettext_noop('Noon'), 12],
+ [gettext_noop('6 p.m.'), 18]
+ ]
+ },
+ dismissClockFunc: [],
+ dismissCalendarFunc: [],
+ calendarDivName1: 'calendarbox', // name of calendar
that gets toggled
+ calendarDivName2: 'calendarin', // name of
that contains calendar
+ calendarLinkName: 'calendarlink', // name of the link that is used to toggle
+ clockDivName: 'clockbox', // name of clock
that gets toggled
+ clockLinkName: 'clocklink', // name of the link that is used to toggle
+ shortCutsClass: 'datetimeshortcuts', // class of the clock and cal shortcuts
+ timezoneWarningClass: 'timezonewarning', // class of the warning for timezone mismatch
+ timezoneOffset: 0,
+ init: function() {
+ const serverOffset = document.body.dataset.adminUtcOffset;
+ if (serverOffset) {
+ const localOffset = new Date().getTimezoneOffset() * -60;
+ DateTimeShortcuts.timezoneOffset = localOffset - serverOffset;
+ }
+
+ for (const inp of document.getElementsByTagName('input')) {
+ if (inp.type === 'text' && inp.classList.contains('vTimeField')) {
+ DateTimeShortcuts.addClock(inp);
+ DateTimeShortcuts.addTimezoneWarning(inp);
+ }
+ else if (inp.type === 'text' && inp.classList.contains('vDateField')) {
+ DateTimeShortcuts.addCalendar(inp);
+ DateTimeShortcuts.addTimezoneWarning(inp);
+ }
+ }
+ },
+ // Return the current time while accounting for the server timezone.
+ now: function() {
+ const serverOffset = document.body.dataset.adminUtcOffset;
+ if (serverOffset) {
+ const localNow = new Date();
+ const localOffset = localNow.getTimezoneOffset() * -60;
+ localNow.setTime(localNow.getTime() + 1000 * (serverOffset - localOffset));
+ return localNow;
+ } else {
+ return new Date();
+ }
+ },
+ // Add a warning when the time zone in the browser and backend do not match.
+ addTimezoneWarning: function(inp) {
+ const warningClass = DateTimeShortcuts.timezoneWarningClass;
+ let timezoneOffset = DateTimeShortcuts.timezoneOffset / 3600;
+
+ // Only warn if there is a time zone mismatch.
+ if (!timezoneOffset) {
+ return;
+ }
+
+ // Check if warning is already there.
+ if (inp.parentNode.querySelectorAll('.' + warningClass).length) {
+ return;
+ }
+
+ let message;
+ if (timezoneOffset > 0) {
+ message = ngettext(
+ 'Note: You are %s hour ahead of server time.',
+ 'Note: You are %s hours ahead of server time.',
+ timezoneOffset
+ );
+ }
+ else {
+ timezoneOffset *= -1;
+ message = ngettext(
+ 'Note: You are %s hour behind server time.',
+ 'Note: You are %s hours behind server time.',
+ timezoneOffset
+ );
+ }
+ message = interpolate(message, [timezoneOffset]);
+
+ const warning = document.createElement('div');
+ warning.classList.add('help', warningClass);
+ warning.textContent = message;
+ inp.parentNode.appendChild(warning);
+ },
+ // Add clock widget to a given field
+ addClock: function(inp) {
+ const num = DateTimeShortcuts.clockInputs.length;
+ DateTimeShortcuts.clockInputs[num] = inp;
+ DateTimeShortcuts.dismissClockFunc[num] = function() { DateTimeShortcuts.dismissClock(num); return true; };
+
+ // Shortcut links (clock icon and "Now" link)
+ const shortcuts_span = document.createElement('span');
+ shortcuts_span.className = DateTimeShortcuts.shortCutsClass;
+ inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling);
+ const now_link = document.createElement('a');
+ now_link.href = "#";
+ now_link.textContent = gettext('Now');
+ now_link.addEventListener('click', function(e) {
+ e.preventDefault();
+ DateTimeShortcuts.handleClockQuicklink(num, -1);
+ });
+ const clock_link = document.createElement('a');
+ clock_link.href = '#';
+ clock_link.id = DateTimeShortcuts.clockLinkName + num;
+ clock_link.addEventListener('click', function(e) {
+ e.preventDefault();
+ // avoid triggering the document click handler to dismiss the clock
+ e.stopPropagation();
+ DateTimeShortcuts.openClock(num);
+ });
+
+ quickElement(
+ 'span', clock_link, '',
+ 'class', 'clock-icon',
+ 'title', gettext('Choose a Time')
+ );
+ shortcuts_span.appendChild(document.createTextNode('\u00A0'));
+ shortcuts_span.appendChild(now_link);
+ shortcuts_span.appendChild(document.createTextNode('\u00A0|\u00A0'));
+ shortcuts_span.appendChild(clock_link);
+
+ // Create clock link div
+ //
+ // Markup looks like:
+ //
+ //
Choose a time
+ //
+ //
Cancel
+ //
+
+ const clock_box = document.createElement('div');
+ clock_box.style.display = 'none';
+ clock_box.style.position = 'absolute';
+ clock_box.className = 'clockbox module';
+ clock_box.id = DateTimeShortcuts.clockDivName + num;
+ document.body.appendChild(clock_box);
+ clock_box.addEventListener('click', function(e) { e.stopPropagation(); });
+
+ quickElement('h2', clock_box, gettext('Choose a time'));
+ const time_list = quickElement('ul', clock_box);
+ time_list.className = 'timelist';
+ // The list of choices can be overridden in JavaScript like this:
+ // DateTimeShortcuts.clockHours.name = [['3 a.m.', 3]];
+ // where name is the name attribute of the
.
+ const name = typeof DateTimeShortcuts.clockHours[inp.name] === 'undefined' ? 'default_' : inp.name;
+ DateTimeShortcuts.clockHours[name].forEach(function(element) {
+ const time_link = quickElement('a', quickElement('li', time_list), gettext(element[0]), 'href', '#');
+ time_link.addEventListener('click', function(e) {
+ e.preventDefault();
+ DateTimeShortcuts.handleClockQuicklink(num, element[1]);
+ });
+ });
+
+ const cancel_p = quickElement('p', clock_box);
+ cancel_p.className = 'calendar-cancel';
+ const cancel_link = quickElement('a', cancel_p, gettext('Cancel'), 'href', '#');
+ cancel_link.addEventListener('click', function(e) {
+ e.preventDefault();
+ DateTimeShortcuts.dismissClock(num);
+ });
+
+ document.addEventListener('keyup', function(event) {
+ if (event.which === 27) {
+ // ESC key closes popup
+ DateTimeShortcuts.dismissClock(num);
+ event.preventDefault();
+ }
+ });
+ },
+ openClock: function(num) {
+ const clock_box = document.getElementById(DateTimeShortcuts.clockDivName + num);
+ const clock_link = document.getElementById(DateTimeShortcuts.clockLinkName + num);
+
+ // Recalculate the clockbox position
+ // is it left-to-right or right-to-left layout ?
+ if (window.getComputedStyle(document.body).direction !== 'rtl') {
+ clock_box.style.left = findPosX(clock_link) + 17 + 'px';
+ }
+ else {
+ // since style's width is in em, it'd be tough to calculate
+ // px value of it. let's use an estimated px for now
+ clock_box.style.left = findPosX(clock_link) - 110 + 'px';
+ }
+ clock_box.style.top = Math.max(0, findPosY(clock_link) - 30) + 'px';
+
+ // Show the clock box
+ clock_box.style.display = 'block';
+ document.addEventListener('click', DateTimeShortcuts.dismissClockFunc[num]);
+ },
+ dismissClock: function(num) {
+ document.getElementById(DateTimeShortcuts.clockDivName + num).style.display = 'none';
+ document.removeEventListener('click', DateTimeShortcuts.dismissClockFunc[num]);
+ },
+ handleClockQuicklink: function(num, val) {
+ let d;
+ if (val === -1) {
+ d = DateTimeShortcuts.now();
+ }
+ else {
+ d = new Date(1970, 1, 1, val, 0, 0, 0);
+ }
+ DateTimeShortcuts.clockInputs[num].value = d.strftime(get_format('TIME_INPUT_FORMATS')[0]);
+ DateTimeShortcuts.clockInputs[num].focus();
+ DateTimeShortcuts.dismissClock(num);
+ },
+ // Add calendar widget to a given field.
+ addCalendar: function(inp) {
+ const num = DateTimeShortcuts.calendars.length;
+
+ DateTimeShortcuts.calendarInputs[num] = inp;
+ DateTimeShortcuts.dismissCalendarFunc[num] = function() { DateTimeShortcuts.dismissCalendar(num); return true; };
+
+ // Shortcut links (calendar icon and "Today" link)
+ const shortcuts_span = document.createElement('span');
+ shortcuts_span.className = DateTimeShortcuts.shortCutsClass;
+ inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling);
+ const today_link = document.createElement('a');
+ today_link.href = '#';
+ today_link.appendChild(document.createTextNode(gettext('Today')));
+ today_link.addEventListener('click', function(e) {
+ e.preventDefault();
+ DateTimeShortcuts.handleCalendarQuickLink(num, 0);
+ });
+ const cal_link = document.createElement('a');
+ cal_link.href = '#';
+ cal_link.id = DateTimeShortcuts.calendarLinkName + num;
+ cal_link.addEventListener('click', function(e) {
+ e.preventDefault();
+ // avoid triggering the document click handler to dismiss the calendar
+ e.stopPropagation();
+ DateTimeShortcuts.openCalendar(num);
+ });
+ quickElement(
+ 'span', cal_link, '',
+ 'class', 'date-icon',
+ 'title', gettext('Choose a Date')
+ );
+ shortcuts_span.appendChild(document.createTextNode('\u00A0'));
+ shortcuts_span.appendChild(today_link);
+ shortcuts_span.appendChild(document.createTextNode('\u00A0|\u00A0'));
+ shortcuts_span.appendChild(cal_link);
+
+ // Create calendarbox div.
+ //
+ // Markup looks like:
+ //
+ //
+ //
+ // ‹
+ // › February 2003
+ //
+ //
+ //
+ //
+ //
+ //
Cancel
+ //
+ const cal_box = document.createElement('div');
+ cal_box.style.display = 'none';
+ cal_box.style.position = 'absolute';
+ cal_box.className = 'calendarbox module';
+ cal_box.id = DateTimeShortcuts.calendarDivName1 + num;
+ document.body.appendChild(cal_box);
+ cal_box.addEventListener('click', function(e) { e.stopPropagation(); });
+
+ // next-prev links
+ const cal_nav = quickElement('div', cal_box);
+ const cal_nav_prev = quickElement('a', cal_nav, '<', 'href', '#');
+ cal_nav_prev.className = 'calendarnav-previous';
+ cal_nav_prev.addEventListener('click', function(e) {
+ e.preventDefault();
+ DateTimeShortcuts.drawPrev(num);
+ });
+
+ const cal_nav_next = quickElement('a', cal_nav, '>', 'href', '#');
+ cal_nav_next.className = 'calendarnav-next';
+ cal_nav_next.addEventListener('click', function(e) {
+ e.preventDefault();
+ DateTimeShortcuts.drawNext(num);
+ });
+
+ // main box
+ const cal_main = quickElement('div', cal_box, '', 'id', DateTimeShortcuts.calendarDivName2 + num);
+ cal_main.className = 'calendar';
+ DateTimeShortcuts.calendars[num] = new Calendar(DateTimeShortcuts.calendarDivName2 + num, DateTimeShortcuts.handleCalendarCallback(num));
+ DateTimeShortcuts.calendars[num].drawCurrent();
+
+ // calendar shortcuts
+ const shortcuts = quickElement('div', cal_box);
+ shortcuts.className = 'calendar-shortcuts';
+ let day_link = quickElement('a', shortcuts, gettext('Yesterday'), 'href', '#');
+ day_link.addEventListener('click', function(e) {
+ e.preventDefault();
+ DateTimeShortcuts.handleCalendarQuickLink(num, -1);
+ });
+ shortcuts.appendChild(document.createTextNode('\u00A0|\u00A0'));
+ day_link = quickElement('a', shortcuts, gettext('Today'), 'href', '#');
+ day_link.addEventListener('click', function(e) {
+ e.preventDefault();
+ DateTimeShortcuts.handleCalendarQuickLink(num, 0);
+ });
+ shortcuts.appendChild(document.createTextNode('\u00A0|\u00A0'));
+ day_link = quickElement('a', shortcuts, gettext('Tomorrow'), 'href', '#');
+ day_link.addEventListener('click', function(e) {
+ e.preventDefault();
+ DateTimeShortcuts.handleCalendarQuickLink(num, +1);
+ });
+
+ // cancel bar
+ const cancel_p = quickElement('p', cal_box);
+ cancel_p.className = 'calendar-cancel';
+ const cancel_link = quickElement('a', cancel_p, gettext('Cancel'), 'href', '#');
+ cancel_link.addEventListener('click', function(e) {
+ e.preventDefault();
+ DateTimeShortcuts.dismissCalendar(num);
+ });
+ document.addEventListener('keyup', function(event) {
+ if (event.which === 27) {
+ // ESC key closes popup
+ DateTimeShortcuts.dismissCalendar(num);
+ event.preventDefault();
+ }
+ });
+ },
+ openCalendar: function(num) {
+ const cal_box = document.getElementById(DateTimeShortcuts.calendarDivName1 + num);
+ const cal_link = document.getElementById(DateTimeShortcuts.calendarLinkName + num);
+ const inp = DateTimeShortcuts.calendarInputs[num];
+
+ // Determine if the current value in the input has a valid date.
+ // If so, draw the calendar with that date's year and month.
+ if (inp.value) {
+ const format = get_format('DATE_INPUT_FORMATS')[0];
+ const selected = inp.value.strptime(format);
+ const year = selected.getUTCFullYear();
+ const month = selected.getUTCMonth() + 1;
+ const re = /\d{4}/;
+ if (re.test(year.toString()) && month >= 1 && month <= 12) {
+ DateTimeShortcuts.calendars[num].drawDate(month, year, selected);
+ }
+ }
+
+ // Recalculate the clockbox position
+ // is it left-to-right or right-to-left layout ?
+ if (window.getComputedStyle(document.body).direction !== 'rtl') {
+ cal_box.style.left = findPosX(cal_link) + 17 + 'px';
+ }
+ else {
+ // since style's width is in em, it'd be tough to calculate
+ // px value of it. let's use an estimated px for now
+ cal_box.style.left = findPosX(cal_link) - 180 + 'px';
+ }
+ cal_box.style.top = Math.max(0, findPosY(cal_link) - 75) + 'px';
+
+ cal_box.style.display = 'block';
+ document.addEventListener('click', DateTimeShortcuts.dismissCalendarFunc[num]);
+ },
+ dismissCalendar: function(num) {
+ document.getElementById(DateTimeShortcuts.calendarDivName1 + num).style.display = 'none';
+ document.removeEventListener('click', DateTimeShortcuts.dismissCalendarFunc[num]);
+ },
+ drawPrev: function(num) {
+ DateTimeShortcuts.calendars[num].drawPreviousMonth();
+ },
+ drawNext: function(num) {
+ DateTimeShortcuts.calendars[num].drawNextMonth();
+ },
+ handleCalendarCallback: function(num) {
+ const format = get_format('DATE_INPUT_FORMATS')[0];
+ return function(y, m, d) {
+ DateTimeShortcuts.calendarInputs[num].value = new Date(y, m - 1, d).strftime(format);
+ DateTimeShortcuts.calendarInputs[num].focus();
+ document.getElementById(DateTimeShortcuts.calendarDivName1 + num).style.display = 'none';
+ };
+ },
+ handleCalendarQuickLink: function(num, offset) {
+ const d = DateTimeShortcuts.now();
+ d.setDate(d.getDate() + offset);
+ DateTimeShortcuts.calendarInputs[num].value = d.strftime(get_format('DATE_INPUT_FORMATS')[0]);
+ DateTimeShortcuts.calendarInputs[num].focus();
+ DateTimeShortcuts.dismissCalendar(num);
+ }
+ };
+
+ window.addEventListener('load', DateTimeShortcuts.init);
+ window.DateTimeShortcuts = DateTimeShortcuts;
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/js/admin/RelatedObjectLookups.js b/django_code/django_code/cloudmanager/templates/admin/js/admin/RelatedObjectLookups.js
new file mode 100644
index 0000000..afb6b66
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/js/admin/RelatedObjectLookups.js
@@ -0,0 +1,238 @@
+/*global SelectBox, interpolate*/
+// Handles related-objects functionality: lookup link for raw_id_fields
+// and Add Another links.
+'use strict';
+{
+ const $ = django.jQuery;
+ let popupIndex = 0;
+ const relatedWindows = [];
+
+ function dismissChildPopups() {
+ relatedWindows.forEach(function(win) {
+ if(!win.closed) {
+ win.dismissChildPopups();
+ win.close();
+ }
+ });
+ }
+
+ function setPopupIndex() {
+ if(document.getElementsByName("_popup").length > 0) {
+ const index = window.name.lastIndexOf("__") + 2;
+ popupIndex = parseInt(window.name.substring(index));
+ } else {
+ popupIndex = 0;
+ }
+ }
+
+ function addPopupIndex(name) {
+ return name + "__" + (popupIndex + 1);
+ }
+
+ function removePopupIndex(name) {
+ return name.replace(new RegExp("__" + (popupIndex + 1) + "$"), '');
+ }
+
+ function showAdminPopup(triggeringLink, name_regexp, add_popup) {
+ const name = addPopupIndex(triggeringLink.id.replace(name_regexp, ''));
+ const href = new URL(triggeringLink.href);
+ if (add_popup) {
+ href.searchParams.set('_popup', 1);
+ }
+ const win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
+ relatedWindows.push(win);
+ win.focus();
+ return false;
+ }
+
+ function showRelatedObjectLookupPopup(triggeringLink) {
+ return showAdminPopup(triggeringLink, /^lookup_/, true);
+ }
+
+ function dismissRelatedLookupPopup(win, chosenId) {
+ const name = removePopupIndex(win.name);
+ const elem = document.getElementById(name);
+ if (elem.classList.contains('vManyToManyRawIdAdminField') && elem.value) {
+ elem.value += ',' + chosenId;
+ } else {
+ document.getElementById(name).value = chosenId;
+ }
+ const index = relatedWindows.indexOf(win);
+ if (index > -1) {
+ relatedWindows.splice(index, 1);
+ }
+ win.close();
+ }
+
+ function showRelatedObjectPopup(triggeringLink) {
+ return showAdminPopup(triggeringLink, /^(change|add|delete)_/, false);
+ }
+
+ function updateRelatedObjectLinks(triggeringLink) {
+ const $this = $(triggeringLink);
+ const siblings = $this.nextAll('.view-related, .change-related, .delete-related');
+ if (!siblings.length) {
+ return;
+ }
+ const value = $this.val();
+ if (value) {
+ siblings.each(function() {
+ const elm = $(this);
+ elm.attr('href', elm.attr('data-href-template').replace('__fk__', value));
+ });
+ } else {
+ siblings.removeAttr('href');
+ }
+ }
+
+ function updateRelatedSelectsOptions(currentSelect, win, objId, newRepr, newId) {
+ // After create/edit a model from the options next to the current
+ // select (+ or :pencil:) update ForeignKey PK of the rest of selects
+ // in the page.
+
+ const path = win.location.pathname;
+ // Extract the model from the popup url '.../
/add/' or
+ // '...///change/' depending the action (add or change).
+ const modelName = path.split('/')[path.split('/').length - (objId ? 4 : 3)];
+ // Exclude autocomplete selects.
+ const selectsRelated = document.querySelectorAll(`[data-model-ref="${modelName}"] select:not(.admin-autocomplete)`);
+
+ selectsRelated.forEach(function(select) {
+ if (currentSelect === select) {
+ return;
+ }
+
+ let option = select.querySelector(`option[value="${objId}"]`);
+
+ if (!option) {
+ option = new Option(newRepr, newId);
+ select.options.add(option);
+ return;
+ }
+
+ option.textContent = newRepr;
+ option.value = newId;
+ });
+ }
+
+ function dismissAddRelatedObjectPopup(win, newId, newRepr) {
+ const name = removePopupIndex(win.name);
+ const elem = document.getElementById(name);
+ if (elem) {
+ const elemName = elem.nodeName.toUpperCase();
+ if (elemName === 'SELECT') {
+ elem.options[elem.options.length] = new Option(newRepr, newId, true, true);
+ updateRelatedSelectsOptions(elem, win, null, newRepr, newId);
+ } else if (elemName === 'INPUT') {
+ if (elem.classList.contains('vManyToManyRawIdAdminField') && elem.value) {
+ elem.value += ',' + newId;
+ } else {
+ elem.value = newId;
+ }
+ }
+ // Trigger a change event to update related links if required.
+ $(elem).trigger('change');
+ } else {
+ const toId = name + "_to";
+ const o = new Option(newRepr, newId);
+ SelectBox.add_to_cache(toId, o);
+ SelectBox.redisplay(toId);
+ }
+ const index = relatedWindows.indexOf(win);
+ if (index > -1) {
+ relatedWindows.splice(index, 1);
+ }
+ win.close();
+ }
+
+ function dismissChangeRelatedObjectPopup(win, objId, newRepr, newId) {
+ const id = removePopupIndex(win.name.replace(/^edit_/, ''));
+ const selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]);
+ const selects = $(selectsSelector);
+ selects.find('option').each(function() {
+ if (this.value === objId) {
+ this.textContent = newRepr;
+ this.value = newId;
+ }
+ }).trigger('change');
+ updateRelatedSelectsOptions(selects[0], win, objId, newRepr, newId);
+ selects.next().find('.select2-selection__rendered').each(function() {
+ // The element can have a clear button as a child.
+ // Use the lastChild to modify only the displayed value.
+ this.lastChild.textContent = newRepr;
+ this.title = newRepr;
+ });
+ const index = relatedWindows.indexOf(win);
+ if (index > -1) {
+ relatedWindows.splice(index, 1);
+ }
+ win.close();
+ }
+
+ function dismissDeleteRelatedObjectPopup(win, objId) {
+ const id = removePopupIndex(win.name.replace(/^delete_/, ''));
+ const selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]);
+ const selects = $(selectsSelector);
+ selects.find('option').each(function() {
+ if (this.value === objId) {
+ $(this).remove();
+ }
+ }).trigger('change');
+ const index = relatedWindows.indexOf(win);
+ if (index > -1) {
+ relatedWindows.splice(index, 1);
+ }
+ win.close();
+ }
+
+ window.showRelatedObjectLookupPopup = showRelatedObjectLookupPopup;
+ window.dismissRelatedLookupPopup = dismissRelatedLookupPopup;
+ window.showRelatedObjectPopup = showRelatedObjectPopup;
+ window.updateRelatedObjectLinks = updateRelatedObjectLinks;
+ window.dismissAddRelatedObjectPopup = dismissAddRelatedObjectPopup;
+ window.dismissChangeRelatedObjectPopup = dismissChangeRelatedObjectPopup;
+ window.dismissDeleteRelatedObjectPopup = dismissDeleteRelatedObjectPopup;
+ window.dismissChildPopups = dismissChildPopups;
+
+ // Kept for backward compatibility
+ window.showAddAnotherPopup = showRelatedObjectPopup;
+ window.dismissAddAnotherPopup = dismissAddRelatedObjectPopup;
+
+ window.addEventListener('unload', function(evt) {
+ window.dismissChildPopups();
+ });
+
+ $(document).ready(function() {
+ setPopupIndex();
+ $("a[data-popup-opener]").on('click', function(event) {
+ event.preventDefault();
+ opener.dismissRelatedLookupPopup(window, $(this).data("popup-opener"));
+ });
+ $('body').on('click', '.related-widget-wrapper-link[data-popup="yes"]', function(e) {
+ e.preventDefault();
+ if (this.href) {
+ const event = $.Event('django:show-related', {href: this.href});
+ $(this).trigger(event);
+ if (!event.isDefaultPrevented()) {
+ showRelatedObjectPopup(this);
+ }
+ }
+ });
+ $('body').on('change', '.related-widget-wrapper select', function(e) {
+ const event = $.Event('django:update-related');
+ $(this).trigger(event);
+ if (!event.isDefaultPrevented()) {
+ updateRelatedObjectLinks(this);
+ }
+ });
+ $('.related-widget-wrapper select').trigger('change');
+ $('body').on('click', '.related-lookup', function(e) {
+ e.preventDefault();
+ const event = $.Event('django:lookup-related');
+ $(this).trigger(event);
+ if (!event.isDefaultPrevented()) {
+ showRelatedObjectLookupPopup(this);
+ }
+ });
+ });
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/js/autocomplete.js b/django_code/django_code/cloudmanager/templates/admin/js/autocomplete.js
new file mode 100644
index 0000000..d3daeab
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/js/autocomplete.js
@@ -0,0 +1,33 @@
+'use strict';
+{
+ const $ = django.jQuery;
+
+ $.fn.djangoAdminSelect2 = function() {
+ $.each(this, function(i, element) {
+ $(element).select2({
+ ajax: {
+ data: (params) => {
+ return {
+ term: params.term,
+ page: params.page,
+ app_label: element.dataset.appLabel,
+ model_name: element.dataset.modelName,
+ field_name: element.dataset.fieldName
+ };
+ }
+ }
+ });
+ });
+ return this;
+ };
+
+ $(function() {
+ // Initialize all autocomplete widgets except the one in the template
+ // form used when a new formset is added.
+ $('.admin-autocomplete').not('[name*=__prefix__]').djangoAdminSelect2();
+ });
+
+ document.addEventListener('formset:added', (event) => {
+ $(event.target).find('.admin-autocomplete').djangoAdminSelect2();
+ });
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/js/calendar.js b/django_code/django_code/cloudmanager/templates/admin/js/calendar.js
new file mode 100644
index 0000000..a62d10a
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/js/calendar.js
@@ -0,0 +1,221 @@
+/*global gettext, pgettext, get_format, quickElement, removeChildren*/
+/*
+calendar.js - Calendar functions by Adrian Holovaty
+depends on core.js for utility functions like removeChildren or quickElement
+*/
+'use strict';
+{
+ // CalendarNamespace -- Provides a collection of HTML calendar-related helper functions
+ const CalendarNamespace = {
+ monthsOfYear: [
+ gettext('January'),
+ gettext('February'),
+ gettext('March'),
+ gettext('April'),
+ gettext('May'),
+ gettext('June'),
+ gettext('July'),
+ gettext('August'),
+ gettext('September'),
+ gettext('October'),
+ gettext('November'),
+ gettext('December')
+ ],
+ monthsOfYearAbbrev: [
+ pgettext('abbrev. month January', 'Jan'),
+ pgettext('abbrev. month February', 'Feb'),
+ pgettext('abbrev. month March', 'Mar'),
+ pgettext('abbrev. month April', 'Apr'),
+ pgettext('abbrev. month May', 'May'),
+ pgettext('abbrev. month June', 'Jun'),
+ pgettext('abbrev. month July', 'Jul'),
+ pgettext('abbrev. month August', 'Aug'),
+ pgettext('abbrev. month September', 'Sep'),
+ pgettext('abbrev. month October', 'Oct'),
+ pgettext('abbrev. month November', 'Nov'),
+ pgettext('abbrev. month December', 'Dec')
+ ],
+ daysOfWeek: [
+ pgettext('one letter Sunday', 'S'),
+ pgettext('one letter Monday', 'M'),
+ pgettext('one letter Tuesday', 'T'),
+ pgettext('one letter Wednesday', 'W'),
+ pgettext('one letter Thursday', 'T'),
+ pgettext('one letter Friday', 'F'),
+ pgettext('one letter Saturday', 'S')
+ ],
+ firstDayOfWeek: parseInt(get_format('FIRST_DAY_OF_WEEK')),
+ isLeapYear: function(year) {
+ return (((year % 4) === 0) && ((year % 100) !== 0 ) || ((year % 400) === 0));
+ },
+ getDaysInMonth: function(month, year) {
+ let days;
+ if (month === 1 || month === 3 || month === 5 || month === 7 || month === 8 || month === 10 || month === 12) {
+ days = 31;
+ }
+ else if (month === 4 || month === 6 || month === 9 || month === 11) {
+ days = 30;
+ }
+ else if (month === 2 && CalendarNamespace.isLeapYear(year)) {
+ days = 29;
+ }
+ else {
+ days = 28;
+ }
+ return days;
+ },
+ draw: function(month, year, div_id, callback, selected) { // month = 1-12, year = 1-9999
+ const today = new Date();
+ const todayDay = today.getDate();
+ const todayMonth = today.getMonth() + 1;
+ const todayYear = today.getFullYear();
+ let todayClass = '';
+
+ // Use UTC functions here because the date field does not contain time
+ // and using the UTC function variants prevent the local time offset
+ // from altering the date, specifically the day field. For example:
+ //
+ // ```
+ // var x = new Date('2013-10-02');
+ // var day = x.getDate();
+ // ```
+ //
+ // The day variable above will be 1 instead of 2 in, say, US Pacific time
+ // zone.
+ let isSelectedMonth = false;
+ if (typeof selected !== 'undefined') {
+ isSelectedMonth = (selected.getUTCFullYear() === year && (selected.getUTCMonth() + 1) === month);
+ }
+
+ month = parseInt(month);
+ year = parseInt(year);
+ const calDiv = document.getElementById(div_id);
+ removeChildren(calDiv);
+ const calTable = document.createElement('table');
+ quickElement('caption', calTable, CalendarNamespace.monthsOfYear[month - 1] + ' ' + year);
+ const tableBody = quickElement('tbody', calTable);
+
+ // Draw days-of-week header
+ let tableRow = quickElement('tr', tableBody);
+ for (let i = 0; i < 7; i++) {
+ quickElement('th', tableRow, CalendarNamespace.daysOfWeek[(i + CalendarNamespace.firstDayOfWeek) % 7]);
+ }
+
+ const startingPos = new Date(year, month - 1, 1 - CalendarNamespace.firstDayOfWeek).getDay();
+ const days = CalendarNamespace.getDaysInMonth(month, year);
+
+ let nonDayCell;
+
+ // Draw blanks before first of month
+ tableRow = quickElement('tr', tableBody);
+ for (let i = 0; i < startingPos; i++) {
+ nonDayCell = quickElement('td', tableRow, ' ');
+ nonDayCell.className = "nonday";
+ }
+
+ function calendarMonth(y, m) {
+ function onClick(e) {
+ e.preventDefault();
+ callback(y, m, this.textContent);
+ }
+ return onClick;
+ }
+
+ // Draw days of month
+ let currentDay = 1;
+ for (let i = startingPos; currentDay <= days; i++) {
+ if (i % 7 === 0 && currentDay !== 1) {
+ tableRow = quickElement('tr', tableBody);
+ }
+ if ((currentDay === todayDay) && (month === todayMonth) && (year === todayYear)) {
+ todayClass = 'today';
+ } else {
+ todayClass = '';
+ }
+
+ // use UTC function; see above for explanation.
+ if (isSelectedMonth && currentDay === selected.getUTCDate()) {
+ if (todayClass !== '') {
+ todayClass += " ";
+ }
+ todayClass += "selected";
+ }
+
+ const cell = quickElement('td', tableRow, '', 'class', todayClass);
+ const link = quickElement('a', cell, currentDay, 'href', '#');
+ link.addEventListener('click', calendarMonth(year, month));
+ currentDay++;
+ }
+
+ // Draw blanks after end of month (optional, but makes for valid code)
+ while (tableRow.childNodes.length < 7) {
+ nonDayCell = quickElement('td', tableRow, ' ');
+ nonDayCell.className = "nonday";
+ }
+
+ calDiv.appendChild(calTable);
+ }
+ };
+
+ // Calendar -- A calendar instance
+ function Calendar(div_id, callback, selected) {
+ // div_id (string) is the ID of the element in which the calendar will
+ // be displayed
+ // callback (string) is the name of a JavaScript function that will be
+ // called with the parameters (year, month, day) when a day in the
+ // calendar is clicked
+ this.div_id = div_id;
+ this.callback = callback;
+ this.today = new Date();
+ this.currentMonth = this.today.getMonth() + 1;
+ this.currentYear = this.today.getFullYear();
+ if (typeof selected !== 'undefined') {
+ this.selected = selected;
+ }
+ }
+ Calendar.prototype = {
+ drawCurrent: function() {
+ CalendarNamespace.draw(this.currentMonth, this.currentYear, this.div_id, this.callback, this.selected);
+ },
+ drawDate: function(month, year, selected) {
+ this.currentMonth = month;
+ this.currentYear = year;
+
+ if(selected) {
+ this.selected = selected;
+ }
+
+ this.drawCurrent();
+ },
+ drawPreviousMonth: function() {
+ if (this.currentMonth === 1) {
+ this.currentMonth = 12;
+ this.currentYear--;
+ }
+ else {
+ this.currentMonth--;
+ }
+ this.drawCurrent();
+ },
+ drawNextMonth: function() {
+ if (this.currentMonth === 12) {
+ this.currentMonth = 1;
+ this.currentYear++;
+ }
+ else {
+ this.currentMonth++;
+ }
+ this.drawCurrent();
+ },
+ drawPreviousYear: function() {
+ this.currentYear--;
+ this.drawCurrent();
+ },
+ drawNextYear: function() {
+ this.currentYear++;
+ this.drawCurrent();
+ }
+ };
+ window.Calendar = Calendar;
+ window.CalendarNamespace = CalendarNamespace;
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/js/cancel.js b/django_code/django_code/cloudmanager/templates/admin/js/cancel.js
new file mode 100644
index 0000000..3069c6f
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/js/cancel.js
@@ -0,0 +1,29 @@
+'use strict';
+{
+ // Call function fn when the DOM is loaded and ready. If it is already
+ // loaded, call the function now.
+ // http://youmightnotneedjquery.com/#ready
+ function ready(fn) {
+ if (document.readyState !== 'loading') {
+ fn();
+ } else {
+ document.addEventListener('DOMContentLoaded', fn);
+ }
+ }
+
+ ready(function() {
+ function handleClick(event) {
+ event.preventDefault();
+ const params = new URLSearchParams(window.location.search);
+ if (params.has('_popup')) {
+ window.close(); // Close the popup.
+ } else {
+ window.history.back(); // Otherwise, go back.
+ }
+ }
+
+ document.querySelectorAll('.cancel-link').forEach(function(el) {
+ el.addEventListener('click', handleClick);
+ });
+ });
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/js/change_form.js b/django_code/django_code/cloudmanager/templates/admin/js/change_form.js
new file mode 100644
index 0000000..96a4c62
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/js/change_form.js
@@ -0,0 +1,16 @@
+'use strict';
+{
+ const inputTags = ['BUTTON', 'INPUT', 'SELECT', 'TEXTAREA'];
+ const modelName = document.getElementById('django-admin-form-add-constants').dataset.modelName;
+ if (modelName) {
+ const form = document.getElementById(modelName + '_form');
+ for (const element of form.elements) {
+ // HTMLElement.offsetParent returns null when the element is not
+ // rendered.
+ if (inputTags.includes(element.tagName) && !element.disabled && element.offsetParent) {
+ element.focus();
+ break;
+ }
+ }
+ }
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/js/collapse.js b/django_code/django_code/cloudmanager/templates/admin/js/collapse.js
new file mode 100644
index 0000000..c6c7b0f
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/js/collapse.js
@@ -0,0 +1,43 @@
+/*global gettext*/
+'use strict';
+{
+ window.addEventListener('load', function() {
+ // Add anchor tag for Show/Hide link
+ const fieldsets = document.querySelectorAll('fieldset.collapse');
+ for (const [i, elem] of fieldsets.entries()) {
+ // Don't hide if fields in this fieldset have errors
+ if (elem.querySelectorAll('div.errors, ul.errorlist').length === 0) {
+ elem.classList.add('collapsed');
+ const h2 = elem.querySelector('h2');
+ const link = document.createElement('a');
+ link.id = 'fieldsetcollapser' + i;
+ link.className = 'collapse-toggle';
+ link.href = '#';
+ link.textContent = gettext('Show');
+ h2.appendChild(document.createTextNode(' ('));
+ h2.appendChild(link);
+ h2.appendChild(document.createTextNode(')'));
+ }
+ }
+ // Add toggle to hide/show anchor tag
+ const toggleFunc = function(ev) {
+ if (ev.target.matches('.collapse-toggle')) {
+ ev.preventDefault();
+ ev.stopPropagation();
+ const fieldset = ev.target.closest('fieldset');
+ if (fieldset.classList.contains('collapsed')) {
+ // Show
+ ev.target.textContent = gettext('Hide');
+ fieldset.classList.remove('collapsed');
+ } else {
+ // Hide
+ ev.target.textContent = gettext('Show');
+ fieldset.classList.add('collapsed');
+ }
+ }
+ };
+ document.querySelectorAll('fieldset.module').forEach(function(el) {
+ el.addEventListener('click', toggleFunc);
+ });
+ });
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/js/core.js b/django_code/django_code/cloudmanager/templates/admin/js/core.js
new file mode 100644
index 0000000..0344a13
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/js/core.js
@@ -0,0 +1,170 @@
+// Core JavaScript helper functions
+'use strict';
+
+// quickElement(tagType, parentReference [, textInChildNode, attribute, attributeValue ...]);
+function quickElement() {
+ const obj = document.createElement(arguments[0]);
+ if (arguments[2]) {
+ const textNode = document.createTextNode(arguments[2]);
+ obj.appendChild(textNode);
+ }
+ const len = arguments.length;
+ for (let i = 3; i < len; i += 2) {
+ obj.setAttribute(arguments[i], arguments[i + 1]);
+ }
+ arguments[1].appendChild(obj);
+ return obj;
+}
+
+// "a" is reference to an object
+function removeChildren(a) {
+ while (a.hasChildNodes()) {
+ a.removeChild(a.lastChild);
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Find-position functions by PPK
+// See https://www.quirksmode.org/js/findpos.html
+// ----------------------------------------------------------------------------
+function findPosX(obj) {
+ let curleft = 0;
+ if (obj.offsetParent) {
+ while (obj.offsetParent) {
+ curleft += obj.offsetLeft - obj.scrollLeft;
+ obj = obj.offsetParent;
+ }
+ } else if (obj.x) {
+ curleft += obj.x;
+ }
+ return curleft;
+}
+
+function findPosY(obj) {
+ let curtop = 0;
+ if (obj.offsetParent) {
+ while (obj.offsetParent) {
+ curtop += obj.offsetTop - obj.scrollTop;
+ obj = obj.offsetParent;
+ }
+ } else if (obj.y) {
+ curtop += obj.y;
+ }
+ return curtop;
+}
+
+//-----------------------------------------------------------------------------
+// Date object extensions
+// ----------------------------------------------------------------------------
+{
+ Date.prototype.getTwelveHours = function() {
+ return this.getHours() % 12 || 12;
+ };
+
+ Date.prototype.getTwoDigitMonth = function() {
+ return (this.getMonth() < 9) ? '0' + (this.getMonth() + 1) : (this.getMonth() + 1);
+ };
+
+ Date.prototype.getTwoDigitDate = function() {
+ return (this.getDate() < 10) ? '0' + this.getDate() : this.getDate();
+ };
+
+ Date.prototype.getTwoDigitTwelveHour = function() {
+ return (this.getTwelveHours() < 10) ? '0' + this.getTwelveHours() : this.getTwelveHours();
+ };
+
+ Date.prototype.getTwoDigitHour = function() {
+ return (this.getHours() < 10) ? '0' + this.getHours() : this.getHours();
+ };
+
+ Date.prototype.getTwoDigitMinute = function() {
+ return (this.getMinutes() < 10) ? '0' + this.getMinutes() : this.getMinutes();
+ };
+
+ Date.prototype.getTwoDigitSecond = function() {
+ return (this.getSeconds() < 10) ? '0' + this.getSeconds() : this.getSeconds();
+ };
+
+ Date.prototype.getAbbrevMonthName = function() {
+ return typeof window.CalendarNamespace === "undefined"
+ ? this.getTwoDigitMonth()
+ : window.CalendarNamespace.monthsOfYearAbbrev[this.getMonth()];
+ };
+
+ Date.prototype.getFullMonthName = function() {
+ return typeof window.CalendarNamespace === "undefined"
+ ? this.getTwoDigitMonth()
+ : window.CalendarNamespace.monthsOfYear[this.getMonth()];
+ };
+
+ Date.prototype.strftime = function(format) {
+ const fields = {
+ b: this.getAbbrevMonthName(),
+ B: this.getFullMonthName(),
+ c: this.toString(),
+ d: this.getTwoDigitDate(),
+ H: this.getTwoDigitHour(),
+ I: this.getTwoDigitTwelveHour(),
+ m: this.getTwoDigitMonth(),
+ M: this.getTwoDigitMinute(),
+ p: (this.getHours() >= 12) ? 'PM' : 'AM',
+ S: this.getTwoDigitSecond(),
+ w: '0' + this.getDay(),
+ x: this.toLocaleDateString(),
+ X: this.toLocaleTimeString(),
+ y: ('' + this.getFullYear()).substr(2, 4),
+ Y: '' + this.getFullYear(),
+ '%': '%'
+ };
+ let result = '', i = 0;
+ while (i < format.length) {
+ if (format.charAt(i) === '%') {
+ result += fields[format.charAt(i + 1)];
+ ++i;
+ }
+ else {
+ result += format.charAt(i);
+ }
+ ++i;
+ }
+ return result;
+ };
+
+ // ----------------------------------------------------------------------------
+ // String object extensions
+ // ----------------------------------------------------------------------------
+ String.prototype.strptime = function(format) {
+ const split_format = format.split(/[.\-/]/);
+ const date = this.split(/[.\-/]/);
+ let i = 0;
+ let day, month, year;
+ while (i < split_format.length) {
+ switch (split_format[i]) {
+ case "%d":
+ day = date[i];
+ break;
+ case "%m":
+ month = date[i] - 1;
+ break;
+ case "%Y":
+ year = date[i];
+ break;
+ case "%y":
+ // A %y value in the range of [00, 68] is in the current
+ // century, while [69, 99] is in the previous century,
+ // according to the Open Group Specification.
+ if (parseInt(date[i], 10) >= 69) {
+ year = date[i];
+ } else {
+ year = (new Date(Date.UTC(date[i], 0))).getUTCFullYear() + 100;
+ }
+ break;
+ }
+ ++i;
+ }
+ // Create Date object from UTC since the parsed value is supposed to be
+ // in UTC, not local time. Also, the calendar uses UTC functions for
+ // date extraction.
+ return new Date(Date.UTC(year, month, day));
+ };
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/js/filters.js b/django_code/django_code/cloudmanager/templates/admin/js/filters.js
new file mode 100644
index 0000000..f5536eb
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/js/filters.js
@@ -0,0 +1,30 @@
+/**
+ * Persist changelist filters state (collapsed/expanded).
+ */
+'use strict';
+{
+ // Init filters.
+ let filters = JSON.parse(sessionStorage.getItem('django.admin.filtersState'));
+
+ if (!filters) {
+ filters = {};
+ }
+
+ Object.entries(filters).forEach(([key, value]) => {
+ const detailElement = document.querySelector(`[data-filter-title='${CSS.escape(key)}']`);
+
+ // Check if the filter is present, it could be from other view.
+ if (detailElement) {
+ value ? detailElement.setAttribute('open', '') : detailElement.removeAttribute('open');
+ }
+ });
+
+ // Save filter state when clicks.
+ const details = document.querySelectorAll('details');
+ details.forEach(detail => {
+ detail.addEventListener('toggle', event => {
+ filters[`${event.target.dataset.filterTitle}`] = detail.open;
+ sessionStorage.setItem('django.admin.filtersState', JSON.stringify(filters));
+ });
+ });
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/js/inlines.js b/django_code/django_code/cloudmanager/templates/admin/js/inlines.js
new file mode 100644
index 0000000..e9a1dfe
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/js/inlines.js
@@ -0,0 +1,359 @@
+/*global DateTimeShortcuts, SelectFilter*/
+/**
+ * Django admin inlines
+ *
+ * Based on jQuery Formset 1.1
+ * @author Stanislaus Madueke (stan DOT madueke AT gmail DOT com)
+ * @requires jQuery 1.2.6 or later
+ *
+ * Copyright (c) 2009, Stanislaus Madueke
+ * All rights reserved.
+ *
+ * Spiced up with Code from Zain Memon's GSoC project 2009
+ * and modified for Django by Jannis Leidel, Travis Swicegood and Julien Phalip.
+ *
+ * Licensed under the New BSD License
+ * See: https://opensource.org/licenses/bsd-license.php
+ */
+'use strict';
+{
+ const $ = django.jQuery;
+ $.fn.formset = function(opts) {
+ const options = $.extend({}, $.fn.formset.defaults, opts);
+ const $this = $(this);
+ const $parent = $this.parent();
+ const updateElementIndex = function(el, prefix, ndx) {
+ const id_regex = new RegExp("(" + prefix + "-(\\d+|__prefix__))");
+ const replacement = prefix + "-" + ndx;
+ if ($(el).prop("for")) {
+ $(el).prop("for", $(el).prop("for").replace(id_regex, replacement));
+ }
+ if (el.id) {
+ el.id = el.id.replace(id_regex, replacement);
+ }
+ if (el.name) {
+ el.name = el.name.replace(id_regex, replacement);
+ }
+ };
+ const totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS").prop("autocomplete", "off");
+ let nextIndex = parseInt(totalForms.val(), 10);
+ const maxForms = $("#id_" + options.prefix + "-MAX_NUM_FORMS").prop("autocomplete", "off");
+ const minForms = $("#id_" + options.prefix + "-MIN_NUM_FORMS").prop("autocomplete", "off");
+ let addButton;
+
+ /**
+ * The "Add another MyModel" button below the inline forms.
+ */
+ const addInlineAddButton = function() {
+ if (addButton === null) {
+ if ($this.prop("tagName") === "TR") {
+ // If forms are laid out as table rows, insert the
+ // "add" button in a new table row:
+ const numCols = $this.eq(-1).children().length;
+ $parent.append('| ' + options.addText + " |
");
+ addButton = $parent.find("tr:last a");
+ } else {
+ // Otherwise, insert it immediately after the last form:
+ $this.filter(":last").after('");
+ addButton = $this.filter(":last").next().find("a");
+ }
+ }
+ addButton.on('click', addInlineClickHandler);
+ };
+
+ const addInlineClickHandler = function(e) {
+ e.preventDefault();
+ const template = $("#" + options.prefix + "-empty");
+ const row = template.clone(true);
+ row.removeClass(options.emptyCssClass)
+ .addClass(options.formCssClass)
+ .attr("id", options.prefix + "-" + nextIndex);
+ addInlineDeleteButton(row);
+ row.find("*").each(function() {
+ updateElementIndex(this, options.prefix, totalForms.val());
+ });
+ // Insert the new form when it has been fully edited.
+ row.insertBefore($(template));
+ // Update number of total forms.
+ $(totalForms).val(parseInt(totalForms.val(), 10) + 1);
+ nextIndex += 1;
+ // Hide the add button if there's a limit and it's been reached.
+ if ((maxForms.val() !== '') && (maxForms.val() - totalForms.val()) <= 0) {
+ addButton.parent().hide();
+ }
+ // Show the remove buttons if there are more than min_num.
+ toggleDeleteButtonVisibility(row.closest('.inline-group'));
+
+ // Pass the new form to the post-add callback, if provided.
+ if (options.added) {
+ options.added(row);
+ }
+ row.get(0).dispatchEvent(new CustomEvent("formset:added", {
+ bubbles: true,
+ detail: {
+ formsetName: options.prefix
+ }
+ }));
+ };
+
+ /**
+ * The "X" button that is part of every unsaved inline.
+ * (When saved, it is replaced with a "Delete" checkbox.)
+ */
+ const addInlineDeleteButton = function(row) {
+ if (row.is("tr")) {
+ // If the forms are laid out in table rows, insert
+ // the remove button into the last table cell:
+ row.children(":last").append('");
+ } else if (row.is("ul") || row.is("ol")) {
+ // If they're laid out as an ordered/unordered list,
+ // insert an - after the last list item:
+ row.append('
- ' + options.deleteText + "
");
+ } else {
+ // Otherwise, just insert the remove button as the
+ // last child element of the form's container:
+ row.children(":first").append('' + options.deleteText + "");
+ }
+ // Add delete handler for each row.
+ row.find("a." + options.deleteCssClass).on('click', inlineDeleteHandler.bind(this));
+ };
+
+ const inlineDeleteHandler = function(e1) {
+ e1.preventDefault();
+ const deleteButton = $(e1.target);
+ const row = deleteButton.closest('.' + options.formCssClass);
+ const inlineGroup = row.closest('.inline-group');
+ // Remove the parent form containing this button,
+ // and also remove the relevant row with non-field errors:
+ const prevRow = row.prev();
+ if (prevRow.length && prevRow.hasClass('row-form-errors')) {
+ prevRow.remove();
+ }
+ row.remove();
+ nextIndex -= 1;
+ // Pass the deleted form to the post-delete callback, if provided.
+ if (options.removed) {
+ options.removed(row);
+ }
+ document.dispatchEvent(new CustomEvent("formset:removed", {
+ detail: {
+ formsetName: options.prefix
+ }
+ }));
+ // Update the TOTAL_FORMS form count.
+ const forms = $("." + options.formCssClass);
+ $("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length);
+ // Show add button again once below maximum number.
+ if ((maxForms.val() === '') || (maxForms.val() - forms.length) > 0) {
+ addButton.parent().show();
+ }
+ // Hide the remove buttons if at min_num.
+ toggleDeleteButtonVisibility(inlineGroup);
+ // Also, update names and ids for all remaining form controls so
+ // they remain in sequence:
+ let i, formCount;
+ const updateElementCallback = function() {
+ updateElementIndex(this, options.prefix, i);
+ };
+ for (i = 0, formCount = forms.length; i < formCount; i++) {
+ updateElementIndex($(forms).get(i), options.prefix, i);
+ $(forms.get(i)).find("*").each(updateElementCallback);
+ }
+ };
+
+ const toggleDeleteButtonVisibility = function(inlineGroup) {
+ if ((minForms.val() !== '') && (minForms.val() - totalForms.val()) >= 0) {
+ inlineGroup.find('.inline-deletelink').hide();
+ } else {
+ inlineGroup.find('.inline-deletelink').show();
+ }
+ };
+
+ $this.each(function(i) {
+ $(this).not("." + options.emptyCssClass).addClass(options.formCssClass);
+ });
+
+ // Create the delete buttons for all unsaved inlines:
+ $this.filter('.' + options.formCssClass + ':not(.has_original):not(.' + options.emptyCssClass + ')').each(function() {
+ addInlineDeleteButton($(this));
+ });
+ toggleDeleteButtonVisibility($this);
+
+ // Create the add button, initially hidden.
+ addButton = options.addButton;
+ addInlineAddButton();
+
+ // Show the add button if allowed to add more items.
+ // Note that max_num = None translates to a blank string.
+ const showAddButton = maxForms.val() === '' || (maxForms.val() - totalForms.val()) > 0;
+ if ($this.length && showAddButton) {
+ addButton.parent().show();
+ } else {
+ addButton.parent().hide();
+ }
+
+ return this;
+ };
+
+ /* Setup plugin defaults */
+ $.fn.formset.defaults = {
+ prefix: "form", // The form prefix for your django formset
+ addText: "add another", // Text for the add link
+ deleteText: "remove", // Text for the delete link
+ addCssClass: "add-row", // CSS class applied to the add link
+ deleteCssClass: "delete-row", // CSS class applied to the delete link
+ emptyCssClass: "empty-row", // CSS class applied to the empty row
+ formCssClass: "dynamic-form", // CSS class applied to each form in a formset
+ added: null, // Function called each time a new form is added
+ removed: null, // Function called each time a form is deleted
+ addButton: null // Existing add button to use
+ };
+
+
+ // Tabular inlines ---------------------------------------------------------
+ $.fn.tabularFormset = function(selector, options) {
+ const $rows = $(this);
+
+ const reinitDateTimeShortCuts = function() {
+ // Reinitialize the calendar and clock widgets by force
+ if (typeof DateTimeShortcuts !== "undefined") {
+ $(".datetimeshortcuts").remove();
+ DateTimeShortcuts.init();
+ }
+ };
+
+ const updateSelectFilter = function() {
+ // If any SelectFilter widgets are a part of the new form,
+ // instantiate a new SelectFilter instance for it.
+ if (typeof SelectFilter !== 'undefined') {
+ $('.selectfilter').each(function(index, value) {
+ SelectFilter.init(value.id, this.dataset.fieldName, false);
+ });
+ $('.selectfilterstacked').each(function(index, value) {
+ SelectFilter.init(value.id, this.dataset.fieldName, true);
+ });
+ }
+ };
+
+ const initPrepopulatedFields = function(row) {
+ row.find('.prepopulated_field').each(function() {
+ const field = $(this),
+ input = field.find('input, select, textarea'),
+ dependency_list = input.data('dependency_list') || [],
+ dependencies = [];
+ $.each(dependency_list, function(i, field_name) {
+ dependencies.push('#' + row.find('.field-' + field_name).find('input, select, textarea').attr('id'));
+ });
+ if (dependencies.length) {
+ input.prepopulate(dependencies, input.attr('maxlength'));
+ }
+ });
+ };
+
+ $rows.formset({
+ prefix: options.prefix,
+ addText: options.addText,
+ formCssClass: "dynamic-" + options.prefix,
+ deleteCssClass: "inline-deletelink",
+ deleteText: options.deleteText,
+ emptyCssClass: "empty-form",
+ added: function(row) {
+ initPrepopulatedFields(row);
+ reinitDateTimeShortCuts();
+ updateSelectFilter();
+ },
+ addButton: options.addButton
+ });
+
+ return $rows;
+ };
+
+ // Stacked inlines ---------------------------------------------------------
+ $.fn.stackedFormset = function(selector, options) {
+ const $rows = $(this);
+ const updateInlineLabel = function(row) {
+ $(selector).find(".inline_label").each(function(i) {
+ const count = i + 1;
+ $(this).html($(this).html().replace(/(#\d+)/g, "#" + count));
+ });
+ };
+
+ const reinitDateTimeShortCuts = function() {
+ // Reinitialize the calendar and clock widgets by force, yuck.
+ if (typeof DateTimeShortcuts !== "undefined") {
+ $(".datetimeshortcuts").remove();
+ DateTimeShortcuts.init();
+ }
+ };
+
+ const updateSelectFilter = function() {
+ // If any SelectFilter widgets were added, instantiate a new instance.
+ if (typeof SelectFilter !== "undefined") {
+ $(".selectfilter").each(function(index, value) {
+ SelectFilter.init(value.id, this.dataset.fieldName, false);
+ });
+ $(".selectfilterstacked").each(function(index, value) {
+ SelectFilter.init(value.id, this.dataset.fieldName, true);
+ });
+ }
+ };
+
+ const initPrepopulatedFields = function(row) {
+ row.find('.prepopulated_field').each(function() {
+ const field = $(this),
+ input = field.find('input, select, textarea'),
+ dependency_list = input.data('dependency_list') || [],
+ dependencies = [];
+ $.each(dependency_list, function(i, field_name) {
+ // Dependency in a fieldset.
+ let field_element = row.find('.form-row .field-' + field_name);
+ // Dependency without a fieldset.
+ if (!field_element.length) {
+ field_element = row.find('.form-row.field-' + field_name);
+ }
+ dependencies.push('#' + field_element.find('input, select, textarea').attr('id'));
+ });
+ if (dependencies.length) {
+ input.prepopulate(dependencies, input.attr('maxlength'));
+ }
+ });
+ };
+
+ $rows.formset({
+ prefix: options.prefix,
+ addText: options.addText,
+ formCssClass: "dynamic-" + options.prefix,
+ deleteCssClass: "inline-deletelink",
+ deleteText: options.deleteText,
+ emptyCssClass: "empty-form",
+ removed: updateInlineLabel,
+ added: function(row) {
+ initPrepopulatedFields(row);
+ reinitDateTimeShortCuts();
+ updateSelectFilter();
+ updateInlineLabel(row);
+ },
+ addButton: options.addButton
+ });
+
+ return $rows;
+ };
+
+ $(document).ready(function() {
+ $(".js-inline-admin-formset").each(function() {
+ const data = $(this).data(),
+ inlineOptions = data.inlineFormset;
+ let selector;
+ switch(data.inlineType) {
+ case "stacked":
+ selector = inlineOptions.name + "-group .inline-related";
+ $(selector).stackedFormset(selector, inlineOptions.options);
+ break;
+ case "tabular":
+ selector = inlineOptions.name + "-group .tabular.inline-related tbody:first > tr.form-row";
+ $(selector).tabularFormset(selector, inlineOptions.options);
+ break;
+ }
+ });
+ });
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/js/jquery.init.js b/django_code/django_code/cloudmanager/templates/admin/js/jquery.init.js
new file mode 100644
index 0000000..f40b27f
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/js/jquery.init.js
@@ -0,0 +1,8 @@
+/*global jQuery:false*/
+'use strict';
+/* Puts the included jQuery into our own namespace using noConflict and passing
+ * it 'true'. This ensures that the included jQuery doesn't pollute the global
+ * namespace (i.e. this preserves pre-existing values for both window.$ and
+ * window.jQuery).
+ */
+window.django = {jQuery: jQuery.noConflict(true)};
diff --git a/django_code/django_code/cloudmanager/templates/admin/js/nav_sidebar.js b/django_code/django_code/cloudmanager/templates/admin/js/nav_sidebar.js
new file mode 100644
index 0000000..7e735db
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/js/nav_sidebar.js
@@ -0,0 +1,79 @@
+'use strict';
+{
+ const toggleNavSidebar = document.getElementById('toggle-nav-sidebar');
+ if (toggleNavSidebar !== null) {
+ const navSidebar = document.getElementById('nav-sidebar');
+ const main = document.getElementById('main');
+ let navSidebarIsOpen = localStorage.getItem('django.admin.navSidebarIsOpen');
+ if (navSidebarIsOpen === null) {
+ navSidebarIsOpen = 'true';
+ }
+ main.classList.toggle('shifted', navSidebarIsOpen === 'true');
+ navSidebar.setAttribute('aria-expanded', navSidebarIsOpen);
+
+ toggleNavSidebar.addEventListener('click', function() {
+ if (navSidebarIsOpen === 'true') {
+ navSidebarIsOpen = 'false';
+ } else {
+ navSidebarIsOpen = 'true';
+ }
+ localStorage.setItem('django.admin.navSidebarIsOpen', navSidebarIsOpen);
+ main.classList.toggle('shifted');
+ navSidebar.setAttribute('aria-expanded', navSidebarIsOpen);
+ });
+ }
+
+ function initSidebarQuickFilter() {
+ const options = [];
+ const navSidebar = document.getElementById('nav-sidebar');
+ if (!navSidebar) {
+ return;
+ }
+ navSidebar.querySelectorAll('th[scope=row] a').forEach((container) => {
+ options.push({title: container.innerHTML, node: container});
+ });
+
+ function checkValue(event) {
+ let filterValue = event.target.value;
+ if (filterValue) {
+ filterValue = filterValue.toLowerCase();
+ }
+ if (event.key === 'Escape') {
+ filterValue = '';
+ event.target.value = ''; // clear input
+ }
+ let matches = false;
+ for (const o of options) {
+ let displayValue = '';
+ if (filterValue) {
+ if (o.title.toLowerCase().indexOf(filterValue) === -1) {
+ displayValue = 'none';
+ } else {
+ matches = true;
+ }
+ }
+ // show/hide parent
+ o.node.parentNode.parentNode.style.display = displayValue;
+ }
+ if (!filterValue || matches) {
+ event.target.classList.remove('no-results');
+ } else {
+ event.target.classList.add('no-results');
+ }
+ sessionStorage.setItem('django.admin.navSidebarFilterValue', filterValue);
+ }
+
+ const nav = document.getElementById('nav-filter');
+ nav.addEventListener('change', checkValue, false);
+ nav.addEventListener('input', checkValue, false);
+ nav.addEventListener('keyup', checkValue, false);
+
+ const storedValue = sessionStorage.getItem('django.admin.navSidebarFilterValue');
+ if (storedValue) {
+ nav.value = storedValue;
+ checkValue({target: nav, key: ''});
+ }
+ }
+ window.initSidebarQuickFilter = initSidebarQuickFilter;
+ initSidebarQuickFilter();
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/js/popup_response.js b/django_code/django_code/cloudmanager/templates/admin/js/popup_response.js
new file mode 100644
index 0000000..2b1d3dd
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/js/popup_response.js
@@ -0,0 +1,16 @@
+/*global opener */
+'use strict';
+{
+ const initData = JSON.parse(document.getElementById('django-admin-popup-response-constants').dataset.popupResponse);
+ switch(initData.action) {
+ case 'change':
+ opener.dismissChangeRelatedObjectPopup(window, initData.value, initData.obj, initData.new_value);
+ break;
+ case 'delete':
+ opener.dismissDeleteRelatedObjectPopup(window, initData.value);
+ break;
+ default:
+ opener.dismissAddRelatedObjectPopup(window, initData.value, initData.obj);
+ break;
+ }
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/js/prepopulate.js b/django_code/django_code/cloudmanager/templates/admin/js/prepopulate.js
new file mode 100644
index 0000000..89e95ab
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/js/prepopulate.js
@@ -0,0 +1,43 @@
+/*global URLify*/
+'use strict';
+{
+ const $ = django.jQuery;
+ $.fn.prepopulate = function(dependencies, maxLength, allowUnicode) {
+ /*
+ Depends on urlify.js
+ Populates a selected field with the values of the dependent fields,
+ URLifies and shortens the string.
+ dependencies - array of dependent fields ids
+ maxLength - maximum length of the URLify'd string
+ allowUnicode - Unicode support of the URLify'd string
+ */
+ return this.each(function() {
+ const prepopulatedField = $(this);
+
+ const populate = function() {
+ // Bail if the field's value has been changed by the user
+ if (prepopulatedField.data('_changed')) {
+ return;
+ }
+
+ const values = [];
+ $.each(dependencies, function(i, field) {
+ field = $(field);
+ if (field.val().length > 0) {
+ values.push(field.val());
+ }
+ });
+ prepopulatedField.val(URLify(values.join(' '), maxLength, allowUnicode));
+ };
+
+ prepopulatedField.data('_changed', false);
+ prepopulatedField.on('change', function() {
+ prepopulatedField.data('_changed', true);
+ });
+
+ if (!prepopulatedField.val()) {
+ $(dependencies.join(',')).on('keyup change focus', populate);
+ }
+ });
+ };
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/js/prepopulate_init.js b/django_code/django_code/cloudmanager/templates/admin/js/prepopulate_init.js
new file mode 100644
index 0000000..a58841f
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/js/prepopulate_init.js
@@ -0,0 +1,15 @@
+'use strict';
+{
+ const $ = django.jQuery;
+ const fields = $('#django-admin-prepopulated-fields-constants').data('prepopulatedFields');
+ $.each(fields, function(index, field) {
+ $(
+ '.empty-form .form-row .field-' + field.name +
+ ', .empty-form.form-row .field-' + field.name +
+ ', .empty-form .form-row.field-' + field.name
+ ).addClass('prepopulated_field');
+ $(field.id).data('dependency_list', field.dependency_list).prepopulate(
+ field.dependency_ids, field.maxLength, field.allowUnicode
+ );
+ });
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/js/theme.js b/django_code/django_code/cloudmanager/templates/admin/js/theme.js
new file mode 100644
index 0000000..794cd15
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/js/theme.js
@@ -0,0 +1,56 @@
+'use strict';
+{
+ window.addEventListener('load', function(e) {
+
+ function setTheme(mode) {
+ if (mode !== "light" && mode !== "dark" && mode !== "auto") {
+ console.error(`Got invalid theme mode: ${mode}. Resetting to auto.`);
+ mode = "auto";
+ }
+ document.documentElement.dataset.theme = mode;
+ localStorage.setItem("theme", mode);
+ }
+
+ function cycleTheme() {
+ const currentTheme = localStorage.getItem("theme") || "auto";
+ const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
+
+ if (prefersDark) {
+ // Auto (dark) -> Light -> Dark
+ if (currentTheme === "auto") {
+ setTheme("light");
+ } else if (currentTheme === "light") {
+ setTheme("dark");
+ } else {
+ setTheme("auto");
+ }
+ } else {
+ // Auto (light) -> Dark -> Light
+ if (currentTheme === "auto") {
+ setTheme("dark");
+ } else if (currentTheme === "dark") {
+ setTheme("light");
+ } else {
+ setTheme("auto");
+ }
+ }
+ }
+
+ function initTheme() {
+ // set theme defined in localStorage if there is one, or fallback to auto mode
+ const currentTheme = localStorage.getItem("theme");
+ currentTheme ? setTheme(currentTheme) : setTheme("auto");
+ }
+
+ function setupTheme() {
+ // Attach event handlers for toggling themes
+ const buttons = document.getElementsByClassName("theme-toggle");
+ Array.from(buttons).forEach((btn) => {
+ btn.addEventListener("click", cycleTheme);
+ });
+ initTheme();
+ }
+
+ setupTheme();
+ });
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/js/urlify.js b/django_code/django_code/cloudmanager/templates/admin/js/urlify.js
new file mode 100644
index 0000000..9fc0409
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/js/urlify.js
@@ -0,0 +1,169 @@
+/*global XRegExp*/
+'use strict';
+{
+ const LATIN_MAP = {
+ 'À': 'A', 'Á': 'A', 'Â': 'A', 'Ã': 'A', 'Ä': 'A', 'Å': 'A', 'Æ': 'AE',
+ 'Ç': 'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E', 'Ì': 'I', 'Í': 'I',
+ 'Î': 'I', 'Ï': 'I', 'Ð': 'D', 'Ñ': 'N', 'Ò': 'O', 'Ó': 'O', 'Ô': 'O',
+ 'Õ': 'O', 'Ö': 'O', 'Ő': 'O', 'Ø': 'O', 'Ù': 'U', 'Ú': 'U', 'Û': 'U',
+ 'Ü': 'U', 'Ű': 'U', 'Ý': 'Y', 'Þ': 'TH', 'Ÿ': 'Y', 'ß': 'ss', 'à': 'a',
+ 'á': 'a', 'â': 'a', 'ã': 'a', 'ä': 'a', 'å': 'a', 'æ': 'ae', 'ç': 'c',
+ 'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e', 'ì': 'i', 'í': 'i', 'î': 'i',
+ 'ï': 'i', 'ð': 'd', 'ñ': 'n', 'ò': 'o', 'ó': 'o', 'ô': 'o', 'õ': 'o',
+ 'ö': 'o', 'ő': 'o', 'ø': 'o', 'ù': 'u', 'ú': 'u', 'û': 'u', 'ü': 'u',
+ 'ű': 'u', 'ý': 'y', 'þ': 'th', 'ÿ': 'y'
+ };
+ const LATIN_SYMBOLS_MAP = {
+ '©': '(c)'
+ };
+ const GREEK_MAP = {
+ 'α': 'a', 'β': 'b', 'γ': 'g', 'δ': 'd', 'ε': 'e', 'ζ': 'z', 'η': 'h',
+ 'θ': '8', 'ι': 'i', 'κ': 'k', 'λ': 'l', 'μ': 'm', 'ν': 'n', 'ξ': '3',
+ 'ο': 'o', 'π': 'p', 'ρ': 'r', 'σ': 's', 'τ': 't', 'υ': 'y', 'φ': 'f',
+ 'χ': 'x', 'ψ': 'ps', 'ω': 'w', 'ά': 'a', 'έ': 'e', 'ί': 'i', 'ό': 'o',
+ 'ύ': 'y', 'ή': 'h', 'ώ': 'w', 'ς': 's', 'ϊ': 'i', 'ΰ': 'y', 'ϋ': 'y',
+ 'ΐ': 'i', 'Α': 'A', 'Β': 'B', 'Γ': 'G', 'Δ': 'D', 'Ε': 'E', 'Ζ': 'Z',
+ 'Η': 'H', 'Θ': '8', 'Ι': 'I', 'Κ': 'K', 'Λ': 'L', 'Μ': 'M', 'Ν': 'N',
+ 'Ξ': '3', 'Ο': 'O', 'Π': 'P', 'Ρ': 'R', 'Σ': 'S', 'Τ': 'T', 'Υ': 'Y',
+ 'Φ': 'F', 'Χ': 'X', 'Ψ': 'PS', 'Ω': 'W', 'Ά': 'A', 'Έ': 'E', 'Ί': 'I',
+ 'Ό': 'O', 'Ύ': 'Y', 'Ή': 'H', 'Ώ': 'W', 'Ϊ': 'I', 'Ϋ': 'Y'
+ };
+ const TURKISH_MAP = {
+ 'ş': 's', 'Ş': 'S', 'ı': 'i', 'İ': 'I', 'ç': 'c', 'Ç': 'C', 'ü': 'u',
+ 'Ü': 'U', 'ö': 'o', 'Ö': 'O', 'ğ': 'g', 'Ğ': 'G'
+ };
+ const ROMANIAN_MAP = {
+ 'ă': 'a', 'î': 'i', 'ș': 's', 'ț': 't', 'â': 'a',
+ 'Ă': 'A', 'Î': 'I', 'Ș': 'S', 'Ț': 'T', 'Â': 'A'
+ };
+ const RUSSIAN_MAP = {
+ 'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd', 'е': 'e', 'ё': 'yo',
+ 'ж': 'zh', 'з': 'z', 'и': 'i', 'й': 'j', 'к': 'k', 'л': 'l', 'м': 'm',
+ 'н': 'n', 'о': 'o', 'п': 'p', 'р': 'r', 'с': 's', 'т': 't', 'у': 'u',
+ 'ф': 'f', 'х': 'h', 'ц': 'c', 'ч': 'ch', 'ш': 'sh', 'щ': 'sh', 'ъ': '',
+ 'ы': 'y', 'ь': '', 'э': 'e', 'ю': 'yu', 'я': 'ya',
+ 'А': 'A', 'Б': 'B', 'В': 'V', 'Г': 'G', 'Д': 'D', 'Е': 'E', 'Ё': 'Yo',
+ 'Ж': 'Zh', 'З': 'Z', 'И': 'I', 'Й': 'J', 'К': 'K', 'Л': 'L', 'М': 'M',
+ 'Н': 'N', 'О': 'O', 'П': 'P', 'Р': 'R', 'С': 'S', 'Т': 'T', 'У': 'U',
+ 'Ф': 'F', 'Х': 'H', 'Ц': 'C', 'Ч': 'Ch', 'Ш': 'Sh', 'Щ': 'Sh', 'Ъ': '',
+ 'Ы': 'Y', 'Ь': '', 'Э': 'E', 'Ю': 'Yu', 'Я': 'Ya'
+ };
+ const UKRAINIAN_MAP = {
+ 'Є': 'Ye', 'І': 'I', 'Ї': 'Yi', 'Ґ': 'G', 'є': 'ye', 'і': 'i',
+ 'ї': 'yi', 'ґ': 'g'
+ };
+ const CZECH_MAP = {
+ 'č': 'c', 'ď': 'd', 'ě': 'e', 'ň': 'n', 'ř': 'r', 'š': 's', 'ť': 't',
+ 'ů': 'u', 'ž': 'z', 'Č': 'C', 'Ď': 'D', 'Ě': 'E', 'Ň': 'N', 'Ř': 'R',
+ 'Š': 'S', 'Ť': 'T', 'Ů': 'U', 'Ž': 'Z'
+ };
+ const SLOVAK_MAP = {
+ 'á': 'a', 'ä': 'a', 'č': 'c', 'ď': 'd', 'é': 'e', 'í': 'i', 'ľ': 'l',
+ 'ĺ': 'l', 'ň': 'n', 'ó': 'o', 'ô': 'o', 'ŕ': 'r', 'š': 's', 'ť': 't',
+ 'ú': 'u', 'ý': 'y', 'ž': 'z',
+ 'Á': 'a', 'Ä': 'A', 'Č': 'C', 'Ď': 'D', 'É': 'E', 'Í': 'I', 'Ľ': 'L',
+ 'Ĺ': 'L', 'Ň': 'N', 'Ó': 'O', 'Ô': 'O', 'Ŕ': 'R', 'Š': 'S', 'Ť': 'T',
+ 'Ú': 'U', 'Ý': 'Y', 'Ž': 'Z'
+ };
+ const POLISH_MAP = {
+ 'ą': 'a', 'ć': 'c', 'ę': 'e', 'ł': 'l', 'ń': 'n', 'ó': 'o', 'ś': 's',
+ 'ź': 'z', 'ż': 'z',
+ 'Ą': 'A', 'Ć': 'C', 'Ę': 'E', 'Ł': 'L', 'Ń': 'N', 'Ó': 'O', 'Ś': 'S',
+ 'Ź': 'Z', 'Ż': 'Z'
+ };
+ const LATVIAN_MAP = {
+ 'ā': 'a', 'č': 'c', 'ē': 'e', 'ģ': 'g', 'ī': 'i', 'ķ': 'k', 'ļ': 'l',
+ 'ņ': 'n', 'š': 's', 'ū': 'u', 'ž': 'z',
+ 'Ā': 'A', 'Č': 'C', 'Ē': 'E', 'Ģ': 'G', 'Ī': 'I', 'Ķ': 'K', 'Ļ': 'L',
+ 'Ņ': 'N', 'Š': 'S', 'Ū': 'U', 'Ž': 'Z'
+ };
+ const ARABIC_MAP = {
+ 'أ': 'a', 'ب': 'b', 'ت': 't', 'ث': 'th', 'ج': 'g', 'ح': 'h', 'خ': 'kh', 'د': 'd',
+ 'ذ': 'th', 'ر': 'r', 'ز': 'z', 'س': 's', 'ش': 'sh', 'ص': 's', 'ض': 'd', 'ط': 't',
+ 'ظ': 'th', 'ع': 'aa', 'غ': 'gh', 'ف': 'f', 'ق': 'k', 'ك': 'k', 'ل': 'l', 'م': 'm',
+ 'ن': 'n', 'ه': 'h', 'و': 'o', 'ي': 'y'
+ };
+ const LITHUANIAN_MAP = {
+ 'ą': 'a', 'č': 'c', 'ę': 'e', 'ė': 'e', 'į': 'i', 'š': 's', 'ų': 'u',
+ 'ū': 'u', 'ž': 'z',
+ 'Ą': 'A', 'Č': 'C', 'Ę': 'E', 'Ė': 'E', 'Į': 'I', 'Š': 'S', 'Ų': 'U',
+ 'Ū': 'U', 'Ž': 'Z'
+ };
+ const SERBIAN_MAP = {
+ 'ђ': 'dj', 'ј': 'j', 'љ': 'lj', 'њ': 'nj', 'ћ': 'c', 'џ': 'dz',
+ 'đ': 'dj', 'Ђ': 'Dj', 'Ј': 'j', 'Љ': 'Lj', 'Њ': 'Nj', 'Ћ': 'C',
+ 'Џ': 'Dz', 'Đ': 'Dj'
+ };
+ const AZERBAIJANI_MAP = {
+ 'ç': 'c', 'ə': 'e', 'ğ': 'g', 'ı': 'i', 'ö': 'o', 'ş': 's', 'ü': 'u',
+ 'Ç': 'C', 'Ə': 'E', 'Ğ': 'G', 'İ': 'I', 'Ö': 'O', 'Ş': 'S', 'Ü': 'U'
+ };
+ const GEORGIAN_MAP = {
+ 'ა': 'a', 'ბ': 'b', 'გ': 'g', 'დ': 'd', 'ე': 'e', 'ვ': 'v', 'ზ': 'z',
+ 'თ': 't', 'ი': 'i', 'კ': 'k', 'ლ': 'l', 'მ': 'm', 'ნ': 'n', 'ო': 'o',
+ 'პ': 'p', 'ჟ': 'j', 'რ': 'r', 'ს': 's', 'ტ': 't', 'უ': 'u', 'ფ': 'f',
+ 'ქ': 'q', 'ღ': 'g', 'ყ': 'y', 'შ': 'sh', 'ჩ': 'ch', 'ც': 'c', 'ძ': 'dz',
+ 'წ': 'w', 'ჭ': 'ch', 'ხ': 'x', 'ჯ': 'j', 'ჰ': 'h'
+ };
+
+ const ALL_DOWNCODE_MAPS = [
+ LATIN_MAP,
+ LATIN_SYMBOLS_MAP,
+ GREEK_MAP,
+ TURKISH_MAP,
+ ROMANIAN_MAP,
+ RUSSIAN_MAP,
+ UKRAINIAN_MAP,
+ CZECH_MAP,
+ SLOVAK_MAP,
+ POLISH_MAP,
+ LATVIAN_MAP,
+ ARABIC_MAP,
+ LITHUANIAN_MAP,
+ SERBIAN_MAP,
+ AZERBAIJANI_MAP,
+ GEORGIAN_MAP
+ ];
+
+ const Downcoder = {
+ 'Initialize': function() {
+ if (Downcoder.map) { // already made
+ return;
+ }
+ Downcoder.map = {};
+ for (const lookup of ALL_DOWNCODE_MAPS) {
+ Object.assign(Downcoder.map, lookup);
+ }
+ Downcoder.regex = new RegExp(Object.keys(Downcoder.map).join('|'), 'g');
+ }
+ };
+
+ function downcode(slug) {
+ Downcoder.Initialize();
+ return slug.replace(Downcoder.regex, function(m) {
+ return Downcoder.map[m];
+ });
+ }
+
+
+ function URLify(s, num_chars, allowUnicode) {
+ // changes, e.g., "Petty theft" to "petty-theft"
+ if (!allowUnicode) {
+ s = downcode(s);
+ }
+ s = s.toLowerCase(); // convert to lowercase
+ // if downcode doesn't hit, the char will be stripped here
+ if (allowUnicode) {
+ // Keep Unicode letters including both lowercase and uppercase
+ // characters, whitespace, and dash; remove other characters.
+ s = XRegExp.replace(s, XRegExp('[^-_\\p{L}\\p{N}\\s]', 'g'), '');
+ } else {
+ s = s.replace(/[^-\w\s]/g, ''); // remove unneeded chars
+ }
+ s = s.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces
+ s = s.replace(/[-\s]+/g, '-'); // convert spaces to hyphens
+ s = s.substring(0, num_chars); // trim to first num_chars chars
+ return s.replace(/-+$/g, ''); // trim any trailing hyphens
+ }
+ window.URLify = URLify;
+}
diff --git a/django_code/django_code/cloudmanager/templates/admin/js/vendor/jquery/LICENSE.txt b/django_code/django_code/cloudmanager/templates/admin/js/vendor/jquery/LICENSE.txt
new file mode 100644
index 0000000..f642c3f
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/js/vendor/jquery/LICENSE.txt
@@ -0,0 +1,20 @@
+Copyright OpenJS Foundation and other contributors, https://openjsf.org/
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/django_code/django_code/cloudmanager/templates/admin/js/vendor/jquery/jquery.js b/django_code/django_code/cloudmanager/templates/admin/js/vendor/jquery/jquery.js
new file mode 100644
index 0000000..7f35c11
--- /dev/null
+++ b/django_code/django_code/cloudmanager/templates/admin/js/vendor/jquery/jquery.js
@@ -0,0 +1,10965 @@
+/*!
+ * jQuery JavaScript Library v3.6.4
+ * https://jquery.com/
+ *
+ * Includes Sizzle.js
+ * https://sizzlejs.com/
+ *
+ * Copyright OpenJS Foundation and other contributors
+ * Released under the MIT license
+ * https://jquery.org/license
+ *
+ * Date: 2023-03-08T15:28Z
+ */
+( function( global, factory ) {
+
+ "use strict";
+
+ if ( typeof module === "object" && typeof module.exports === "object" ) {
+
+ // For CommonJS and CommonJS-like environments where a proper `window`
+ // is present, execute the factory and get jQuery.
+ // For environments that do not have a `window` with a `document`
+ // (such as Node.js), expose a factory as module.exports.
+ // This accentuates the need for the creation of a real `window`.
+ // e.g. var jQuery = require("jquery")(window);
+ // See ticket trac-14549 for more info.
+ module.exports = global.document ?
+ factory( global, true ) :
+ function( w ) {
+ if ( !w.document ) {
+ throw new Error( "jQuery requires a window with a document" );
+ }
+ return factory( w );
+ };
+ } else {
+ factory( global );
+ }
+
+// Pass this if window is not defined yet
+} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
+
+// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
+// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
+// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
+// enough that all such attempts are guarded in a try block.
+"use strict";
+
+var arr = [];
+
+var getProto = Object.getPrototypeOf;
+
+var slice = arr.slice;
+
+var flat = arr.flat ? function( array ) {
+ return arr.flat.call( array );
+} : function( array ) {
+ return arr.concat.apply( [], array );
+};
+
+
+var push = arr.push;
+
+var indexOf = arr.indexOf;
+
+var class2type = {};
+
+var toString = class2type.toString;
+
+var hasOwn = class2type.hasOwnProperty;
+
+var fnToString = hasOwn.toString;
+
+var ObjectFunctionString = fnToString.call( Object );
+
+var support = {};
+
+var isFunction = function isFunction( obj ) {
+
+ // Support: Chrome <=57, Firefox <=52
+ // In some browsers, typeof returns "function" for HTML