diff --git a/.idea/devops.iml b/.idea/devops.iml index 700ae79..b987638 100644 --- a/.idea/devops.iml +++ b/.idea/devops.iml @@ -2,7 +2,7 @@ - + diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 23578e4..726b5e1 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -8,6 +8,9 @@ + + @@ -15,6 +18,19 @@ message status + readlink + transport + self.transport + 769 + open + TerminalSession + res_asciinema + res + self.res + close_ssh_self + daemon + close + terminal_log @@ -32,43 +48,51 @@ - + @@ -76,11 +100,6 @@ - - - - - @@ -90,11 +109,11 @@ ',""],l=[1,"","
"],c=[3,"","
"],p=[1,'',""],d={"*":[1,"?
","
"],area:[1,"",""],col:[2,"","
"],legend:[1,"
","
"],param:[1,"",""],tr:[2,"","
"],optgroup:u,option:u,caption:l,colgroup:l,tbody:l,tfoot:l,thead:l,td:c,th:c};["circle","clipPath","defs","ellipse","g","image","line","linearGradient","mask","path","pattern","polygon","polyline","radialGradient","rect","stop","text","tspan"].forEach(function(e){d[e]=p,s[e]=!0}),t.exports=r},{123:123,137:137}],134:[function(e,t,n){"use strict";function r(e){return e.Window&&e instanceof e.Window?{x:e.pageXOffset||e.document.documentElement.scrollLeft,y:e.pageYOffset||e.document.documentElement.scrollTop}:{x:e.scrollLeft,y:e.scrollTop}}t.exports=r},{}],135:[function(e,t,n){"use strict";function r(e){return e.replace(o,"-$1").toLowerCase()}var o=/([A-Z])/g;t.exports=r},{}],136:[function(e,t,n){"use strict";function r(e){return o(e).replace(i,"-ms-")}var o=e(135),i=/^ms-/;t.exports=r},{135:135}],137:[function(e,t,n){"use strict";function r(e,t,n,r,i,a,s,u){if(o(t),!e){var l;if(void 0===t)l=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var c=[n,r,i,a,s,u],p=0;l=new Error(t.replace(/%s/g,function(){return c[p++]})),l.name="Invariant Violation"}throw l.framesToPop=1,l}}var o=function(e){};t.exports=r},{}],138:[function(e,t,n){"use strict";function r(e){var t=e?e.ownerDocument||e:document,n=t.defaultView||window;return!(!e||!("function"==typeof n.Node?e instanceof n.Node:"object"==typeof e&&"number"==typeof e.nodeType&&"string"==typeof e.nodeName))}t.exports=r},{}],139:[function(e,t,n){"use strict";function r(e){return o(e)&&3==e.nodeType}var o=e(138);t.exports=r},{138:138}],140:[function(e,t,n){"use strict";function r(e){var t={};return function(n){return t.hasOwnProperty(n)||(t[n]=e.call(this,n)),t[n]}}t.exports=r},{}],141:[function(e,t,n){"use strict";function r(e,t){return e===t?0!==e||0!==t||1/e==1/t:e!==e&&t!==t}function o(e,t){if(r(e,t))return!0;if("object"!=typeof e||null===e||"object"!=typeof t||null===t)return!1;var n=Object.keys(e),o=Object.keys(t);if(n.length!==o.length)return!1;for(var a=0;a 0x10FFFF || // not a valid Unicode code point + floor(codePoint) != codePoint // not an integer + ) { + throw RangeError('Invalid code point: ' + codePoint); + } + if (codePoint <= 0xFFFF) { // BMP code point + codeUnits.push(codePoint); + } else { // Astral code point; split in surrogate halves + // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae + codePoint -= 0x10000; + highSurrogate = (codePoint >> 10) + 0xD800; + lowSurrogate = (codePoint % 0x400) + 0xDC00; + codeUnits.push(highSurrogate, lowSurrogate); + } + if (index + 1 == length || codeUnits.length > MAX_SIZE) { + result += stringFromCharCode.apply(null, codeUnits); + codeUnits.length = 0; + } + } + return result; + }; + if (defineProperty) { + defineProperty(String, 'fromCodePoint', { + 'value': fromCodePoint, + 'configurable': true, + 'writable': true + }); + } else { + String.fromCodePoint = fromCodePoint; + } + }()); +} + +/*! http://mths.be/codepointat v0.1.0 by @mathias */ +if (!String.prototype.codePointAt) { + (function() { + 'use strict'; // needed to support `apply`/`call` with `undefined`/`null` + var codePointAt = function(position) { + if (this == null) { + throw TypeError(); + } + var string = String(this); + var size = string.length; + // `ToInteger` + var index = position ? Number(position) : 0; + if (index != index) { // better `isNaN` + index = 0; + } + // Account for out-of-bounds indices: + if (index < 0 || index >= size) { + return undefined; + } + // Get the first code unit + var first = string.charCodeAt(index); + var second; + if ( // check if it’s the start of a surrogate pair + first >= 0xD800 && first <= 0xDBFF && // high surrogate + size > index + 1 // there is a next code unit + ) { + second = string.charCodeAt(index + 1); + if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate + // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae + return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; + } + } + return first; + }; + if (Object.defineProperty) { + Object.defineProperty(String.prototype, 'codePointAt', { + 'value': codePointAt, + 'configurable': true, + 'writable': true + }); + } else { + String.prototype.codePointAt = codePointAt; + } + }()); +} + +function registerAsciinemaPlayerElement() { + var AsciinemaPlayerProto = Object.create(HTMLElement.prototype); + + function merge() { + var merged = {}; + for (var i=0; i>>0),ma=0;function na(a,b,c){return a.call.apply(a.bind,arguments)} +function oa(a,b,c){if(!a)throw Error();if(2b?1:0};var ua=Array.prototype.indexOf?function(a,b,c){return Array.prototype.indexOf.call(a,b,c)}:function(a,b,c){c=null==c?0:0>c?Math.max(0,a.length+c):c;if(ca(a))return ca(b)&&1==b.length?a.indexOf(b,c):-1;for(;cb?null:ca(a)?a.charAt(b):a[b]}function ya(a,b){var c=ua(a,b),d;(d=0<=c)&&Array.prototype.splice.call(a,c,1);return d}function za(a,b){a.sort(b||Aa)}function Ca(a,b){for(var c=Array(a.length),d=0;db?1:a2*this.Fc&&Na(this),!0):!1};function Na(a){if(a.Fc!=a.ib.length){for(var b=0,c=0;ba){var b=Ra[a];if(b)return b}b=new Qa([a|0],0>a?-1:0);-128<=a&&128>a&&(Ra[a]=b);return b}function Ta(a){if(isNaN(a)||!isFinite(a))return Ua;if(0>a)return Ta(-a).kb();for(var b=[],c=1,d=0;a>=c;d++)b[d]=a/c|0,c*=Va;return new Qa(b,0)}var Va=4294967296,Ua=Sa(0),Wa=Sa(1),Xa=Sa(16777216);g=Qa.prototype; +g.Of=function(){return 0a||36>>0).toString(a);c=e;if(c.hc())return f+d;for(;6>f.length;)f="0"+f;d=""+f+d}};function Ya(a,b){return 0>b?0:bthis.compare(Xa)};g.Ve=function(a){return 0>=this.compare(a)};g.compare=function(a){a=this.ze(a);return a.Eb()?-1:a.hc()?0:1};g.kb=function(){return this.Hf().add(Wa)}; +g.add=function(a){for(var b=Math.max(this.Ma.length,a.Ma.length),c=[],d=0,e=0;e<=b;e++){var f=d+(Ya(this,e)&65535)+(Ya(a,e)&65535),h=(f>>>16)+(Ya(this,e)>>>16)+(Ya(a,e)>>>16);d=h>>>16;f&=65535;h&=65535;c[e]=h<<16|f}return new Qa(c,c[c.length-1]&-2147483648?-1:0)};g.ze=function(a){return this.add(a.kb())}; +g.multiply=function(a){if(this.hc()||a.hc())return Ua;if(this.Eb())return a.Eb()?this.kb().multiply(a.kb()):this.kb().multiply(a).kb();if(a.Eb())return this.multiply(a.kb()).kb();if(this.Ue()&&a.Ue())return Ta(this.vd()*a.vd());for(var b=this.Ma.length+a.Ma.length,c=[],d=0;d<2*b;d++)c[d]=0;for(d=0;d>>16,h=Ya(this,d)&65535,k=Ya(a,e)>>>16,l=Ya(a,e)&65535;c[2*d+2*e]+=h*l;ab(c,2*d+2*e);c[2*d+2*e+1]+=f*l;ab(c,2*d+2*e+1);c[2*d+2*e+1]+= +h*k;ab(c,2*d+2*e+1);c[2*d+2*e+2]+=f*k;ab(c,2*d+2*e+2)}for(d=0;d>>16,a[b]&=65535,b++} +function Za(a,b){if(b.hc())throw Error("division by zero");if(a.hc())return Ua;if(a.Eb())return b.Eb()?Za(a.kb(),b.kb()):Za(a.kb(),b).kb();if(b.Eb())return Za(a,b.kb()).kb();if(30=f?1:Math.pow(2,f-48);h=Ta(e);for(var k=h.multiply(b);k.Eb()||k.xf(d);)e-=f,h=Ta(e),k=h.multiply(b);h.hc()&&(h=Wa);c=c.add(h);d=d.ze(k)}return c}g.Hf=function(){for(var a=this.Ma.length,b=[],c=0;c>5;a%=32;for(var c=this.Ma.length+b+(0>>32-a:Ya(this,e-b);return new Qa(d,this.Lc)}; +g.ad=function(a){var b=a>>5;a%=32;for(var c=this.Ma.length-b,d=[],e=0;e>>a|Ya(this,e+b+1)<<32-a:Ya(this,e+b);return new Qa(d,this.Lc)};function cb(a,b){null!=a&&this.append.apply(this,arguments)}g=cb.prototype;g.xc="";g.set=function(a){this.xc=""+a};g.append=function(a,b,c){this.xc+=String(a);if(null!=b)for(var d=1;d>>16&65535)*d+c*(b>>>16&65535)<<16>>>0)|0};function hd(a){a=gd(a|0,-862048943);return gd(a<<15|a>>>-15,461845907)} +function id(a,b){var c=(a|0)^(b|0);return gd(c<<13|c>>>-13,5)+-430675100|0}function jd(a,b){var c=(a|0)^b;c=gd(c^c>>>16,-2048144789);c=gd(c^c>>>13,-1028477387);return c^c>>>16}function kd(a){a:{var b=1;for(var c=0;;)if(b>2)}function qd(a){return a instanceof rd} +function sd(a,b){if(a.Zb===b.Zb)return 0;var c=wb(a.fb);if(t(c?b.fb:c))return-1;if(t(a.fb)){if(wb(b.fb))return 1;c=Aa(a.fb,b.fb);return 0===c?Aa(a.name,b.name):c}return Aa(a.name,b.name)}function rd(a,b,c,d,e){this.fb=a;this.name=b;this.Zb=c;this.Oc=d;this.hb=e;this.m=2154168321;this.J=4096}g=rd.prototype;g.toString=function(){return this.Zb};g.equiv=function(a){return this.K(null,a)};g.K=function(a,b){return b instanceof rd?this.Zb===b.Zb:!1}; +g.call=function(){var a=null;a=function(a,c,d){switch(arguments.length){case 2:return D.c(c,this);case 3:return D.l(c,this,d)}throw Error("Invalid arity: "+(arguments.length-1));};a.c=function(a,c){return D.c(c,this)};a.l=function(a,c,d){return D.l(c,this,d)};return a}();g.apply=function(a,b){return this.call.apply(this,[this].concat(Gb(b)))};g.h=function(a){return D.c(a,this)};g.c=function(a,b){return D.l(a,this,b)};g.P=function(){return this.hb}; +g.T=function(a,b){return new rd(this.fb,this.name,this.Zb,this.Oc,b)};g.U=function(){var a=this.Oc;return null!=a?a:this.Oc=a=pd(kd(this.name),nd(this.fb))};g.hd=function(){return this.name};g.jd=function(){return this.fb};g.R=function(a,b){return Jc(b,this.Zb)};var td=function td(a){switch(arguments.length){case 1:return td.h(arguments[0]);case 2:return td.c(arguments[0],arguments[1]);default:throw Error(["Invalid arity: ",v.h(arguments.length)].join(""));}}; +td.h=function(a){if(a instanceof rd)return a;var b=a.indexOf("/");return 1>b?td.c(null,a):td.c(a.substring(0,b),a.substring(b+1,a.length))};td.c=function(a,b){var c=null!=a?[v.h(a),"/",v.h(b)].join(""):b;return new rd(a,b,c,null,null)};td.L=2;function ud(a){return null!=a?a.J&131072||q===a.Tf?!0:a.J?!1:Ab(cd,a):Ab(cd,a)} +function E(a){if(null==a)return null;if(null!=a&&(a.m&8388608||q===a.Pe))return a.S(null);if(vb(a)||"string"===typeof a)return 0===a.length?null:new Jb(a,0,null);if(Ab(Bc,a))return Cc(a);throw Error([v.h(a)," is not ISeqable"].join(""));}function y(a){if(null==a)return null;if(null!=a&&(a.m&64||q===a.G))return a.Ia(null);a=E(a);return null==a?null:Wb(a)}function vd(a){return null!=a?null!=a&&(a.m&64||q===a.G)?a.bb(null):(a=E(a))?Yb(a):wd:wd} +function z(a){return null==a?null:null!=a&&(a.m&128||q===a.Id)?a.Ka(null):E(vd(a))}var G=function G(a){switch(arguments.length){case 1:return G.h(arguments[0]);case 2:return G.c(arguments[0],arguments[1]);default:for(var c=[],d=arguments.length,e=0;;)if(e=d)return-1;!(0c&&(c+=d,c=0>c?0:c);for(;;)if(cc?d+c:c;for(;;)if(0<=c){if(G.c(Vd(a,c),b))return c;--c}else return-1}function Yd(a,b){this.o=a;this.i=b} +Yd.prototype.ja=function(){return this.ia?0:a};g.Rc=function(){var a=this.W(null);return 0d)c=1;else if(0===c)c=0;else a:for(d=0;;){var e=Ke(Vd(a,d),Vd(b,d));if(0===e&&d+1>1&1431655765;a=(a&858993459)+(a>>2&858993459);return 16843009*(a+(a>>4)&252645135)>>24} +var v=function v(a){switch(arguments.length){case 0:return v.B();case 1:return v.h(arguments[0]);default:for(var c=[],d=arguments.length,e=0;;)if(ed:e))c[d]=a.next(),d+=1;else return qf(new nf(c,0,d),Rf.h?Rf.h(a):Rf.call(null,a))}else return null},null,null)};function Sf(a,b,c,d,e,f){this.buffer=a;this.ub=b;this.pe=c;this.Rb=d;this.ye=e;this.Gf=f} +Sf.prototype.step=function(){if(this.ub!==Nf)return!0;for(;;)if(this.ub===Nf)if(this.buffer.Td()){if(this.pe)return!1;if(this.ye.ja()){if(this.Gf)var a=P(this.Rb,ae(null,this.ye.next()));else a=this.ye.next(),a=this.Rb.c?this.Rb.c(null,a):this.Rb.call(null,null,a);Hd(a)&&(this.Rb.h?this.Rb.h(null):this.Rb.call(null,null),this.pe=!0)}else this.Rb.h?this.Rb.h(null):this.Rb.call(null,null),this.pe=!0}else this.ub=this.buffer.remove();else return!0};Sf.prototype.ja=function(){return this.step()}; +Sf.prototype.next=function(){if(this.ja()){var a=this.ub;this.ub=Nf;return a}throw Error("No such element");};Sf.prototype.remove=function(){return Error("Unsupported operation")};Sf.prototype[Fb]=function(){return yd(this)}; +function Tf(a,b){var c=new Sf(Qf,Nf,!1,null,b,!1);c.Rb=function(){var b=function(a){return function(){function b(b,c){a.buffer=a.buffer.add(c);return b}var c=null;c=function(a,c){switch(arguments.length){case 0:return null;case 1:return a;case 2:return b.call(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};c.B=function(){return null};c.h=function(a){return a};c.c=b;return c}()}(c);return a.h?a.h(b):a.call(null,b)}();return c} +function Uf(a,b){var c=Kf(b);c=Tf(a,c);c=Rf(c);return t(c)?c:wd}function Vf(a,b){for(;;){if(null==E(b))return!0;var c=y(b);c=a.h?a.h(c):a.call(null,c);if(t(c)){c=a;var d=z(b);a=c;b=d}else return!1}}function Wf(a,b){for(;;)if(E(b)){var c=y(b);c=a.h?a.h(c):a.call(null,c);if(t(c))return c;c=a;var d=z(b);a=c;b=d}else return null}function Xf(a){if(Ge(a))return 0===(a&1);throw Error(["Argument must be an integer: ",v.h(a)].join(""));} +function Yf(a){return function(){function b(b,c){return wb(a.c?a.c(b,c):a.call(null,b,c))}function c(b){return wb(a.h?a.h(b):a.call(null,b))}function d(){return wb(a.B?a.B():a.call(null))}var e=null,f=function(){function b(a,b,d){var e=null;if(2a?0:a-1>>>5<<5}function Jg(a,b,c){for(;;){if(0===b)return c;var d=Gg(a);d.o[0]=c;c=d;b-=5}} +var Kg=function Kg(a,b,c,d){var f=Hg(c),h=a.F-1>>>b&31;5===b?f.o[h]=d:(c=c.o[h],null!=c?(b-=5,a=Kg.M?Kg.M(a,b,c,d):Kg.call(null,a,b,c,d)):a=Jg(null,b-5,d),f.o[h]=a);return f};function Lg(a,b){throw Error(["No item ",v.h(a)," in vector of length ",v.h(b)].join(""));}function Mg(a,b){if(b>=Ig(a))return a.fa;for(var c=a.root,d=a.shift;;)if(0>>d&31];d=e}else return c.o} +var Ng=function Ng(a,b,c,d,e){var h=Hg(c);if(0===b)h.o[d&31]=e;else{var k=d>>>b&31;b-=5;c=c.o[k];a=Ng.Z?Ng.Z(a,b,c,d,e):Ng.call(null,a,b,c,d,e);h.o[k]=a}return h},Og=function Og(a,b,c){var e=a.F-2>>>b&31;if(5=this.F)a=new Jb(this.fa,0,null);else{a:{a=this.root;for(var b=this.shift;;)if(0this.F-Ig(this)){for(var c=this.fa.length,d=Array(c+1),e=0;;)if(e>>5>1<b)return new R(null,b,5,T,a,null);for(var c=32,d=(new R(null,32,5,T,a.slice(0,32),null)).Pc(null);;)if(cb||this.end<=this.start+b?Lg(b,this.end-this.start):A.c(this.Ja,this.start+b)};g.ka=function(a,b,c){return 0>b||this.end<=this.start+b?c:A.l(this.Ja,this.start+b,c)}; +g.dc=function(a,b,c){a=this.start+b;if(0>b||this.end+1<=a)throw Error(["Index ",v.h(b)," out of bounds [0,",v.h(this.W(null)),"]"].join(""));b=this.meta;c=K.l(this.Ja,a,c);var d=this.end;a+=1;return Zg(b,c,this.start,d>a?d:a,null)};g.ba=function(){return null!=this.Ja&&q===this.Ja.fe?Qg(this.Ja,this.start,this.end):new Jf(Hf,this)};g.P=function(){return this.meta};g.W=function(){return this.end-this.start};g.Ac=function(){return A.c(this.Ja,this.end-1)}; +g.Bc=function(){if(this.start===this.end)throw Error("Can't pop empty vector");return Zg(this.meta,this.Ja,this.start,this.end-1,null)};g.Rc=function(){return this.start!==this.end?new Zd(this,this.end-this.start-1,null):null};g.U=function(){var a=this.w;return null!=a?a:this.w=a=Ad(this)};g.K=function(a,b){return $d(this,b)};g.oa=function(){return tc(he,this.meta)};g.Fa=function(a,b){return null!=this.Ja&&q===this.Ja.fe?Rg(this.Ja,b,this.start,this.end):Kd(this,b)}; +g.Ga=function(a,b,c){return null!=this.Ja&&q===this.Ja.fe?Sg(this.Ja,b,c,this.start,this.end):Ld(this,b,c)};g.O=function(a,b,c){if("number"===typeof b)return this.dc(null,b,c);throw Error("Subvec's key for assoc must be a number.");};g.S=function(){var a=this;return function(b){return function e(d){return d===a.end?null:ae(A.c(a.Ja,d),new kf(null,function(){return function(){return e(d+1)}}(b),null,null))}}(this)(a.start)};g.T=function(a,b){return Zg(b,this.Ja,this.start,this.end,this.w)}; +g.X=function(a,b){return Zg(this.meta,qc(this.Ja,this.end,b),this.start,this.end+1,null)};g.call=function(){var a=null;a=function(a,c,d){switch(arguments.length){case 2:return this.$(null,c);case 3:return this.ka(null,c,d)}throw Error("Invalid arity: "+(arguments.length-1));};a.c=function(a,c){return this.$(null,c)};a.l=function(a,c,d){return this.ka(null,c,d)};return a}();g.apply=function(a,b){return this.call.apply(this,[this].concat(Gb(b)))};g.h=function(a){return this.$(null,a)}; +g.c=function(a,b){return this.ka(null,a,b)};Yg.prototype[Fb]=function(){return yd(this)};function Zg(a,b,c,d,e){for(;;)if(b instanceof Yg)c=b.start+c,d=b.start+d,b=b.Ja;else{if(!ze(b))throw Error("v must satisfy IVector");var f=H(b);if(0>c||0>d||c>f||d>f)throw Error("Index out of bounds");return new Yg(a,b,c,d,e)}}function $g(a,b){return a===b.la?b:new Fg(a,Gb(b.o))} +var ah=function ah(a,b,c,d){c=$g(a.root.la,c);var f=a.F-1>>>b&31;if(5===b)a=d;else{var h=c.o[f];null!=h?(b-=5,a=ah.M?ah.M(a,b,h,d):ah.call(null,a,b,h,d)):a=Jg(a.root.la,b-5,d)}c.o[f]=a;return c};function Tg(a,b,c,d){this.F=a;this.shift=b;this.root=c;this.fa=d;this.J=88;this.m=275}g=Tg.prototype; +g.Dc=function(a,b){if(this.root.la){if(32>this.F-Ig(this))this.fa[this.F&31]=b;else{var c=new Fg(this.root.la,this.fa),d=[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null];d[0]=b;this.fa=d;if(this.F>>>5>1<>>d&31,m=k(d-5,f.o[p]);f.o[p]=m}return f}}(a)(a.shift,a.root)}();a.root=d}return a}if(b===a.F)return a.Dc(null,c);throw Error(["Index ",v.h(b)," out of bounds for TransientVector of length",v.h(a.F)].join(""));}throw Error("assoc! after persistent!");} +g.W=function(){if(this.root.la)return this.F;throw Error("count after persistent!");};g.$=function(a,b){if(this.root.la)return(0<=b&&b=c)return new r(this.meta,this.F-1,d,null);G.c(b,this.o[e])||(d[f]=this.o[e],d[f+1]=this.o[e+1],f+=2);e+=2}}else return this}; +g.O=function(a,b,c){a=ih(this.o,b);if(-1===a){if(this.Fb?4:2*(b+1));Be(this.o,0,c,0,2*b);return new xh(a,this.na,c)};g.qd=function(){return yh(this.o,0,null)};g.Jc=function(a,b){return vh(this.o,a,b)};g.sc=function(a,b,c,d){var e=1<<(b>>>a&31);if(0===(this.na&e))return d;var f=$e(this.na&e-1);e=this.o[2*f];f=this.o[2*f+1];return null==e?f.sc(a+5,b,c,d):rh(c,e)?f:d}; +g.Kb=function(a,b,c,d,e,f){var h=1<<(c>>>b&31),k=$e(this.na&h-1);if(0===(this.na&h)){var l=$e(this.na);if(2*l>>b&31]=zh.Kb(a,b+5,c,d,e,f);for(e=d=0;;)if(32>d)0!== +(this.na>>>d&1)&&(k[d]=null!=this.o[e]?zh.Kb(a,b+5,od(this.o[e]),this.o[e],this.o[e+1],f):this.o[e+1],e+=2),d+=1;else break;return new Ah(a,l+1,k)}b=Array(2*(l+4));Be(this.o,0,b,0,2*k);b[2*k]=d;b[2*k+1]=e;Be(this.o,2*k,b,2*(k+1),2*(l-k));f.H=!0;a=this.Gc(a);a.o=b;a.na|=h;return a}l=this.o[2*k];h=this.o[2*k+1];if(null==l)return l=h.Kb(a,b+5,c,d,e,f),l===h?this:uh(this,a,2*k+1,l);if(rh(d,l))return e===h?this:uh(this,a,2*k+1,e);f.H=!0;f=b+5;b=od(l);if(b===c)e=new Bh(null,b,2,[l,h,d,e]);else{var p=new qh; +e=zh.Kb(a,f,b,l,h,p).Kb(a,f,c,d,e,p)}d=2*k;k=2*k+1;a=this.Gc(a);a.o[d]=null;a.o[k]=e;return a}; +g.Jb=function(a,b,c,d,e){var f=1<<(b>>>a&31),h=$e(this.na&f-1);if(0===(this.na&f)){var k=$e(this.na);if(16<=k){h=[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null];h[b>>>a&31]=zh.Jb(a+5,b,c,d,e);for(d=c=0;;)if(32>c)0!==(this.na>>>c&1)&&(h[c]=null!=this.o[d]?zh.Jb(a+5,od(this.o[d]),this.o[d],this.o[d+1],e):this.o[d+1],d+=2),c+=1;else break;return new Ah(null,k+1,h)}a=Array(2*(k+1));Be(this.o, +0,a,0,2*h);a[2*h]=c;a[2*h+1]=d;Be(this.o,2*h,a,2*(h+1),2*(k-h));e.H=!0;return new xh(null,this.na|f,a)}var l=this.o[2*h];f=this.o[2*h+1];if(null==l)return k=f.Jb(a+5,b,c,d,e),k===f?this:new xh(null,this.na,sh(this.o,2*h+1,k));if(rh(c,l))return d===f?this:new xh(null,this.na,sh(this.o,2*h+1,d));e.H=!0;e=this.na;k=this.o;a+=5;var p=od(l);if(p===b)c=new Bh(null,p,2,[l,f,c,d]);else{var m=new qh;c=zh.Jb(a,p,l,f,m).Jb(a,b,c,d,m)}a=2*h;h=2*h+1;d=Gb(k);d[a]=null;d[h]=c;return new xh(null,e,d)}; +g.rd=function(a,b,c){var d=1<<(b>>>a&31);if(0===(this.na&d))return this;var e=$e(this.na&d-1),f=this.o[2*e],h=this.o[2*e+1];return null==f?(a=h.rd(a+5,b,c),a===h?this:null!=a?new xh(null,this.na,sh(this.o,2*e+1,a)):this.na===d?null:new xh(null,this.na^d,th(this.o,e))):rh(c,f)?new xh(null,this.na^d,th(this.o,e)):this};g.ba=function(){return new wh(this.o,0,null,null)};var zh=new xh(null,0,[]);function Ch(a,b,c){this.o=a;this.i=b;this.Lb=c} +Ch.prototype.ja=function(){for(var a=this.o.length;;){if(null!=this.Lb&&this.Lb.ja())return!0;if(this.i>>a&31];return null!=e?e.sc(a+5,b,c,d):d};g.Kb=function(a,b,c,d,e,f){var h=c>>>b&31,k=this.o[h];if(null==k)return a=uh(this,a,h,zh.Kb(a,b+5,c,d,e,f)),a.F+=1,a;b=k.Kb(a,b+5,c,d,e,f);return b===k?this:uh(this,a,h,b)}; +g.Jb=function(a,b,c,d,e){var f=b>>>a&31,h=this.o[f];if(null==h)return new Ah(null,this.F+1,sh(this.o,f,zh.Jb(a+5,b,c,d,e)));a=h.Jb(a+5,b,c,d,e);return a===h?this:new Ah(null,this.F,sh(this.o,f,a))}; +g.rd=function(a,b,c){var d=b>>>a&31,e=this.o[d];if(null!=e){a=e.rd(a+5,b,c);if(a===e)d=this;else if(null==a)if(8>=this.F)a:{e=this.o;a=e.length;b=Array(2*(this.F-1));c=0;for(var f=1,h=0;;)if(ca?d:rh(c,this.o[a])?this.o[a+1]:d}; +g.Kb=function(a,b,c,d,e,f){if(c===this.ec){b=Eh(this.o,this.F,d);if(-1===b){if(this.o.length>2*this.F)return b=2*this.F,c=2*this.F+1,a=this.Gc(a),a.o[b]=d,a.o[c]=e,f.H=!0,a.F+=1,a;c=this.o.length;b=Array(c+2);Be(this.o,0,b,0,c);b[c]=d;b[c+1]=e;f.H=!0;d=this.F+1;a===this.la?(this.o=b,this.F=d,a=this):a=new Bh(this.la,this.ec,d,b);return a}return this.o[b+1]===e?this:uh(this,a,b+1,e)}return(new xh(a,1<<(this.ec>>>b&31),[null,this,null,null])).Kb(a,b,c,d,e,f)}; +g.Jb=function(a,b,c,d,e){return b===this.ec?(a=Eh(this.o,this.F,c),-1===a?(a=2*this.F,b=Array(a+2),Be(this.o,0,b,0,a),b[a]=c,b[a+1]=d,e.H=!0,new Bh(null,this.ec,this.F+1,b)):G.c(this.o[a+1],d)?this:new Bh(null,this.ec,this.F,sh(this.o,a+1,d))):(new xh(null,1<<(this.ec>>>a&31),[null,this])).Jb(a,b,c,d,e)};g.rd=function(a,b,c){a=Eh(this.o,this.F,c);return-1===a?this:1===this.F?null:new Bh(null,this.ec,this.F-1,th(this.o,Ze(a)))};g.ba=function(){return new wh(this.o,0,null,null)}; +function Fh(a,b,c,d,e){this.meta=a;this.Mb=b;this.i=c;this.s=d;this.w=e;this.m=32374988;this.J=0}g=Fh.prototype;g.toString=function(){return fd(this)};g.equiv=function(a){return this.K(null,a)};g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}(); +g.lastIndexOf=function(){function a(a){return Xd(this,a,H(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}();g.P=function(){return this.meta};g.Ka=function(){return null==this.s?yh(this.Mb,this.i+2,null):yh(this.Mb,this.i,z(this.s))};g.U=function(){var a=this.w;return null!=a?a:this.w=a=Ad(this)}; +g.K=function(a,b){return $d(this,b)};g.oa=function(){return tc(wd,this.meta)};g.Fa=function(a,b){return ce(b,this)};g.Ga=function(a,b,c){return de(b,c,this)};g.Ia=function(){return null==this.s?new R(null,2,5,T,[this.Mb[this.i],this.Mb[this.i+1]],null):y(this.s)};g.bb=function(){var a=null==this.s?yh(this.Mb,this.i+2,null):yh(this.Mb,this.i,z(this.s));return null!=a?a:wd};g.S=function(){return this};g.T=function(a,b){return new Fh(b,this.Mb,this.i,this.s,this.w)};g.X=function(a,b){return ae(b,this)}; +Fh.prototype[Fb]=function(){return yd(this)};function yh(a,b,c){if(null==c)for(c=a.length;;)if(bthis.F?H(z(this))+1:this.F};g.U=function(){var a=this.w;return null!=a?a:this.w=a=Ad(this)};g.K=function(a,b){return $d(this,b)};g.oa=function(){return tc(wd,this.meta)};g.Fa=function(a,b){return ce(b,this)};g.Ga=function(a,b,c){return de(b,c,this)};g.Ia=function(){var a=this.stack;return null==a?null:nc(a)};g.bb=function(){var a=y(this.stack);a=Mh(this.vc?a.right:a.left,z(this.stack),this.vc);return null!=a?new Nh(null,a,this.vc,this.F-1,null):wd};g.S=function(){return this}; +g.T=function(a,b){return new Nh(b,this.stack,this.vc,this.F,this.w)};g.X=function(a,b){return ae(b,this)};Nh.prototype[Fb]=function(){return yd(this)};function Oh(a,b,c){return new Nh(null,Mh(a,null,b),b,c,null)} +function Ph(a,b,c,d){return c instanceof Qh?c.left instanceof Qh?new Qh(c.key,c.H,c.left.bc(),new Rh(a,b,c.right,d,null),null):c.right instanceof Qh?new Qh(c.right.key,c.right.H,new Rh(c.key,c.H,c.left,c.right.left,null),new Rh(a,b,c.right.right,d,null),null):new Rh(a,b,c,d,null):new Rh(a,b,c,d,null)} +function Sh(a,b,c,d){return d instanceof Qh?d.right instanceof Qh?new Qh(d.key,d.H,new Rh(a,b,c,d.left,null),d.right.bc(),null):d.left instanceof Qh?new Qh(d.left.key,d.left.H,new Rh(a,b,c,d.left.left,null),new Rh(d.key,d.H,d.left.right,d.right,null),null):new Rh(a,b,c,d,null):new Rh(a,b,c,d,null)} +function Th(a,b,c,d){if(c instanceof Qh)return new Qh(a,b,c.bc(),d,null);if(d instanceof Rh)return Sh(a,b,c,d.ud());if(d instanceof Qh&&d.left instanceof Rh)return new Qh(d.left.key,d.left.H,new Rh(a,b,c,d.left.left,null),Sh(d.key,d.H,d.left.right,d.right.ud()),null);throw Error("red-black tree invariant violation");} +function Uh(a,b,c,d){if(d instanceof Qh)return new Qh(a,b,c,d.bc(),null);if(c instanceof Rh)return Ph(a,b,c.ud(),d);if(c instanceof Qh&&c.right instanceof Rh)return new Qh(c.right.key,c.right.H,Ph(c.key,c.H,c.left.ud(),c.right.left),new Rh(a,b,c.right.right,d,null),null);throw Error("red-black tree invariant violation");} +var Vh=function Vh(a,b,c){var e=null!=a.left?function(){var e=a.left;return Vh.l?Vh.l(e,b,c):Vh.call(null,e,b,c)}():c;if(Hd(e))return e;var f=function(){var c=a.key,f=a.H;return b.l?b.l(e,c,f):b.call(null,e,c,f)}();if(Hd(f))return f;if(null!=a.right){var h=a.right;return Vh.l?Vh.l(h,b,f):Vh.call(null,h,b,f)}return f};function Rh(a,b,c,d,e){this.key=a;this.H=b;this.left=c;this.right=d;this.w=e;this.m=32402207;this.J=0}g=Rh.prototype; +g.lastIndexOf=function(){function a(a){return Xd(this,a,H(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}(); +g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}();g.Ee=function(a){return a.He(this)};g.ud=function(){return new Qh(this.key,this.H,this.left,this.right,null)};g.bc=function(){return this};g.De=function(a){return a.Ge(this)};g.replace=function(a,b,c,d){return new Rh(a,b,c,d,null)}; +g.Ge=function(a){return new Rh(a.key,a.H,this,a.right,null)};g.He=function(a){return new Rh(a.key,a.H,a.left,this,null)};g.Jc=function(a,b){return Vh(this,a,b)};g.V=function(a,b){return this.ka(null,b,null)};g.I=function(a,b,c){return this.ka(null,b,c)};g.$=function(a,b){if(0===b)return this.key;if(1===b)return this.H;throw Error("Index out of bounds");};g.ka=function(a,b,c){return 0===b?this.key:1===b?this.H:c};g.dc=function(a,b,c){return(new R(null,2,5,T,[this.key,this.H],null)).dc(null,b,c)}; +g.P=function(){return null};g.W=function(){return 2};g.fd=function(){return this.key};g.gd=function(){return this.H};g.Ac=function(){return this.H};g.Bc=function(){return new R(null,1,5,T,[this.key],null)};g.U=function(){var a=this.w;return null!=a?a:this.w=a=Ad(this)};g.K=function(a,b){return $d(this,b)};g.oa=function(){return he};g.Fa=function(a,b){return Kd(this,b)};g.Ga=function(a,b,c){return Ld(this,b,c)};g.O=function(a,b,c){return K.l(new R(null,2,5,T,[this.key,this.H],null),b,c)}; +g.yc=function(a,b){return 0===b||1===b};g.S=function(){var a=this.key;return Tb(Tb(wd,this.H),a)};g.T=function(a,b){return tc(new R(null,2,5,T,[this.key,this.H],null),b)};g.X=function(a,b){return new R(null,3,5,T,[this.key,this.H,b],null)}; +g.call=function(){var a=null;a=function(a,c,d){switch(arguments.length){case 2:return this.$(null,c);case 3:return this.ka(null,c,d)}throw Error("Invalid arity: "+(arguments.length-1));};a.c=function(a,c){return this.$(null,c)};a.l=function(a,c,d){return this.ka(null,c,d)};return a}();g.apply=function(a,b){return this.call.apply(this,[this].concat(Gb(b)))};g.h=function(a){return this.$(null,a)};g.c=function(a,b){return this.ka(null,a,b)};Rh.prototype[Fb]=function(){return yd(this)}; +function Qh(a,b,c,d,e){this.key=a;this.H=b;this.left=c;this.right=d;this.w=e;this.m=32402207;this.J=0}g=Qh.prototype;g.lastIndexOf=function(){function a(a){return Xd(this,a,H(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}(); +g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}();g.Ee=function(a){return new Qh(this.key,this.H,this.left,a,null)};g.ud=function(){throw Error("red-black tree invariant violation");};g.bc=function(){return new Rh(this.key,this.H,this.left,this.right,null)}; +g.De=function(a){return new Qh(this.key,this.H,a,this.right,null)};g.replace=function(a,b,c,d){return new Qh(a,b,c,d,null)};g.Ge=function(a){return this.left instanceof Qh?new Qh(this.key,this.H,this.left.bc(),new Rh(a.key,a.H,this.right,a.right,null),null):this.right instanceof Qh?new Qh(this.right.key,this.right.H,new Rh(this.key,this.H,this.left,this.right.left,null),new Rh(a.key,a.H,this.right.right,a.right,null),null):new Rh(a.key,a.H,this,a.right,null)}; +g.He=function(a){return this.right instanceof Qh?new Qh(this.key,this.H,new Rh(a.key,a.H,a.left,this.left,null),this.right.bc(),null):this.left instanceof Qh?new Qh(this.left.key,this.left.H,new Rh(a.key,a.H,a.left,this.left.left,null),new Rh(this.key,this.H,this.left.right,this.right,null),null):new Rh(a.key,a.H,a.left,this,null)};g.Jc=function(a,b){return Vh(this,a,b)};g.V=function(a,b){return this.ka(null,b,null)};g.I=function(a,b,c){return this.ka(null,b,c)}; +g.$=function(a,b){if(0===b)return this.key;if(1===b)return this.H;throw Error("Index out of bounds");};g.ka=function(a,b,c){return 0===b?this.key:1===b?this.H:c};g.dc=function(a,b,c){return(new R(null,2,5,T,[this.key,this.H],null)).dc(null,b,c)};g.P=function(){return null};g.W=function(){return 2};g.fd=function(){return this.key};g.gd=function(){return this.H};g.Ac=function(){return this.H};g.Bc=function(){return new R(null,1,5,T,[this.key],null)}; +g.U=function(){var a=this.w;return null!=a?a:this.w=a=Ad(this)};g.K=function(a,b){return $d(this,b)};g.oa=function(){return he};g.Fa=function(a,b){return Kd(this,b)};g.Ga=function(a,b,c){return Ld(this,b,c)};g.O=function(a,b,c){return K.l(new R(null,2,5,T,[this.key,this.H],null),b,c)};g.yc=function(a,b){return 0===b||1===b};g.S=function(){var a=this.key;return Tb(Tb(wd,this.H),a)};g.T=function(a,b){return tc(new R(null,2,5,T,[this.key,this.H],null),b)}; +g.X=function(a,b){return new R(null,3,5,T,[this.key,this.H,b],null)};g.call=function(){var a=null;a=function(a,c,d){switch(arguments.length){case 2:return this.$(null,c);case 3:return this.ka(null,c,d)}throw Error("Invalid arity: "+(arguments.length-1));};a.c=function(a,c){return this.$(null,c)};a.l=function(a,c,d){return this.ka(null,c,d)};return a}();g.apply=function(a,b){return this.call.apply(this,[this].concat(Gb(b)))};g.h=function(a){return this.$(null,a)}; +g.c=function(a,b){return this.ka(null,a,b)};Qh.prototype[Fb]=function(){return yd(this)}; +var Wh=function Wh(a,b,c,d,e){if(null==b)return new Qh(c,d,null,null,null);var h=function(){var d=b.key;return a.c?a.c(c,d):a.call(null,c,d)}();if(0===h)return e[0]=b,null;if(0>h)return h=function(){var h=b.left;return Wh.Z?Wh.Z(a,h,c,d,e):Wh.call(null,a,h,c,d,e)}(),null!=h?b.De(h):null;h=function(){var h=b.right;return Wh.Z?Wh.Z(a,h,c,d,e):Wh.call(null,a,h,c,d,e)}();return null!=h?b.Ee(h):null},Xh=function Xh(a,b){if(null==a)return b;if(null==b)return a;if(a instanceof Qh){if(b instanceof Qh){var d= +function(){var d=a.right,f=b.left;return Xh.c?Xh.c(d,f):Xh.call(null,d,f)}();return d instanceof Qh?new Qh(d.key,d.H,new Qh(a.key,a.H,a.left,d.left,null),new Qh(b.key,b.H,d.right,b.right,null),null):new Qh(a.key,a.H,a.left,new Qh(b.key,b.H,d,b.right,null),null)}return new Qh(a.key,a.H,a.left,function(){var d=a.right;return Xh.c?Xh.c(d,b):Xh.call(null,d,b)}(),null)}if(b instanceof Qh)return new Qh(b.key,b.H,function(){var d=b.left;return Xh.c?Xh.c(a,d):Xh.call(null,a,d)}(),b.right,null);d=function(){var d= +a.right,f=b.left;return Xh.c?Xh.c(d,f):Xh.call(null,d,f)}();return d instanceof Qh?new Qh(d.key,d.H,new Rh(a.key,a.H,a.left,d.left,null),new Rh(b.key,b.H,d.right,b.right,null),null):Th(a.key,a.H,a.left,new Rh(b.key,b.H,d,b.right,null))},Yh=function Yh(a,b,c,d){if(null!=b){var f=function(){var d=b.key;return a.c?a.c(c,d):a.call(null,c,d)}();if(0===f)return d[0]=b,Xh(b.left,b.right);if(0>f)return f=function(){var f=b.left;return Yh.M?Yh.M(a,f,c,d):Yh.call(null,a,f,c,d)}(),null!=f||null!=d[0]?b.left instanceof +Rh?Th(b.key,b.H,f,b.right):new Qh(b.key,b.H,f,b.right,null):null;f=function(){var f=b.right;return Yh.M?Yh.M(a,f,c,d):Yh.call(null,a,f,c,d)}();return null!=f||null!=d[0]?b.right instanceof Rh?Uh(b.key,b.H,b.left,f):new Qh(b.key,b.H,b.left,f,null):null}return null},Zh=function Zh(a,b,c,d){var f=b.key,h=a.c?a.c(c,f):a.call(null,c,f);return 0===h?b.replace(f,d,b.left,b.right):0>h?b.replace(f,b.H,function(){var f=b.left;return Zh.M?Zh.M(a,f,c,d):Zh.call(null,a,f,c,d)}(),b.right):b.replace(f,b.H,b.left, +function(){var f=b.right;return Zh.M?Zh.M(a,f,c,d):Zh.call(null,a,f,c,d)}())};function $h(a,b,c,d,e){this.Bb=a;this.mc=b;this.F=c;this.meta=d;this.w=e;this.m=418776847;this.J=8192}g=$h.prototype;g.forEach=function(a){for(var b=E(this),c=null,d=0,e=0;;)if(ed?c.left:c.right}else return null}g.has=function(a){return He(this,a)};g.V=function(a,b){return this.I(null,b,null)}; +g.I=function(a,b,c){a=ai(this,b);return null!=a?a.H:c};g.Qc=function(a,b,c){return null!=this.mc?Jd(Vh(this.mc,b,c)):c};g.P=function(){return this.meta};g.W=function(){return this.F};g.Rc=function(){return 0(a.h?a.h(c):a.call(null,c))?b:c};Ai.A=function(a,b,c,d){return Mb(function(b,c){return Ai.l(a,b,c)},Ai.l(a,b,c),d)};Ai.N=function(a){var b=y(a),c=z(a);a=y(c);var d=z(c);c=y(d);d=z(d);return Ai.A(b,a,c,d)};Ai.L=3;function Bi(a,b){return new kf(null,function(){var c=E(b);if(c){var d=y(c);d=a.h?a.h(d):a.call(null,d);c=t(d)?ae(y(c),Bi(a,vd(c))):null}else c=null;return c},null,null)}function Di(a,b,c){this.i=a;this.end=b;this.step=c} +Di.prototype.ja=function(){return 0this.end};Di.prototype.next=function(){var a=this.i;this.i+=this.step;return a};function Ei(a,b,c,d,e){this.meta=a;this.start=b;this.end=c;this.step=d;this.w=e;this.m=32375006;this.J=139264}g=Ei.prototype;g.toString=function(){return fd(this)};g.equiv=function(a){return this.K(null,a)}; +g.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return Ud(this,a,0);case 2:return Ud(this,a,c)}throw Error("Invalid arity: "+(arguments.length-1));};a.h=function(a){return Ud(this,a,0)};a.c=function(a,c){return Ud(this,a,c)};return a}(); +g.lastIndexOf=function(){function a(a){return Xd(this,a,H(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Xd(this,b,d)}throw Error("Invalid arity: "+(arguments.length-1));};b.h=a;b.c=function(a,b){return Xd(this,a,b)};return b}();g.$=function(a,b){if(0<=b&&bthis.end&&0===this.step)return this.start;throw Error("Index out of bounds");}; +g.ka=function(a,b,c){return 0<=b&&bthis.end&&0===this.step?this.start:c};g.ba=function(){return new Di(this.start,this.end,this.step)};g.P=function(){return this.meta};g.Ka=function(){return 0this.end?new Ei(this.meta,this.start+this.step,this.end,this.step,null):null}; +g.W=function(){return wb(this.S(null))?0:Math.ceil((this.end-this.start)/this.step)};g.U=function(){var a=this.w;return null!=a?a:this.w=a=Ad(this)};g.K=function(a,b){return $d(this,b)};g.oa=function(){return tc(wd,this.meta)};g.Fa=function(a,b){return Kd(this,b)};g.Ga=function(a,b,c){for(a=this.start;;)if(0this.end){c=b.c?b.c(c,a):b.call(null,c,a);if(Hd(c))return B(c);a+=this.step}else return c};g.Ia=function(){return null==this.S(null)?null:this.start}; +g.bb=function(){return null!=this.S(null)?new Ei(this.meta,this.start+this.step,this.end,this.step,null):wd};g.S=function(){return 0this.step?this.start>this.end?this:null:this.start===this.end?null:this};g.T=function(a,b){return new Ei(b,this.start,this.end,this.step,this.w)};g.X=function(a,b){return ae(b,this)};Ei.prototype[Fb]=function(){return yd(this)};function Fi(a,b,c){return new Ei(null,a,b,c,null)} +function Gi(a,b){return new R(null,2,5,T,[Bi(a,b),ng(a,b)],null)} +function Hi(a){var b=y;return function(){function c(c,d,e){return new R(null,2,5,T,[b.l?b.l(c,d,e):b.call(null,c,d,e),a.l?a.l(c,d,e):a.call(null,c,d,e)],null)}function d(c,d){return new R(null,2,5,T,[b.c?b.c(c,d):b.call(null,c,d),a.c?a.c(c,d):a.call(null,c,d)],null)}function e(c){return new R(null,2,5,T,[b.h?b.h(c):b.call(null,c),a.h?a.h(c):a.call(null,c)],null)}function f(){return new R(null,2,5,T,[b.B?b.B():b.call(null),a.B?a.B():a.call(null)],null)}var h=null,k=function(){function c(a,b,c,e){var f= +null;if(3lb)return Jc(a,"#");Jc(a,c);if(0===tb.h(f))E(h)&&Jc(a,function(){var a=Ki.h(f);return t(a)?a:"..."}());else{if(E(h)){var l=y(h);b.l?b.l(l,a,f):b.call(null,l,a,f)}for(var p=z(h),m=tb.h(f)-1;;)if(!p||null!=m&&0===m){E(p)&&0===m&&(Jc(a,d),Jc(a,function(){var a=Ki.h(f);return t(a)?a:"..."}()));break}else{Jc(a,d);var u=y(p);c=a;h=f;b.l?b.l(u,c,h):b.call(null,u,c,h);var w=z(p);c=m-1;p=w;m=c}}return Jc(a,e)}finally{lb=k}} +function Li(a,b){for(var c=E(b),d=null,e=0,f=0;;)if(fH(a)?a.toUpperCase():[v.h(a.substring(0,1).toUpperCase()),v.h(a.substring(1))].join("")} +function Qo(a){if("string"===typeof a)return a;a=jf(a);var b=Fo(a,/-/),c=E(b);b=y(c);c=z(c);return t(Oo.h?Oo.h(b):Oo.call(null,b))?a:Kb(v,b,ig.c(Po,c))}function Ro(a){var b=function(){var b=function(){var b=me(a);return b?(b=a.displayName,t(b)?b:a.name):b}();if(t(b))return b;b=function(){var b=null!=a?a.J&4096||q===a.Oe?!0:!1:!1;return b?jf(a):b}();if(t(b))return b;b=qe(a);return xe(b)?Tk.h(b):null}();return Do(""+v.h(b),"$",".")}var So=!1;if("undefined"===typeof To)var To=0;function Uo(a){return setTimeout(a,16)}var Vo="undefined"===typeof window||null==window.document?Uo:function(){var a=window,b=a.requestAnimationFrame;if(t(b))return b;b=a.webkitRequestAnimationFrame;if(t(b))return b;b=a.mozRequestAnimationFrame;if(t(b))return b;a=a.msRequestAnimationFrame;return t(a)?a:Uo}();function Wo(a,b){return a.cljsMountOrder-b.cljsMountOrder}if("undefined"===typeof Xo)var Xo=function(){return null};function Yo(a){this.Yd=a} +function Zo(a,b){var c=a[b];if(null==c)return null;a[b]=null;for(var d=c.length,e=0;;)if(e=d&&a.push(gq(c));return a}}(e),[b,c],a))}};if("undefined"===typeof jq)var jq=null;function kq(){if(null!=jq)return jq;if("undefined"!==typeof ReactDOM)return jq=ReactDOM;if("undefined"!==typeof require){var a=jq=require("react-dom");if(t(a))return a;throw Error("require('react-dom') failed");}throw Error("js/ReactDOM is missing");}if("undefined"===typeof lq)var lq=dg.h(Ef); +function mq(a,b,c){var d=So;So=!0;try{return kq().render(a.B?a.B():a.call(null),b,function(){return function(){var d=So;So=!1;try{return gg.M(lq,K,b,new R(null,2,5,T,[a,b],null)),Zo(bp,"afterRender"),null!=c?c.B?c.B():c.call(null):null}finally{So=d}}}(d))}finally{So=d}}function nq(a,b){return mq(a,b,null)}function oq(a,b,c){qp();return mq(function(){return gq(me(a)?a.B?a.B():a.call(null):a)},b,c)}Wp=function(a){return kq().findDOMNode(a)};function pq(a){switch(arguments.length){case 2:return oq(arguments[0],arguments[1],null);case 3:return oq(arguments[0],arguments[1],arguments[2]);default:throw Error(["Invalid arity: ",v.h(arguments.length)].join(""));}}function qq(a,b){return oq(a,b,null)} +da("reagent.core.force_update_all",function(){qp();qp();for(var a=E(mh(B(lq))),b=null,c=0,d=0;;)if(d=Number(c)?a:a=-1Number(a)?"-":0<=b.indexOf("+")?"+":0<=b.indexOf(" ")?" ":"";0<=Number(a)&&(d=f+d);if(isNaN(c)||d.length>=Number(c))return d;d=isNaN(e)?Math.abs(Number(a)).toString():Math.abs(Number(a)).toFixed(e);a=Number(c)-d.length-f.length;0<=b.indexOf("-",0)?d=f+d+sa(" ",a):(b=0<=b.indexOf("0",0)?"0":" ",d=f+sa(b,a)+d);return d};yq.fc.d=function(a,b,c,d,e,f,h,k){return yq.fc.f(parseInt(a,10),b,c,d,0,f,h,k)}; +yq.fc.i=yq.fc.d;yq.fc.u=yq.fc.d;function zq(a){var b=be([Vk,null]);return wg.c(t(a)?a:Ef,function(){return function e(a){return new kf(null,function(){for(var b=a;;)if(b=E(b)){if(Ae(b)){var d=Wc(b),k=H(d),l=of(k);a:for(var p=0;;)if(p=H(h)&&Vf(function(){return function(a){return!(a instanceof Xq)}}(b,c,d,e,f,h),h)))throw Error(Bq("%s is not a valid sequence schema; %s%s%s",be([a,"a valid sequence schema consists of zero or more `one` elements, ","followed by zero or more `optional` elements, followed by an optional ", +"schema that will match the remaining elements."])));return new R(null,2,5,T,[O.c(c,f),y(h)],null)} +R.prototype.xb=function(){var a=this,b=Zq(a),c=J(b,0,null),d=J(b,1,null);return Wg(O.c(function(){return function(a,b,c,d){return function m(e){return new kf(null,function(){return function(){for(;;){var a=E(e);if(a){if(Ae(a)){var b=Wc(a),c=H(b),d=of(c);return function(){for(var a=0;;)if(ac?f:c;return $r(a,ea?0:a}():function(){var a=e-b;return f>a?f:a}())} +function gs(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a,d=D.c(c,pl);d=null!=d&&(d.m&64||q===d.G)?P(U,d):d;var e=D.c(d,Aj),f=D.c(c,Yj),h=D.c(c,no);return $r(c,e>f?function(){var a=h-1,c=e+b;return a=a}}(l,p,a,c,c,d,e,f,h,k),h),l,p);return Zr(c,d)} +function it(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a,d=D.c(c,pl),e=null!=d&&(d.m&64||q===d.G)?P(U,d):d,f=D.c(e,zn),h=D.c(c,tk),k=D.c(c,fl),l=b-1;d=J(cf(Bi(function(a,b,c,d,e,f,h){return function(a){return h>a}}(l,a,c,c,d,e,f,h,k),h)),l,0);return Zr(c,d)}function jt(a){return K.l(a,im,Ve)}function kt(a){return K.l(a,im,Hr)}function lt(a,b,c){return K.l(a,b,c)}function mt(a,b,c){return Wg(O.A(jg(b,a),new R(null,1,5,T,[c],null),be([jg(H(a)-b-1,kg(b,a))])))} +function nt(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a,d=D.c(c,pl),e=null!=d&&(d.m&64||q===d.G)?P(U,d):d;d=D.c(e,zn);e=D.c(e,Aj);var f=D.c(c,fl);D.c(c,no);var h=D.c(c,Oj),k=D.c(c,Rj),l=D.c(c,$l),p=D.c(c,im);p=95b?p.h?p.h(b):p.call(null,b):b;h=tr(p,h);return G.c(f,d+1)?t(k)?K.l(Yr(zg(c,new R(null,3,5,T,[il,e,d],null),h),d+1),vk,!0):zg(c,new R(null,3,5,T,[il,e,d],null),h):Yr(Ag.Z(c,new R(null,2,5,T,[il,e],null),t(l)?mt:lt,d,h),d+1)} +function ot(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a,d=D.c(c,Rj),e=D.c(c,vk);t(t(d)?e:d)&&(c=null!=c&&(c.m&64||q===c.G)?P(U,c):c,d=D.c(c,pl),d=null!=d&&(d.m&64||q===d.G)?P(U,d):d,d=D.c(d,Aj),e=D.c(c,no),c=Yr(c,0),c=G.c(e,d+1)?Tr.h(c):$r(c,d+1));return c=nt(c,b)}function pt(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var b=D.c(a,fl),c=D.c(a,no);return K.l(a,il,Wg(qg(c,Wg(qg(b,new R(null,2,5,T,[69,Ef],null))))))} +function qt(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var b=D.c(a,pl);b=null!=b&&(b.m&64||q===b.G)?P(U,b):b;b=D.c(b,Aj);var c=D.c(a,fl),d=D.c(a,Oj);return zg(a,new R(null,2,5,T,[il,b],null),gr.c(c,d))}function rt(a,b,c){return Wg(O.c(jg(b,a),qg(H(a)-b,vr(c))))}function st(a,b,c){return Wg(O.c(qg(b+1,vr(c)),kg(b+1,a)))} +function tt(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var b=D.c(a,pl),c=null!=b&&(b.m&64||q===b.G)?P(U,b):b;b=D.c(c,zn);c=D.c(c,Aj);var d=D.c(a,fl),e=D.c(a,Oj);--d;return Ag.Z(a,new R(null,2,5,T,[il,c],null),rt,b=k?Zr(c,k-1):c,m=Mb(D,p,new R(null,2,5,T,[pl,zn],null));return Ag.l(p,new R(null,2,5,T,[il,h],null),function(a,b,c,d,e,f,h,k,m,l,p,Q){return function(a){return Wg(O.A(jg(b,a),kg(b+c,a),be([qg(c,vr(Q))])))}}(p,m,function(){var a=k-m;return b=a}}(c,b)(b)}()))return Gu(a,b+64);throw Jt;}catch(h){if(h instanceof Error){var d=h;if(d===Jt)try{if(55===b)return Bg(a,V,ms);throw Jt;}catch(k){if(k instanceof Error){var e=k;if(e===Jt)try{if(56===b)return Bg(a,V,ns);throw Jt;}catch(l){if(l instanceof Error){var f=l;if(f===Jt)try{if(99===b)return du(a); +throw Jt;}catch(p){if(p instanceof Error){d=p;if(d===Jt)throw Jt;throw d;}throw p;}else throw f;}else throw l;}else throw e;}else throw k;}else throw d;}else throw h;}else throw Jt;}catch(h){if(h instanceof Error)if(d=h,d===Jt)try{if(35===c)try{if(56===b)return Bg(a,V,pt);throw Jt;}catch(k){if(k instanceof Error){e=k;if(e===Jt)throw Jt;throw e;}throw k;}else throw Jt;}catch(k){if(k instanceof Error)if(e=k,e===Jt)try{if(40===c)try{if(48===b)return Zt(a);throw Jt;}catch(l){if(l instanceof Error){f= +l;if(f===Jt)return $t(a);throw f;}throw l;}else throw Jt;}catch(l){if(l instanceof Error){f=l;if(f===Jt)return a;throw f;}throw l;}else throw e;else throw k;}else throw d;else throw h;}},function(a){return a},function(a){return a},Gu,function(a,b){return Cg(a,V,ot,b)},function(a,b){var c=function(){switch(b){case 64:return eu;case 65:return fu;case 66:return gu;case 67:return hu;case 68:return iu;case 69:return ju;case 70:return ku;case 71:return lu;case 72:return mu;case 73:return nu;case 74:return ou; +case 75:return pu;case 76:return su;case 77:return tu;case 80:return uu;case 83:return qu;case 84:return ru;case 87:return vu;case 88:return wu;case 90:return xu;case 96:return lu;case 97:return hu;case 100:return Du;case 101:return fu;case 102:return mu;case 103:return yu;case 104:return zu;case 108:return Au;case 109:return Cu;case 112:return Eu;case 114:return Fu;default:return null}}();return t(c)?c.h?c.h(a):c.call(null,a):a},function(a){return a},function(a,b){return K.l(a,kk,ge.c(kk.h(a),b))}, +function(a){return a},function(a,b){return K.l(a,rk,ge.c(rk.h(a),b))},function(a){return a},function(a){return a},function(a){return K.A(a,rk,he,be([kk,he]))}]);function Iu(a,b){for(var c=a,d=Tl.h(c),e=b;;){var f=y(e);if(t(f)){var h=160<=f?65:f;h=D.c(d.h?d.h(xq):d.call(null,xq),h);d=J(h,0,null);h=J(h,1,null);a:for(;;)if(E(h)){var k=y(h);k=Hu.h?Hu.h(k):Hu.call(null,k);c=k.c?k.c(c,f):k.call(null,c,f);h=z(h)}else break a;e=vd(e)}else return K.l(c,Tl,d)}} +function Ju(a,b){var c=xg(function(a){return a.codePointAt(0)},b);return Iu(a,c)} +function Ku(a,b){try{if(ze(b)&&3===H(b)){var c=Vd(b,0),d=Vd(b,1),e=Vd(b,2);return[v.h(a+8),";2;",v.h(c),";",v.h(d),";",v.h(e)].join("")}throw Jt;}catch(k){if(k instanceof Error){var f=k;if(f===Jt)try{if(t(function(){return function(){return function(a){return 8>a}}(f)(b)}()))return""+v.h(a+b);throw Jt;}catch(l){if(l instanceof Error){var h=l;if(h===Jt)try{if(t(function(){return function(){return function(a){return 16>a}}(h,f)(b)}()))return""+v.h(a+52+b);throw Jt;}catch(p){if(p instanceof Error){c= +p;if(c===Jt)return[v.h(a+8),";5;",v.h(b)].join("");throw c;}throw p;}else throw h;}else throw l;}else throw f;}else throw k;}}ag.c(Ku,30);ag.c(Ku,40);var Lu=function Lu(a){if(null!=a&&null!=a.yd)return a.yd(a);var c=Lu[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=Lu._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("Screen.lines",a);},Mu=function Mu(a){if(null!=a&&null!=a.xd)return a.xd(a);var c=Mu[n(null==a?null:a)];if(null!=c)return c.h?c.h(a):c.call(null,a);c=Mu._;if(null!=c)return c.h?c.h(a):c.call(null,a);throw Cb("Screen.cursor",a);};function Nu(a,b){var c=0parseFloat(Iv)){Hv=String(Kv);break a}}Hv=Iv}var gb={}; +function Lv(a){return fb(a,function(){for(var b=0,c=ra(String(Hv)).split("."),d=ra(String(a)).split("."),e=Math.max(c.length,d.length),f=0;0==b&&f=a.keyCode)a.keyCode=-1}catch(b){}};var Uv="closure_listenable_"+(1E6*Math.random()|0),Vv=0;function Wv(a,b,c,d,e){this.listener=a;this.Xd=null;this.src=b;this.type=c;this.capture=!!d;this.Ub=e;this.key=++Vv;this.$c=this.Fd=!1}function Xv(a){a.$c=!0;a.listener=null;a.Xd=null;a.src=null;a.Ub=null};function Yv(a){this.src=a;this.rb={};this.wd=0}Yv.prototype.add=function(a,b,c,d,e){var f=a.toString();a=this.rb[f];a||(a=this.rb[f]=[],this.wd++);var h=Zv(a,b,d,e);-1e.keyCode||void 0!=e.returnValue)){a:{var f=!1;if(0==e.keyCode)try{e.keyCode=-1;break a}catch(l){f=!0}if(f||void 0==e.returnValue)e.returnValue=!0}e=[];for(f=c.currentTarget;f;f=f.parentNode)e.push(f);f=a.type;for(var h=e.length-1;!c.Kc&&0<=h;h--){c.currentTarget=e[h];var k=nw(e[h],f,!0,c);d=d&&k}for(h=0;!c.Kc&& +h>>0);function fw(a){if(ha(a))return a;a[pw]||(a[pw]=function(b){return a.handleEvent(b)});return a[pw]};function qw(){wv.call(this);this.Ib=new Yv(this);this.ff=this;this.ve=null}qa(qw,wv);qw.prototype[Uv]=!0;g=qw.prototype;g.addEventListener=function(a,b,c,d){dw(this,a,b,c,d)};g.removeEventListener=function(a,b,c,d){lw(this,a,b,c,d)}; +g.dispatchEvent=function(a){var b,c=this.ve;if(c)for(b=[];c;c=c.ve)b.push(c);c=this.ff;var d=a.type||a;if(ca(a))a=new Sv(a,c);else if(a instanceof Sv)a.target=a.target||c;else{var e=a;a=new Sv(d,c);Ia(a,e)}e=!0;if(b)for(var f=b.length-1;!a.Kc&&0<=f;f--){var h=a.currentTarget=b[f];e=rw(h,d,!0,a)&&e}a.Kc||(h=a.currentTarget=c,e=rw(h,d,!0,a)&&e,a.Kc||(e=rw(h,d,!1,a)&&e));if(b)for(f=0;!a.Kc&&fthis.head?(Yw(this.o,this.fa,a,0,this.o.length-this.fa),Yw(this.o,0,a,this.o.length-this.fa,this.head),this.fa=0,this.head=this.length,this.o=a):this.fa===this.head?(this.head=this.fa=0,this.o=a):null};function ax(a,b){for(var c=a.length,d=0;;)if(da)){a+=1;continue}break}hx=!1;return 0c)return a;a:for(;;){var e=cMath.random()&&15>d)d+=1;else break a;if(d>this.level){for(var e=this.level+1;;)if(e<=d+1)c[e]=this.header,e+=1;else break;this.level=d}for(d=Ex(a,b,Array(d));;)return 0<=this.level?(c=c[0].forward,d.forward[0]=c[0],c[0]=d):null}; +Gx.prototype.remove=function(a){var b=Array(15),c=Fx(this.header,a,this.level,b);c=0===c.forward.length?null:c.forward[0];if(null!=c&&c.key===a){for(a=0;;)if(a<=this.level){var d=b[a].forward;c===(ad)return c===b.header?null:c;var e;a:for(e=c;;){e=d=a)break a}null!=e?(--d,c=e):--d}}Gx.prototype.S=function(){return function(a){return function d(c){return new kf(null,function(){return function(){return null==c?null:ae(new R(null,2,5,T,[c.key,c.H],null),d(c.forward[0]))}}(a),null,null)}}(this)(this.header.forward[0])}; +Gx.prototype.R=function(a,b,c){return Y(b,function(){return function(a){return Y(b,Qi,""," ","",c,a)}}(this),"{",", ","}",c,this)};var Ix=new Gx(Ex(null,null,0),0);function Jx(a){var b=(new Date).valueOf()+a,c=Hx(b),d=t(t(c)?c.keya:b)?a+8:a,[v.h(c),v.h(a)].join("")):null} +function Vy(a){var b=J(a,0,null),c=J(a,1,null);a=J(a,2,null);return["rgb(",v.h(b),",",v.h(c),",",v.h(a),")"].join("")} +var Wy=hj(function(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var b=D.c(a,Nk),c=D.c(a,pl);a=K.l(a,Nk,t(c)?wb(b):b);var d=null!=a&&(a.m&64||q===a.G)?P(U,a):a,e=D.c(d,Ok),f=D.c(d,Tn);b=D.c(d,Kj);var h=D.c(d,dk);c=D.c(d,Vl);var k=D.c(d,Nk),l=D.c(d,Yn);d=D.c(d,pl);var p=t(k)?t(e)?e:"fg":f;e=Uy(t(k)?t(f)?f:"bg":e,b,"fg-");h=Uy(p,h,"bg-");c=vg(ub,new R(null,6,5,T,[e,h,t(b)?"bright":null,t(l)?"italic":null,t(c)?"underline":null,t(d)?"cursor":null],null));if(E(c))a:for(b=new cb,c=E(c);;)if(null!=c)b.append(""+ +v.h(y(c))),c=z(c),null!=c&&b.append(" ");else{b=b.toString();break a}else b=null;l=null!=a&&(a.m&64||q===a.G)?P(U,a):a;a=D.c(l,Ok);c=D.c(l,Tn);h=D.c(l,Nk);l=t(h)?c:a;a=t(h)?a:c;a=hi.A(be([t(ze.h?ze.h(l):ze.call(null,l))?new r(null,1,[ik,Vy(l)],null):null,t(ze.h?ze.h(a):ze.call(null,a))?new r(null,1,[al,Vy(a)],null):null]));return hi.A(be([t(b)?new r(null,1,[vn,b],null):null,t(a)?new r(null,1,[fm,a],null):null]))}); +function Xy(a,b){var c=J(a,0,null),d=J(a,1,null);d=Bg(d,pl,function(){return function(a){return t(a)?B(b):a}}(a,c,d));return new R(null,3,5,T,[ro,Wy.h?Wy.h(d):Wy.call(null,d),c],null)}function Yy(a,b){var c=J(a,0,null),d=J(a,1,null),e=jg(b,c);e=E(e)?new R(null,2,5,T,[Eo(e),d],null):null;var f=K.l(d,pl,!0);f=new R(null,2,5,T,[Vd(c,b),f],null);c=kg(b+1,c);d=E(c)?new R(null,2,5,T,[Eo(c),d],null):null;return vg(ub,new R(null,3,5,T,[e,f,d],null))} +function Zy(a,b){for(var c=he,d=a,e=b;;)if(E(d)){var f=y(d),h=J(f,0,null);J(f,1,null);h=H(h);if(h<=e)c=ge.c(c,f),d=vd(d),e-=h;else return O.A(c,Yy(f,e),be([vd(d)]))}else return c}function $y(a,b,c){a=t(B(b))?Zy(B(a),B(b)):B(a);return new R(null,2,5,T,[Lm,Ii(bg(function(){return function(a,b){return pe(new R(null,3,5,T,[Xy,b,c],null),new r(null,1,[mk,a],null))}}(a),a))],null)}var qA=new ti(null,new r(null,3,["small",null,"medium",null,"big",null],null),null); +function rA(a,b,c,d,e){var f=yp(function(){var a=B(c);return t(qA.h?qA.h(a):qA.call(null,a))?["font-",v.h(a)].join(""):null}),h=yp(function(){return function(){var d=B(a),e=B(b),f=B(c);f=t(qA.h?qA.h(f):qA.call(null,f))?null:new r(null,1,[wk,f],null);return hi.A(be([new r(null,2,[fl,[v.h(d),"ch"].join(""),no,[v.h(1.3333333333*e),"em"].join("")],null),f]))}}(f)),k=yp(function(){return function(){return Lu(B(d))}}(f,h)),l=yp(function(a,c,d){return function(){return xg(function(a,b,c){return function(d){return yp(function(a, +b,c){return function(){return D.c(B(c),d)}}(a,b,c))}}(a,c,d),Fi(0,B(b),1))}}(f,h,k)),p=yp(function(){return function(){return Mu(B(d))}}(f,h,k,l)),m=yp(function(a,b,c,d,e){return function(){return zn.h(B(e))}}(f,h,k,l,p)),u=yp(function(a,b,c,d,e){return function(){return Aj.h(B(e))}}(f,h,k,l,p,m)),w=yp(function(a,b,c,d,e){return function(){return On.h(B(e))}}(f,h,k,l,p,m,u));return function(a,b,c,d,f,h,k,l){return function(){return new R(null,3,5,T,[Gm,new r(null,2,[vn,B(a),fm,B(b)],null),bg(function(a, +b,c,d,f,h,k,l){return function(m,p){var u=yp(function(a,b,c,d,e,f,h,k){return function(){var a=B(k);return t(a)?(a=G.c(m,B(h)))?B(f):a:a}}(a,b,c,d,f,h,k,l));return pe(new R(null,4,5,T,[$y,p,u,e],null),new r(null,1,[mk,m],null))}}(a,b,c,d,f,h,k,l),B(d))],null)}}(f,h,k,l,p,m,u,w)} +function sA(){return new R(null,2,5,T,[Ym,new r(null,4,[Mn,"1.1",Fl,"0 0 866.0254037844387 866.0254037844387",vn,"icon",mo,new r(null,1,[An,'\x3cdefs\x3e \x3cmask id\x3d"small-triangle-mask"\x3e \x3crect width\x3d"100%" height\x3d"100%" fill\x3d"white"/\x3e \x3cpolygon points\x3d"508.01270189221935 433.01270189221935, 208.0127018922194 259.8076211353316, 208.01270189221927 606.217782649107" fill\x3d"black"\x3e\x3c/polygon\x3e \x3c/mask\x3e \x3c/defs\x3e \x3cpolygon points\x3d"808.0127018922194 433.01270189221935, 58.01270189221947 -1.1368683772161603e-13, 58.01270189221913 866.0254037844386" mask\x3d"url(#small-triangle-mask)" fill\x3d"white"\x3e\x3c/polygon\x3e \x3cpolyline points\x3d"481.2177826491071 333.0127018922194, 134.80762113533166 533.0127018922194" stroke\x3d"white" stroke-width\x3d"90"\x3e\x3c/polyline\x3e'],null)], +null)],null)}function tA(){return new R(null,3,5,T,[Ym,new r(null,3,[Mn,"1.1",Fl,"0 0 12 12",vn,"icon"],null),new R(null,2,5,T,[Fj,new r(null,1,[pn,"M1,0 L11,6 L1,12 Z"],null)],null)],null)}function uA(){return new R(null,4,5,T,[Ym,new r(null,3,[Mn,"1.1",Fl,"0 0 12 12",vn,"icon"],null),new R(null,2,5,T,[Fj,new r(null,1,[pn,"M1,0 L4,0 L4,12 L1,12 Z"],null)],null),new R(null,2,5,T,[Fj,new r(null,1,[pn,"M8,0 L11,0 L11,12 L8,12 Z"],null)],null)],null)} +function vA(){return new R(null,4,5,T,[Ym,new r(null,3,[Mn,"1.1",Fl,"0 0 12 12",vn,"icon"],null),new R(null,2,5,T,[Fj,new r(null,1,[pn,"M12,0 L7,0 L9,2 L7,4 L8,5 L10,3 L12,5 Z"],null)],null),new R(null,2,5,T,[Fj,new r(null,1,[pn,"M0,12 L0,7 L2,9 L4,7 L5,8 L3,10 L5,12 Z"],null)],null)],null)} +function wA(){return new R(null,4,5,T,[Ym,new r(null,3,[Mn,"1.1",Fl,"0 0 12 12",vn,"icon"],null),new R(null,2,5,T,[Fj,new r(null,1,[pn,"M7,5 L7,0 L9,2 L11,0 L12,1 L10,3 L12,5 Z"],null)],null),new R(null,2,5,T,[Fj,new r(null,1,[pn,"M5,7 L0,7 L2,9 L0,11 L1,12 L3,10 L5,12 Z"],null)],null)],null)}function xA(a,b){return function(b){return function(){return new R(null,3,5,T,[cl,new r(null,1,[Sl,b],null),new R(null,1,5,T,[t(B(a))?uA:tA],null)],null)}}(Ty(b,new fy(null,null,null)))} +function yA(a){return 10>a?["0",v.h(a)].join(""):a}function zA(a){var b=Math.floor((a%60+60)%60);return[v.h(yA(Math.floor(a/60))),":",v.h(yA(b))].join("")}function AA(a,b){var c=T,d=new R(null,2,5,T,[Yk,zA(B(a))],null),e=T;var f=B(a);var h=B(b);f=["-",v.h(zA(h-f))].join("");return new R(null,3,5,c,[Ml,d,new R(null,2,5,e,[co,f],null)],null)} +function BA(){function a(a){a.preventDefault();return Ry(a.currentTarget.parentNode.parentNode.parentNode)}return function(){return new R(null,4,5,T,[un,new r(null,1,[Sl,a],null),new R(null,1,5,T,[vA],null),new R(null,1,5,T,[wA],null)],null)}} +function CA(a,b){var c=Sy(b,function(a){var b=a.currentTarget.offsetWidth,c=a.currentTarget.getBoundingClientRect();return cy(Nu(a.clientX-c.left,b)/b)}),d=yp(function(){return function(){return[v.h(100*B(a)),"%"].join("")}}(c));return function(a,b){return function(){return new R(null,2,5,T,[Vj,new R(null,3,5,T,[Bl,new r(null,1,[Ql,a],null),new R(null,2,5,T,[Cj,new R(null,2,5,T,[ro,new r(null,1,[fm,new r(null,1,[fl,B(b)],null)],null)],null)],null)],null)],null)}}(c,d)} +function DA(a,b,c,d){return function(e){return function(){return new R(null,5,5,T,[Kk,new R(null,3,5,T,[xA,a,d],null),new R(null,3,5,T,[AA,b,c],null),new R(null,1,5,T,[BA],null),new R(null,3,5,T,[CA,e,d],null)],null)}}(yp(function(){return B(b)/B(c)}))} +function EA(a){return function(a){return function(){return new R(null,3,5,T,[ol,new r(null,1,[Sl,a],null),new R(null,2,5,T,[Xk,new R(null,2,5,T,[km,new R(null,2,5,T,[ro,new R(null,1,5,T,[sA],null)],null)],null)],null)],null)}}(Ty(a,new fy(null,null,null)))}function FA(){return new R(null,2,5,T,[Ek,new R(null,1,5,T,[xn],null)],null)}function GA(a){return Wf(function(b){return a[b]},new R(null,4,5,T,["altKey","shiftKey","metaKey","ctrlKey"],null))} +function HA(a){var b=t(GA(a))?null:function(){switch(a.key){case " ":return new fy(null,null,null);case "f":return bm;case "0":return cy(0);case "1":return cy(.1);case "2":return cy(.2);case "3":return cy(.3);case "4":return cy(.4);case "5":return cy(.5);case "6":return cy(.6);case "7":return cy(.7);case "8":return cy(.8);case "9":return cy(.9);default:return null}}();if(t(b))return b;switch(a.key){case "\x3e":return new ey(null,null,null);case "\x3c":return new dy(null,null,null);default:return null}} +function IA(a){if(t(GA(a)))return null;switch(a.which){case 37:return new ay(null,null,null);case 39:return new $x(null,null,null);default:return null}}function JA(a){var b=HA(a);return t(b)?(a.preventDefault(),G.c(b,bm)?(Ry(a.currentTarget),null):b):null}function KA(a){var b=IA(a);return t(b)?(a.preventDefault(),b):null} +function LA(a,b,c,d){a=t(a)?['"',v.h(a),'"'].join(""):"untitled";return new R(null,4,5,T,[dl,t(d)?new R(null,2,5,T,[jo,new r(null,1,[zl,d],null)],null):null,a,t(b)?new R(null,3,5,T,[ro," by ",t(c)?new R(null,3,5,T,[lo,new r(null,1,[ho,c],null),b],null):b],null):null],null)} +function MA(a){var b=Mx(1,ig.h(iy)),c=Kx(1);lx(function(c){return function(){var d=function(){return function(a){return function(){function b(b){for(;;){a:try{for(;;){var c=a(b);if(!N(c,Z)){var d=c;break a}}}catch(x){if(x instanceof Object)b[5]=x,Cx(b),d=Z;else throw x;}if(!N(d,Z))return d}}function c(){var a=[null,null,null,null,null,null,null,null,null,null,null,null];a[0]=d;a[1]=1;return a}var d=null;d=function(a){switch(arguments.length){case 0:return c.call(this);case 1:return b.call(this,a)}throw Error("Invalid arity: "+ +(arguments.length-1));};d.B=c;d.h=b;return d}()}(function(){return function(c){var d=c[1];if(7===d)return c[7]=c[2],Ax(c,12,b,!1);if(1===d)return c[2]=null,c[1]=2,Z;if(4===d)return c[8]=c[2],Ax(c,5,b,!0);if(6===d)return d=Jx(3E3),Ux(c,8,new R(null,2,5,T,[a,d],null));if(3===d)return Bx(c,c[2]);if(12===d)return c[9]=c[2],c[2]=null,c[1]=2,Z;if(2===d)return zx(c,4,a);if(11===d)return c[2]=c[2],c[1]=7,Z;if(9===d)return c[2]=null,c[1]=6,Z;if(5===d)return c[10]=c[2],c[2]=null,c[1]=6,Z;if(10===d)return c[2]= +null,c[1]=11,Z;if(8===d){var e=c[2];d=J(e,0,null);e=J(e,1,null);e=G.c(e,a);c[11]=d;c[1]=e?9:10;return Z}return null}}(c),c)}(),f=function(){var a=d.B?d.B():d.call(null);a[6]=c;return a}();return yx(f)}}(c));return b} +function NA(a,b){var c=dg.h(b),d=Kx(1);lx(function(b,c){return function(){var d=function(){return function(a){return function(){function b(b){for(;;){a:try{for(;;){var c=a(b);if(!N(c,Z)){var d=c;break a}}}catch(F){if(F instanceof Object)b[5]=F,Cx(b),d=Z;else throw F;}if(!N(d,Z))return d}}function c(){var a=[null,null,null,null,null,null,null,null,null,null,null,null,null];a[0]=d;a[1]=1;return a}var d=null;d=function(a){switch(arguments.length){case 0:return c.call(this);case 1:return b.call(this, +a)}throw Error("Invalid arity: "+(arguments.length-1));};d.B=c;d.h=b;return d}()}(function(b,c){return function(d){var e=d[1];if(7===e){var f=d[7],h=wb(null==f);d[8]=d[2];d[1]=h?8:9;return Z}if(20===e)return f=d[7],d[1]=t(q===f.Fe)?23:24,Z;if(27===e)return d[2]=!1,d[1]=28,Z;if(1===e)return d[2]=null,d[1]=2,Z;if(24===e)return f=d[7],d[1]=t(!f.Tc)?26:27,Z;if(4===e){f=d[7];var k=d[9];h=d[2];var l=J(h,0,null),m=J(h,1,null);d[10]=m;d[7]=l;d[9]=h;d[1]=t(null==l)?5:6;return Z}return 15===e?(d[2]=!1,d[1]= +16,Z):21===e?(f=d[7],h=Ab(Yx,f),d[2]=h,d[1]=22,Z):31===e?(d[11]=d[2],d[2]=null,d[1]=2,Z):13===e?(d[2]=d[2],d[1]=10,Z):22===e?(d[1]=t(d[2])?29:30,Z):29===e?(f=d[7],h=B(a),h=Zx(f,h),h=gg.l(c,wo,h),d[2]=h,d[1]=31,Z):6===e?(d[2]=null,d[1]=7,Z):28===e?(d[2]=d[2],d[1]=25,Z):25===e?(d[2]=d[2],d[1]=22,Z):17===e?(m=d[10],f=d[7],k=d[9],h=gg.c(a,function(){return function(a,b){return function(a){return Xx(b,a)}}(k,f,m,m,f,k,e,b,c)}()),d[2]=h,d[1]=19,Z):3===e?Bx(d,d[2]):12===e?(f=d[7],d[1]=t(!f.Tc)?14:15,Z): +2===e?(h=B(c),h=E(h),Ux(d,4,h)):23===e?(d[2]=!0,d[1]=25,Z):19===e?(f=d[7],h=wb(null==f),d[12]=d[2],d[1]=h?20:21,Z):11===e?(d[2]=!0,d[1]=13,Z):9===e?(f=d[7],h=Ab(Wx,f),d[2]=h,d[1]=10,Z):5===e?(m=d[10],h=gg.l(c,re,m),d[2]=h,d[1]=7,Z):14===e?(f=d[7],h=Ab(Wx,f),d[2]=h,d[1]=16,Z):26===e?(f=d[7],h=Ab(Yx,f),d[2]=h,d[1]=28,Z):16===e?(d[2]=d[2],d[1]=13,Z):30===e?(d[2]=null,d[1]=31,Z):10===e?(d[1]=t(d[2])?17:18,Z):18===e?(d[2]=null,d[1]=19,Z):8===e?(f=d[7],d[1]=t(q===f.sb)?11:12,Z):null}}(b,c),b,c)}(),e=function(){var a= +d.B?d.B():d.call(null);a[6]=b;return a}();return yx(e)}}(d,c));return d} +function OA(a,b,c){c=Ty(c,!0);var d=Sy(b,JA),e=Sy(b,KA),f=yp(function(){return function(){return Hm.h(B(a))}}(c,d,e)),h=yp(function(){return function(){return el.h(B(a))}}(c,d,e,f)),k=yp(function(a,b,c,d,e){return function(){var a=B(d);return t(a)?a:B(e)}}(c,d,e,f,h)),l=yp(function(b,c,d,e,f,h){return function(){var b=Gk.h(B(a));b=t(b)?b:wb(B(h));return t(b)?"hud":null}}(c,d,e,f,h,k)),p=yp(function(){return function(){return["asciinema-theme-",v.h(gm.h(B(a)))].join("")}}(c,d,e,f,h,k,l)),m=yp(function(){return function(){var b= +fl.h(B(a));return t(b)?b:80}}(c,d,e,f,h,k,l,p)),u=yp(function(){return function(){var b=no.h(B(a));return t(b)?b:24}}(c,d,e,f,h,k,l,p,m)),w=yp(function(){return function(){return wk.h(B(a))}}(c,d,e,f,h,k,l,p,m,u)),x=yp(function(){return function(){return V.h(B(a))}}(c,d,e,f,h,k,l,p,m,u,w)),C=yp(function(){return function(){return ml.h(B(a))}}(c,d,e,f,h,k,l,p,m,u,w,x)),F=yp(function(){return function(){return jn.h(B(a))}}(c,d,e,f,h,k,l,p,m,u,w,x,C)),I=yp(function(){return function(){return Uj.h(B(a))}}(c, +d,e,f,h,k,l,p,m,u,w,x,C,F)),M=yp(function(){return function(){return wl.h(B(a))}}(c,d,e,f,h,k,l,p,m,u,w,x,C,F,I)),S=B(a),X=null!=S&&(S.m&64||q===S.G)?P(U,S):S,Ga=D.c(X,ki),db=D.c(X,li),Q=D.c(X,mi),xb=D.c(X,ni);return function(a,c,d,e,f,h,k,l,m,p,u,w,x,C,F,I,M,S,Q,X,Ga,db){return function(){return new R(null,3,5,T,[Cn,new r(null,5,[Jj,-1,Zj,c,Rn,d,Vm,a,vn,B(k)],null),new R(null,7,5,T,[Sm,new r(null,1,[vn,B(l)],null),new R(null,6,5,T,[rA,m,p,u,w,x],null),new R(null,5,5,T,[DA,C,F,I,b],null),t(t(Q)?Q: +X)?new R(null,5,5,T,[LA,Q,X,Ga,db],null):null,t(B(h))?null:new R(null,2,5,T,[EA,b],null),t(B(e))?new R(null,1,5,T,[FA],null):null],null)],null)}}(c,d,e,f,h,k,l,p,m,u,w,x,C,F,I,M,S,X,Ga,db,Q,xb)} +function PA(a){var b=Kx(null),c=Kx(new dx(bx(1),1));return function(b,c){return function(){return Pp(new r(null,4,[ln,"asciinema-player",Dm,function(b,c){return function(){return OA(a,b,c)}}(b,c),$k,function(b,c){return function(){var d=ty(Gl.h(B(a))),e=MA(c);Tx(e,b);return NA(a,Je([b,d]))}}(b,c),Wm,function(){return function(){return uy(Gl.h(B(a)))}}(b,c)],null))}}(b,c)};function QA(a,b){var c=null!=b&&(b.m&64||q===b.G)?P(U,b):b,d=D.c(c,Ak),e=D.c(c,Gl);d=a.h?a.h(d):a.call(null,d);zy(e,d);return K.l(c,Ak,d)}$x.prototype.sb=q;$x.prototype.qb=function(a,b){var c=null!=b&&(b.m&64||q===b.G)?P(U,b):b,d=D.c(c,Uj),e=D.c(c,wl),f=D.c(c,Gl);t(e)&&yy(f,Nu(d+5,e));return c};ay.prototype.sb=q;ay.prototype.qb=function(a,b){var c=null!=b&&(b.m&64||q===b.G)?P(U,b):b,d=D.c(c,Uj),e=D.c(c,wl),f=D.c(c,Gl);t(e)&&yy(f,Nu(d+-5,e));return c};by.prototype.sb=q; +by.prototype.qb=function(a,b){var c=null!=b&&(b.m&64||q===b.G)?P(U,b):b,d=D.c(c,wl),e=D.c(c,Gl);t(d)&&(d*=nn.h(this),yy(e,d));return c};dy.prototype.sb=q;dy.prototype.qb=function(a,b){return QA(function(){return function(a){return a/2}}(this),b)};ey.prototype.sb=q;ey.prototype.qb=function(a,b){return QA(function(){return function(a){return 2*a}}(this),b)};fy.prototype.sb=q;fy.prototype.qb=function(a,b){xy(Gl.h(b));return b};gy.prototype.sb=q;gy.prototype.qb=function(a,b){return K.l(b,ml,so.h(this))}; +hy.prototype.sb=q;hy.prototype.qb=function(a,b){return K.l(b,Gk,so.h(this))};jy.prototype.sb=q;jy.prototype.qb=function(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a;D.c(c,fl);D.c(c,no);D.c(c,wl);c=null!=b&&(b.m&64||q===b.G)?P(U,b):b;var d=D.c(c,fl),e=D.c(c,no),f=null!=this&&(this.m&64||q===this.G)?P(U,this):this,h=D.c(f,fl),k=D.c(f,no);f=D.c(f,wl);return K.A(c,fl,t(d)?d:h,be([no,t(e)?e:k,wl,f]))};ky.prototype.sb=q;ky.prototype.qb=function(a,b){return K.l(b,Hm,Hm.h(this))};oy.prototype.sb=q; +oy.prototype.qb=function(a,b){var c=null!=b&&(b.m&64||q===b.G)?P(U,b):b,d=D.c(c,oi);t(d)&&(ap(bp),d.B?d.B():d.call(null));return c};ry.prototype.sb=q;ry.prototype.qb=function(a,b){return K.l(b,Uj,Zk.h(this))};function RA(){return ig.l(function(a,b){return new R(null,2,5,T,[a,new gy(b,null,null,null)],null)},rg(function(a){return a+.5},.5),og(new R(null,2,5,T,[!1,!0],null)))}function SA(a){var b=Dy(RA());return K.l(K.l(a,ml,!0),Ol,b)} +function TA(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;var b=D.c(a,Ol);Tw(b);return K.l(K.l(a,ml,!0),Ol,null)}function UA(a){a=null!=a&&(a.m&64||q===a.G)?P(U,a):a;a=D.c(a,Ol);return t(a)?Je([a]):vi}my.prototype.sb=q; +my.prototype.qb=function(a,b){var c=null!=a&&(a.m&64||q===a.G)?P(U,a):a;D.c(c,jn);var d=null!=b&&(b.m&64||q===b.G)?P(U,b):b,e=D.c(d,jn);c=D.c(d,pi);var f=D.c(d,qi),h=null!=this&&(this.m&64||q===this.G)?P(U,this):this;h=D.c(h,jn);if(G.c(e,h))return d;d=K.A(d,jn,h,be([el,!0]));if(t(h))return t(c)&&(c.B?c.B():c.call(null)),SA(d);t(f)&&(f.B?f.B():f.call(null));return TA(d)};my.prototype.Fe=q;my.prototype.de=function(a,b){return UA(b)};py.prototype.sb=q; +py.prototype.qb=function(a,b){var c=K.l(b,V,V.h(this));c=null!=c&&(c.m&64||q===c.G)?P(U,c):c;var d=D.c(c,Ol);return t(d)?SA(TA(c)):c};py.prototype.Fe=q;py.prototype.de=function(a,b){return UA(b)};function VA(a){return t(a)?(a=ig.c(parseFloat,Fo(""+v.h(a),/:/)),a=ig.l(Ye,cf(a),rg(function(){return function(a){return 60*a}}(a),1)),P(Xe,a)):null} +function WA(a,b,c){t(a)?"string"===typeof a?t(0===a.indexOf("data:application/json;base64,"))?(b=a.substring(29).replace(RegExp("\\s","g"),""),b=JSON.parse(atob(b)),b=fj(b),b=new r(null,1,[V,new r(null,1,[il,b],null)],null)):t(0===a.indexOf("data:text/plain,"))?(a=a.substring(16),b=Ju(Ot(t(b)?b:80,t(c)?c:24),a),b=new r(null,1,[V,b],null)):b=t(0===a.indexOf("npt:"))?new r(null,1,[Zk,VA(a.substring(4))],null):null:b=new r(null,1,[V,new r(null,1,[il,a],null)],null):b=null;return b} +var XA=new r(null,2,[pl,new r(null,1,[On,!1],null),il,he],null); +function YA(a,b){var c=null!=b&&(b.m&64||q===b.G)?P(U,b):b,d=D.c(c,no),e=D.l(c,wk,"small"),f=D.l(c,Ak,1),h=D.c(c,Hk),k=D.c(c,fl),l=D.c(c,rl),p=D.l(c,cm,!1),m=D.l(c,gm,"asciinema"),u=D.c(c,qm),w=D.c(c,Bm),x=D.l(c,vm,!1),C=D.l(c,Em,!1),F=function(){var a=VA(h);return t(a)?a:0}();w=WA(w,k,d);var I=null!=w&&(w.m&64||q===w.G)?P(U,w):w;w=D.c(I,V);I=D.c(I,Zk);var M=t(I)?I:wb(w)&&0c\u001b[2;1H\u001b[1m\u001b[34m~ \u001b[3;1H~ \u001b[4;1H~ \u001b[5;1H~ \u001b[6;1H~ \u001b[7;1H~ \u001b[8;1H~ \u001b[9;1H~ \u001b[10;1H~ \u001b[11;1H~ \u001b[12;1H~ "] +[6.258626, "o", " \u001b[13;1H~ \u001b[14;1H~ \u001b[15;1H~ \u001b[16;1H~ \u001b[17;1H~ \u001b[18;1H~ \u001b[19;1H~ \u001b[20;1H~ \u001b[21;1H~ \u001b[22;1H~ \u001b[23;1H~ \u001b[m\u001b[24;63"] +[6.259626, "o", "H0,0-1\u001b[9CAll\u001b[1;1H\u001b[?12l\u001b[?25h"] +[7.087709, "o", "\u001b[?25l\u001b[24;1H\u001b[1m-- INSERT --\u001b[m\u001b[24;13H\u001b[K\u001b[24;63H0,1\u001b[11CAll\u001b[1;1H\u001b[?12l\u001b[?25h"] +[7.288729, "o", "\u001b[?25l1\u001b[24;63H1,2\u001b[1;2H\u001b[?12l\u001b[?25h"] +[7.463746, "o", "\u001b[?25l2\u001b[24;65H3\u001b[1;3H\u001b[?12l\u001b[?25h"] +[7.49575, "o", "\u001b[?25l1\u001b[24;65H4\u001b[1;4H\u001b[?12l\u001b[?25h"] +[7.719772, "o", "\u001b[?25l2\u001b[24;65H5\u001b[1;5H\u001b[?12l\u001b[?25h"] +[7.744774, "o", "\u001b[?25l\u001b[2;1H\u001b[K\u001b[24;63H2,1\u001b[2;1H\u001b[?12l\u001b[?25h"] +[7.959796, "o", "\u001b[?25l\u001b[3;1H\u001b[K\u001b[24;63H3\u001b[3;1H\u001b[?12l\u001b[?25h"] +[8.10381, "o", "\u001b[?25l1\u001b[24;65H2\u001b[3;2H\u001b[?12l\u001b[?25h"] +[8.255826, "o", "\u001b[?25l3\u001b[24;65H3\u001b[3;3H\u001b[?12l\u001b[?25h"] +[8.383838, "o", "\u001b[?25l1\u001b[24;65H4\u001b[3;4H\u001b[?12l\u001b[?25h"] +[8.447845, "o", "\u001b[?25l\u001b[4;1H\u001b[K\u001b[24;63H4,1\u001b[4;1H\u001b[?12l\u001b[?25h"] +[8.623862, "o", "\u001b[?25l\u001b[5;1H\u001b[K\u001b[24;63H5\u001b[5;1H\u001b[?12l\u001b[?25h"] +[8.783879, "o", "\u001b[?25l\u001b[6;1H\u001b[K\u001b[24;63H6\u001b[6;1H\u001b[?12l\u001b[?25h"] +[8.9999, "o", "\u001b[?25l\u001b[7;1H\u001b[K\u001b[24;63H7\u001b[7;1H\u001b[?12l\u001b[?25h"] +[9.223922, "o", "\u001b[?25l2\u001b[24;65H2\u001b[7;2H\u001b[?12l\u001b[?25h"] +[9.247925, "o", "\u001b[?25l1\u001b[24;65H3\u001b[7;3H\u001b[?12l\u001b[?25h"] +[9.344934, "o", "\u001b[?25l3\u001b[24;65H4\u001b[7;4H\u001b[?12l\u001b[?25h"] +[9.439944, "o", "\u001b[?25l1\u001b[24;65H5\u001b[7;5H\u001b[?12l\u001b[?25h"] +[9.455945, "o", "\u001b[?25l2\u001b[24;65H6\u001b[7;6H\u001b[?12l\u001b[?25h"] +[9.543954, "o", "\u001b[?25l3\u001b[24;65H7\u001b[7;7H\u001b[?12l\u001b[?25h"] +[9.639964, "o", "\u001b[?25l\u001b[24;63H6,1\u001b[6;1H\u001b[?12l\u001b[?25h"] +[10.156016, "o", "\u001b[?25l\u001b[24;63H5\u001b[5;1H\u001b[?12l\u001b[?25h"] +[10.188019, "o", "\u001b[?25l\u001b[24;63H4\u001b[4;1H\u001b[?12l\u001b[?25h"] +[10.222022, "o", "\u001b[?25l\u001b[24;63H3,4\u001b[3;4H\u001b[?12l\u001b[?25h"] +[10.255025, "o", "\u001b[?25l\u001b[24;63H2,1\u001b[2;1H\u001b[?12l\u001b[?25h"] +[10.288029, "o", "\u001b[?25l\u001b[24;63H1,5\u001b[1;5H\u001b[?12l\u001b[?25h"] +[10.321032, "o", "\u0007"] +[10.353035, "o", "\u0007"] +[10.387039, "o", "\u0007"] +[10.419042, "o", "\u0007"] +[10.452045, "o", "\u0007"] +[10.485049, "o", "\u0007"] +[10.518052, "o", "\u0007"] +[10.551055, "o", "\u0007"] +[10.584059, "o", "\u0007"] +[10.626063, "o", "\u0007"] +[10.650065, "o", "\u0007"] +[10.683068, "o", "\u0007"] +[10.716072, "o", "\u0007"] +[10.912091, "o", "\u001b[?25lw\u001b[24;65H6\u001b[1;6H\u001b[?12l\u001b[?25h"] +[10.929093, "o", "\u001b[?25le\u001b[24;65H7\u001b[1;7H\u001b[?12l\u001b[?25h"] +[11.025103, "o", "\u001b[?25lq\u001b[24;65H8\u001b[1;8H\u001b[?12l\u001b[?25h"] +[11.640164, "o", "\u001b[?25l\u001b[24;65H7\u001b[1;7H\u001b[?12l\u001b[?25h"] +[12.140214, "o", "\u001b[?25l\u001b[24;65H6\u001b[1;6H\u001b[?12l\u001b[?25h"] +[12.173217, "o", "\u001b[?25l\u001b[24;65H5\u001b[1;5H\u001b[?12l\u001b[?25h"] +[12.206221, "o", "\u001b[?25l\u001b[24;65H4\u001b[1;4H\u001b[?12l\u001b[?25h"] +[12.239224, "o", "\u001b[?25l\u001b[24;65H3\u001b[1;3H\u001b[?12l\u001b[?25h"] +[12.272227, "o", "\u001b[?25l\u001b[24;65H2\u001b[1;2H\u001b[?12l\u001b[?25h"] +[12.30423, "o", "\u001b[?25l\u001b[24;65H1\u001b[1;1H\u001b[?12l\u001b[?25h"] +[12.338234, "o", "\u0007"] +[12.371237, "o", "\u0007"] +[12.40324, "o", "\u0007"] +[12.436244, "o", "\u0007"] +[12.560256, "o", "\u001b[?25l\u001b[2;23r\u001b[2;1H\u001b[L\u001b[1;24r\u001b[1;1H\u001b[K\u001b[2;1H1212weq\u001b[24;63H\u001b[K\u001b[24;63H2,1\u001b[11CAll\u001b[2;1H\u001b[?12l\u001b[?25h"] +[12.712271, "o", "\u001b[?25l\u001b[3;23r\u001b[3;1H\u001b[L\u001b[1;24r\u001b[2;1H\u001b[K\u001b[3;1H1212weq\u001b[24;63H\u001b[K\u001b[24;63H3,1\u001b[11CAll\u001b[3;1H\u001b[?12l\u001b[?25h"] +[12.866287, "o", "\u001b[24;1H\u001b[K\u001b[3;1H"] +[13.440344, "o", "\u001b[?25l\u001b[24;63H3,1\u001b[11CAll\u001b[3;1H\u001b[?12l\u001b[?25h\u001b[?25l\u001b[24;63H\u001b[K\u001b[24;1H:\u001b[?12l\u001b[?25h"] +[13.528353, "o", "w\u001b[?25l\u001b[?12l\u001b[?25h"] +[13.632363, "o", "q\u001b[?25l\u001b[?12l\u001b[?25h"] +[13.752375, "o", "\r\u001b[?25l\"test.txt\""] +[13.766377, "o", " [New] 9L, 25C written\r\r\r\n\u001b[?1l\u001b>\u001b[?12l\u001b[?25h\u001b[?1049l\u001b]0;root@k8s1:~\u0007[root@k8s1 ~]# "] +[13.952395, "o", "l"] +[14.088409, "o", "l"] +[14.170417, "o", "\r\ntotal 19688\r\ndrwxr-xr-x 11 root root 317 Aug 26 10:30 \u001b[0m\u001b[01;34mcmdb\u001b[0m\r\ndrwxr-xr-x 14 root root 4096 Aug 23 11:33 \u001b[01;34mdevops\u001b[0m\r\n-rw-r--r-- 1 root root 20152008 Aug 23 11:35 \u001b[01;31mdevops.zip\u001b[0m\r\n-rw-r--r-- 1 root root 25 Aug 27 11:44 test.txt\r\n\u001b]0;root@k8s1:~\u0007[root@k8s1 ~]# "] +[14.456446, "o", "i"] +[14.576458, "o", "f"] +[14.752475, "o", "c"] +[14.848485, "o", "o"] +[15.032503, "o", "n"] +[15.112511, "o", "fig "] +[16.290629, "o", "\r\ndocker0: flags=4163 mtu 1500\r\n inet 172.17.0.1 netmask 255.255.0.0 broadcast 0.0.0.0\r\n inet6 fe80::42:f8ff:fe17:3a9c prefixlen 64 scopeid 0x20\r\n ether 02:42:f8:17:3a:9c txqueuelen 0 (Ethernet)\r\n RX packets 2078908 bytes 513848002 (490.0 MiB)\r\n RX errors 0 dropped 0 overruns 0 frame 0\r\n TX packets 2152281 bytes 1944502250 (1.8 GiB)\r\n TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0\r\n\r\nens33: flags=4163 mtu 1500\r\n inet 192.168.223.111 netmask 255.255.255.0 broadcast 192.168.223.255\r\n inet6 fe80::4a6e:c9fb:4e92:16d9 prefixlen 64 scopeid 0x20\r\n ether 00:0c:29:e8:f5:c8 txqueuelen 1000 (Ethernet)\r\n RX packets 2334705 bytes 2881562256 (2.6 GiB)\r\n RX errors 0 dropped 0 overruns 0 frame 0\r\n TX packets 693912 bytes 721347278 (687.9 MiB)\r\n TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0\r\n\r\nlo: flags=73<"] +[16.291629, "o", "UP,LOOPBACK,RUNNING> mtu 65536\r\n inet 127.0.0.1 netmask 255.0.0.0\r\n inet6 ::1 prefixlen 128 scopeid 0x10\r\n loop txqueuelen 1000 (Local Loopback)\r\n RX packets 24710 bytes 26774579 (25.5 MiB)\r\n RX errors 0 dropped 0 overruns 0 frame 0\r\n TX packets 24710 bytes 26774579 (25.5 MiB)\r\n TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0\r\n\r\nvethc7eafac: flags=4163 mtu 1500\r\n inet6 fe80::34c0:6aff:fe69:7c1 prefixlen 64 scopeid 0x20\r\n ether 36:c0:6a:69:07:c1 txqueuelen 0 (Ethernet)\r\n RX packets 676 bytes 592231 (578.3 KiB)\r\n RX errors 0 dropped 0 overruns 0 frame 0\r\n TX packets 775 bytes 111850 (109.2 KiB)\r\n TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0\r\n\r\nvethfa9ccda: flags=4163 mtu 1500\r\n inet6 fe80::f0a2:fdff:fe60:840b prefixlen 64 scopeid 0x20\r\n ether f2:a2:fd:60:84:0b txqueuelen 0 (Eth"] +[16.292629, "o", "ernet)\r\n RX packets 1016067 bytes 210328345 (200.5 MiB)\r\n RX errors 0 dropped 0 overruns 0 frame 0\r\n TX packets 881049 bytes 219971334 (209.7 MiB)\r\n TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0\r\n\r\n\u001b]0;root@k8s1:~\u0007[root@k8s1 ~]# "] +[16.688669, "o", "s"] +[16.69567, "o", "a"] +[16.817682, "o", "d"] +[16.928693, "o", "a"] +[16.936694, "o", "s"] +[17.032703, "o", "d"] +[17.137714, "o", "\r\n-bash: sadasd: command not found\r\n\u001b]0;root@k8s1:~\u0007[root@k8s1 ~]# "] +[17.536754, "o", "e"] +[17.807781, "o", "x"] +[17.960796, "o", "i"] +[18.072807, "o", "t"] +[18.273827, "o", "\r\nlogout\r\n"] diff --git a/static/webssh/addons/zmodem/zmodem.js b/static/webssh/addons/zmodem/zmodem.js new file mode 100644 index 0000000..70a7ff7 --- /dev/null +++ b/static/webssh/addons/zmodem/zmodem.js @@ -0,0 +1,45 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.zmodem = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i确定要退出吗? - - diff --git a/templates/user/login.html b/templates/user/login.html index 0149e17..5e6adcb 100644 --- a/templates/user/login.html +++ b/templates/user/login.html @@ -151,5 +151,6 @@ }; }; + diff --git a/templates/webssh/hosts.html b/templates/webssh/hosts.html index 10abcac..c16f12d 100644 --- a/templates/webssh/hosts.html +++ b/templates/webssh/hosts.html @@ -60,7 +60,7 @@

web终端

{{ host.get_type_display }} {{ host.get_env_display }} {{ host.ip }} - {{ host.get_protocol_display }} + {{ host.get_protocol_display }} {{ host.port }} {{ host.release }} {% if host.remote_user %} @@ -72,18 +72,30 @@

web终端

{% if host.remote_user and host.enabled %} {% if host.get_protocol_display == 'ssh' %} -
+ {% elif host.get_protocol_display == 'telnet' %} - + {% else %} - + {% endif %} {% csrf_token %} - +
{% else %} - + + {% endif %} +    + {% if host.remote_user and host.enabled %} + {% if host.get_protocol_display == 'ssh' %} +
+ {% csrf_token %} + + +
+ {% endif %} + {% else %} + {% endif %} @@ -152,4 +164,30 @@

web终端

stateDuration: 86400, // 本地储存(0~更大)还是session储存(-1) }); + + + {% endblock js %} \ No newline at end of file diff --git a/templates/webssh/logs.html b/templates/webssh/logs.html index c79055d..9f4b9b4 100644 --- a/templates/webssh/logs.html +++ b/templates/webssh/logs.html @@ -1,6 +1,10 @@ {% extends 'base.html' %} {% load static %} + {% block css %} + + {% endblock css %} + {% block title %} web终端日志 {% endblock title %} @@ -52,6 +56,7 @@

web终端日志

User_Agent 会话开始时间 事件时间 + 操作 @@ -68,6 +73,7 @@

web终端日志

{{ log.useragent | truncatechars_html:20 | default:'' }}... {{ log.start_time | date:"Y/m/d H:i:s" }} {{ log.create_time | date:"Y/m/d H:i:s" }} + 录像 {% endfor %} @@ -84,6 +90,7 @@

web终端日志

User_Agent 会话开始时间 事件时间 + 操作 @@ -91,6 +98,21 @@

web终端日志

+ + + + {% endblock content %} {% block js %} @@ -134,4 +156,29 @@

web终端日志

stateDuration: 86400, // 本地储存(0~更大)还是session储存(-1) }); + + + {% endblock js %} \ No newline at end of file diff --git a/templates/webssh/sessions.html b/templates/webssh/sessions.html index ad0b349..2b51cb9 100644 --- a/templates/webssh/sessions.html +++ b/templates/webssh/sessions.html @@ -44,6 +44,7 @@

在线会话

ID 会话名称 用户 + 类型 主机 端口 账号 @@ -58,20 +59,35 @@

在线会话

{{ session.id }} {{ session.name }} {{ session.user }} + {{ session.host }} {{ session.port }} {{ session.username }} {{ session.create_time | date:"Y/m/d H:i:s" }} - -
- {% csrf_token %} - - - -
   - 断开 + + {% if session.get_type_display == 'webssh' %} +
+ {% csrf_token %} + + + +
   + {% elif session.get_type_display == 'clissh' %} +
+ {% csrf_token %} + + + +
   + {% endif %} + + {% if session.get_type_display == 'webssh' %} + 断开 + {% elif session.get_type_display == 'clissh' %} + 断开 + {% endif %} {% endfor %} @@ -81,6 +97,7 @@

在线会话

ID 会话名称 用户 + 类型 主机 端口 账号 @@ -142,7 +159,7 @@

在线会话

stateDuration: 86400, // 本地储存(0~更大)还是session储存(-1) }); - // 关闭会话 - start + // 关闭webssh会话 - start createdeletemodal = function (event) { var thisObj = $(event); //js对象转jquery对象 var session_id = thisObj.attr('id'); @@ -268,7 +285,133 @@

在线会话

} }; } - // 关闭会话 - end + // 关闭webssh会话 - end + + // 关闭clissh会话 - start + createdeletemodal_clissh = function (event) { + var thisObj = $(event); //js对象转jquery对象 + var session_id = thisObj.attr('id'); + var session_name = thisObj.attr("title"); + // 生成弹出框,使用 \ 换行 + $("#modal-container").html(''); + + // 初始化弹出框 + $("#modal-delete-" + session_id).iziModal({ + iconClass: 'icon-announcement', + width: 450, + //padding: 10, + overlayClose: false, // 是否允许点击模态窗口的外部来关闭模态窗口。 + closeOnEscape: false, // 是否允许通过点击ESC键来关闭模态窗口。 + }); + + // 打开弹出框 + $('#modal-delete-' + session_id).iziModal('open'); + } + + + deleteclisshthis = function(event) { + toastr.options.closeButton = true; + toastr.options.showMethod = 'slideDown'; + toastr.options.hideMethod = 'fadeOut'; + toastr.options.closeMethod = 'fadeOut'; + toastr.options.timeOut = 4000; + toastr.options.extendedTimeOut = 0; + + var thisObj = $(event); //js对象转jquery对象 + var session_id = thisObj.attr('id').split("-")[0]; + var session_name = thisObj.attr("title"); + csrfmiddlewaretoken = '{{ request.COOKIES.csrftoken }}'; + $.ajax({ + url: "{% url 'webssh_api:session_clissh_close' %}", + async: true, + type: 'POST', + dataType: 'json', + data: { + 'csrfmiddlewaretoken': csrfmiddlewaretoken, + 'id': session_id, + 'session': session_name, + }, + timeout: 10000, + cache: true, + beforeSend: LoadFunction, //加载执行方法 + error: errFunction, //错误执行方法 + success: succFunction, //成功执行方法 + }); + + function LoadFunction() { + //$("#aboutcontent").html('删除中...'); + //alert('删除中'); + }; + + function errFunction() { + // 关闭弹出框 + $('#modal-delete-' + session_id).iziModal('close'); + // 消息框 + toastr.error('关闭会话错误 "' + session_name + '"'); + }; + + function succFunction(res) { + if (res.code != 200) { + // 关闭弹出框 + $('#modal-delete-' + session_id).iziModal('close'); + // 消息框 + toastr.error('关闭会话错误 "' + session_name + '": ' + res.err); + } else { + // 先销毁 datatable , 动态删除数据后,然后再重建 + var dttable = $('#datatables-lists').DataTable(); + dttable.destroy(); + + $("#session-" + session_id).remove(); + + $("#datatables-lists").DataTable({ + language: { + "sProcessing": "处理中...", + "sLengthMenu": "显示 _MENU_ 项结果", + "sZeroRecords": "没有匹配结果", + "sInfo": "显示第 _START_ 至 _END_ 项结果,共 _TOTAL_ 项", + "sInfoEmpty": "显示第 0 至 0 项结果,共 0 项", + "sInfoFiltered": "(由 _MAX_ 项结果过滤)", + "sInfoPostFix": "", + "sSearch": "搜索:", + "sUrl": "", + "sEmptyTable": "表中数据为空", + "sLoadingRecords": "载入中...", + "sInfoThousands": ",", + "oPaginate": { + "sFirst": "首页", + "sPrevious": "上页", + "sNext": "下页", + "sLast": "末页" + }, + "oAria": { + "sSortAscending": ": 以升序排列此列", + "sSortDescending": ": 以降序排列此列" + } + }, + destroy: true, // 允许重建 + bProcessing:true, // 表格数据过多处理时显示: sProcessing + lengthMenu: [[10, 25, 50, 100, -1], [10, 25, 50, 100, "全部"]], + order: [], + //scrollY: 480, // 滚动条 + //scrollCollapse: true, + //jQueryUI: true, + stateSave: true, // 保存最后一次分页信息、排序信息,当页面刷新,或者重新进入这个页面,恢复上次的状态。 + stateDuration: 86400, // 本地储存(0~更大)还是session储存(-1) + }); + + // 关闭弹出框 + $('#modal-delete-' + session_id).iziModal('close'); + + // 消息框 + toastr.success('成功关闭会话 "' + session_name + '"'); + } + }; + } + // 关闭clissh会话 - end {% endblock js %} \ No newline at end of file diff --git a/templates/webssh/terminal.html b/templates/webssh/terminal.html index 85a4e36..581b0e5 100644 --- a/templates/webssh/terminal.html +++ b/templates/webssh/terminal.html @@ -18,6 +18,9 @@ + + + @@ -42,6 +45,41 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/templates/webssh/test.html b/templates/webssh/test.html new file mode 100644 index 0000000..84d4def --- /dev/null +++ b/templates/webssh/test.html @@ -0,0 +1,21 @@ +{% load static %} + + + + + + + 测试 + + + + + + + + + + + + + diff --git a/terminal_logs/2qCw37Qa1OR6mDGF.txt b/terminal_logs/2qCw37Qa1OR6mDGF.txt new file mode 100644 index 0000000..99dce62 --- /dev/null +++ b/terminal_logs/2qCw37Qa1OR6mDGF.txt @@ -0,0 +1,305 @@ +{"version": 2, "width": 250, "height": 40, "timestamp": 1566886015, "env": {"SHELL": "/bin/sh", "TERM": "linux"}} +[0.314, "o", "Last login: Tue Aug 27 11:31:40 2019 from 192.168.223.1\r\r\n"] +[0.366, "o", "[root@k8s2 ~]# "] +[1.191, "o", "l"] +[1.326, "o", "l"] +[1.489, "o", "\r\n"] +[1.49, "o", "total 0\r\n[root@k8s2 ~]# "] +[2.254, "o", "v"] +[2.318, "o", "i"] +[2.486, "o", "m"] +[2.55, "o", " "] +[2.654, "o", "t"] +[2.774, "o", "e"] +[2.862, "o", "s"] +[2.974, "o", "t"] +[3.19, "o", "."] +[4.078, "o", "t"] +[4.159, "o", "x"] +[4.254, "o", "t"] +[4.61, "o", "\r\n"] +[4.838, "o", "\u001b[2;1H\u25bd\u001b[6n\u001b[1;1H \u001b[1;1H\u001b[1;56r\u001b[?25h\u001b[?8c\u001b[?25h\u001b[?0c\u001b[27m\u001b[24m\u001b[0m\u001b[H\u001b[J\u001b[?25l\u001b[?1c\u001b[56;1H\"test.txt\" [New File]"] +[4.845, "o", "\u001b[2;1H\u001b[1m\u001b[34m~ \u001b[3;1H~ \u001b[4;1H~ \u001b[5;1H~ \u001b[6;1H~ "] +[4.846, "o", " \u001b[7;1H~ \u001b[8;1H~ \u001b[9;1H~ \u001b[10;1H~ \u001b[11;1H~ "] +[4.846, "o", " \u001b[12;1H~ \u001b[13;1H~ \u001b[14;1H~ \u001b[15;1H~ "] +[4.846, "o", " \u001b[16;1H~ \u001b[17;1H~ \u001b[18;1H~ \u001b[19;1H~ \u001b[20;1H~ "] +[4.847, "o", " \u001b[21;1H~ \u001b[22;1H~ \u001b[23;1H~ \u001b[24;1H~ \u001b[25;1H~ "] +[4.847, "o", " \u001b[26;1H~ \u001b[27;1H~ \u001b[28;1H~ \u001b[29;1H~ "] +[4.847, "o", " \u001b[30;1H~ \u001b[31;1H~ \u001b[32;1H~ \u001b[33;1H~ \u001b[34;1H~ "] +[4.848, "o", " \u001b[35;1H~ \u001b[36;1H~ \u001b[37;1H~ \u001b[38;1H~ \u001b[39;1H~ "] +[4.848, "o", " \u001b[40;1H~ \u001b[41;1H~ \u001b[42;1H~ \u001b[43;1H~ "] +[4.848, "o", " \u001b[44;1H~ \u001b[45;1H~ \u001b[46;1H~ \u001b[47;1H~ \u001b[48;1H~ "] +[4.849, "o", " \u001b[49;1H~ \u001b[50;1H~ \u001b[51;1H~ \u001b[52;1H~ \u001b[53;1H~ "] +[4.849, "o", " \u001b[54;1H~ \u001b[55;1H~ \u001b[0m\u001b[56;196H0,0-1\u001b[9CAll\u001b[1;1H\u001b[?25h\u001b[?0c"] +[5.342, "o", "\u001b[?25l\u001b[?1c\u001b[56;1H\u001b[1m-- INSERT --\u001b[0m\u001b[56;13H\u001b[K\u001b[56;196H0,1\u001b[11CAll\u001b[1;1H\u001b[?25h\u001b[?0c"] +[5.486, "o", "\u001b[?25l\u001b[?1ca\u001b[56;196H1,2\u001b[1;2H\u001b[?25h\u001b[?0c"] +[5.551, "o", "\u001b[?25l\u001b[?1cs\u001b[56;198H3\u001b[1;3H\u001b[?25h\u001b[?0c"] +[5.612, "o", "\u001b[?25l\u001b[?1cd\u001b[56;198H4\u001b[1;4H\u001b[?25h\u001b[?0c"] +[5.702, "o", "\u001b[?25l\u001b[?1ca\u001b[56;198H5\u001b[1;5H\u001b[?25h\u001b[?0c"] +[6.202, "o", "\u001b[?25l\u001b[?1ca\u001b[56;198H6\u001b[1;6H\u001b[?25h\u001b[?0c"] +[6.261, "o", "\u001b[?25l\u001b[?1ca\u001b[56;198H7\u001b[1;7H\u001b[?25h\u001b[?0c"] +[6.268, "o", "\u001b[?25l\u001b[?1ca\u001b[56;198H8\u001b[1;8H\u001b[?25h\u001b[?0c"] +[6.329, "o", "\u001b[?25l\u001b[?1ca\u001b[56;198H9\u001b[1;9H\u001b[?25h\u001b[?0c"] +[6.334, "o", "\u001b[?25l\u001b[?1ca\u001b[56;198H10\u001b[1;10H\u001b[?25h\u001b[?0c"] +[6.397, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H1\u001b[1;11H\u001b[?25h\u001b[?0c"] +[6.399, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H2\u001b[1;12H\u001b[?25h\u001b[?0c"] +[6.461, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H3\u001b[1;13H\u001b[?25h\u001b[?0c"] +[6.465, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H4\u001b[1;14H\u001b[?25h\u001b[?0c"] +[6.529, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H5\u001b[1;15H\u001b[?25h\u001b[?0c"] +[6.531, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H6\u001b[1;16H\u001b[?25h\u001b[?0c"] +[6.596, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H7\u001b[1;17H\u001b[?25h\u001b[?0c"] +[6.598, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H8\u001b[1;18H\u001b[?25h\u001b[?0c"] +[6.662, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H9\u001b[1;19H\u001b[?25h\u001b[?0c"] +[6.664, "o", "\u001b[?25l\u001b[?1ca\u001b[56;198H20\u001b[1;20H\u001b[?25h\u001b[?0c"] +[6.729, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H1\u001b[1;21H\u001b[?25h\u001b[?0c"] +[6.73, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H2\u001b[1;22H\u001b[?25h\u001b[?0c"] +[6.796, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H3\u001b[1;23H\u001b[?25h\u001b[?0c"] +[6.796, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H4\u001b[1;24H\u001b[?25h\u001b[?0c"] +[6.861, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H5\u001b[1;25H\u001b[?25h\u001b[?0c"] +[6.862, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H6\u001b[1;26H\u001b[?25h\u001b[?0c"] +[6.927, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H7\u001b[1;27H\u001b[?25h\u001b[?0c"] +[6.928, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H8\u001b[1;28H\u001b[?25h\u001b[?0c"] +[6.996, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H9\u001b[1;29H\u001b[?25h\u001b[?0c"] +[6.997, "o", "\u001b[?25l\u001b[?1ca\u001b[56;198H30\u001b[1;30H\u001b[?25h\u001b[?0c"] +[7.062, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H1\u001b[1;31H\u001b[?25h\u001b[?0c"] +[7.063, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H2\u001b[1;32H\u001b[?25h\u001b[?0c"] +[7.129, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H3\u001b[1;33H\u001b[?25h\u001b[?0c"] +[7.13, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H4\u001b[1;34H\u001b[?25h\u001b[?0c"] +[7.196, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H5\u001b[1;35H\u001b[?25h\u001b[?0c"] +[7.196, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H6\u001b[1;36H\u001b[?25h\u001b[?0c"] +[7.262, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H7\u001b[1;37H\u001b[?25h\u001b[?0c"] +[7.263, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H8\u001b[1;38H\u001b[?25h\u001b[?0c"] +[7.329, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H9\u001b[1;39H\u001b[?25h\u001b[?0c"] +[7.33, "o", "\u001b[?25l\u001b[?1ca\u001b[56;198H40\u001b[1;40H\u001b[?25h\u001b[?0c"] +[7.396, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H1\u001b[1;41H\u001b[?25h\u001b[?0c"] +[7.397, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H2\u001b[1;42H\u001b[?25h\u001b[?0c"] +[7.461, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H3\u001b[1;43H\u001b[?25h\u001b[?0c"] +[7.462, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H4\u001b[1;44H\u001b[?25h\u001b[?0c"] +[7.527, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H5\u001b[1;45H\u001b[?25h\u001b[?0c"] +[7.528, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H6\u001b[1;46H\u001b[?25h\u001b[?0c"] +[7.595, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H7\u001b[1;47H\u001b[?25h\u001b[?0c"] +[7.596, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H8\u001b[1;48H\u001b[?25h\u001b[?0c"] +[7.662, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H9\u001b[1;49H\u001b[?25h\u001b[?0c"] +[7.663, "o", "\u001b[?25l\u001b[?1ca\u001b[56;198H50\u001b[1;50H\u001b[?25h\u001b[?0c"] +[7.728, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H1\u001b[1;51H\u001b[?25h\u001b[?0c"] +[7.728, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H2\u001b[1;52H\u001b[?25h\u001b[?0c"] +[7.795, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H3\u001b[1;53H\u001b[?25h\u001b[?0c\u001b[?25l\u001b[?1ca\u001b[56;199H4\u001b[1;54H\u001b[?25h\u001b[?0c"] +[7.863, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H5\u001b[1;55H\u001b[?25h\u001b[?0c"] +[7.864, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H6\u001b[1;56H\u001b[?25h\u001b[?0c"] +[7.929, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H7\u001b[1;57H\u001b[?25h\u001b[?0c"] +[7.929, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H8\u001b[1;58H\u001b[?25h\u001b[?0c"] +[7.995, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H9\u001b[1;59H\u001b[?25h\u001b[?0c"] +[7.995, "o", "\u001b[?25l\u001b[?1ca\u001b[56;198H60\u001b[1;60H\u001b[?25h\u001b[?0c"] +[8.062, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H1\u001b[1;61H\u001b[?25h\u001b[?0c"] +[8.063, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H2\u001b[1;62H\u001b[?25h\u001b[?0c"] +[8.129, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H3\u001b[1;63H\u001b[?25h\u001b[?0c"] +[8.13, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H4\u001b[1;64H\u001b[?25h\u001b[?0c"] +[8.196, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H5\u001b[1;65H\u001b[?25h\u001b[?0c"] +[8.196, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H6\u001b[1;66H\u001b[?25h\u001b[?0c"] +[8.262, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H7\u001b[1;67H\u001b[?25h\u001b[?0c\u001b[?25l\u001b[?1ca\u001b[56;199H8\u001b[1;68H\u001b[?25h\u001b[?0c"] +[8.329, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H9\u001b[1;69H\u001b[?25h\u001b[?0c"] +[8.334, "o", "\u001b[?25l\u001b[?1ca\u001b[56;198H70\u001b[1;70H\u001b[?25h\u001b[?0c"] +[8.396, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H1\u001b[1;71H\u001b[?25h\u001b[?0c"] +[8.396, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H2\u001b[1;72H\u001b[?25h\u001b[?0c"] +[8.412, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H3\u001b[1;73H\u001b[?25h\u001b[?0c"] +[8.477, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H4\u001b[1;74H\u001b[?25h\u001b[?0c"] +[8.478, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H5\u001b[1;75H\u001b[?25h\u001b[?0c"] +[8.544, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H6\u001b[1;76H\u001b[?25h\u001b[?0c"] +[8.545, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H7\u001b[1;77H\u001b[?25h\u001b[?0c"] +[8.611, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H8\u001b[1;78H\u001b[?25h\u001b[?0c"] +[8.612, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H9\u001b[1;79H\u001b[?25h\u001b[?0c"] +[8.678, "o", "\u001b[?25l\u001b[?1ca\u001b[56;198H80\u001b[1;80H\u001b[?25h\u001b[?0c"] +[8.678, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H1\u001b[1;81H\u001b[?25h\u001b[?0c"] +[8.745, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H2\u001b[1;82H\u001b[?25h\u001b[?0c"] +[8.746, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H3\u001b[1;83H\u001b[?25h\u001b[?0c"] +[8.812, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H4\u001b[1;84H\u001b[?25h\u001b[?0c"] +[8.813, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H5\u001b[1;85H\u001b[?25h\u001b[?0c"] +[8.879, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H6\u001b[1;86H\u001b[?25h\u001b[?0c\u001b[?25l\u001b[?1ca\u001b[56;199H7\u001b[1;87H\u001b[?25h\u001b[?0c"] +[8.946, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H8\u001b[1;88H\u001b[?25h\u001b[?0c"] +[8.946, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H9\u001b[1;89H\u001b[?25h\u001b[?0c"] +[9.013, "o", "\u001b[?25l\u001b[?1ca\u001b[56;198H90\u001b[1;90H\u001b[?25h\u001b[?0c"] +[9.019, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H1\u001b[1;91H\u001b[?25h\u001b[?0c"] +[9.04, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H2\u001b[1;92H\u001b[?25h\u001b[?0c"] +[9.098, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H3\u001b[1;93H\u001b[?25h\u001b[?0c"] +[9.106, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H4\u001b[1;94H\u001b[?25h\u001b[?0c"] +[9.161, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H5\u001b[1;95H\u001b[?25h\u001b[?0c"] +[9.172, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H6\u001b[1;96H\u001b[?25h\u001b[?0c"] +[9.228, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H7\u001b[1;97H\u001b[?25h\u001b[?0c"] +[9.238, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H8\u001b[1;98H\u001b[?25h\u001b[?0c"] +[9.296, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H9\u001b[1;99H\u001b[?25h\u001b[?0c"] +[9.304, "o", "\u001b[?25l\u001b[?1ca\u001b[56;198H100\u001b[1;100H\u001b[?25h\u001b[?0c"] +[9.362, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H1\u001b[1;101H\u001b[?25h\u001b[?0c"] +[9.37, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H2\u001b[1;102H\u001b[?25h\u001b[?0c"] +[9.428, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H3\u001b[1;103H\u001b[?25h\u001b[?0c"] +[9.483, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H4\u001b[1;104H\u001b[?25h\u001b[?0c"] +[9.484, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H5\u001b[1;105H\u001b[?25h\u001b[?0c"] +[9.546, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H6\u001b[1;106H\u001b[?25h\u001b[?0c\u001b[?25l\u001b[?1ca\u001b[56;200H7\u001b[1;107H\u001b[?25h\u001b[?0c"] +[9.611, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H8\u001b[1;108H\u001b[?25h\u001b[?0c"] +[9.612, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H9\u001b[1;109H\u001b[?25h\u001b[?0c"] +[9.679, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H10\u001b[1;110H\u001b[?25h\u001b[?0c"] +[9.679, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H1\u001b[1;111H\u001b[?25h\u001b[?0c"] +[9.745, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H2\u001b[1;112H\u001b[?25h\u001b[?0c\u001b[?25l\u001b[?1ca\u001b[56;200H3\u001b[1;113H\u001b[?25h\u001b[?0c"] +[9.812, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H4\u001b[1;114H\u001b[?25h\u001b[?0c"] +[9.813, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H5\u001b[1;115H\u001b[?25h\u001b[?0c"] +[9.879, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H6\u001b[1;116H\u001b[?25h\u001b[?0c"] +[9.879, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H7\u001b[1;117H\u001b[?25h\u001b[?0c"] +[9.944, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H8\u001b[1;118H\u001b[?25h\u001b[?0c"] +[9.945, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H9\u001b[1;119H\u001b[?25h\u001b[?0c"] +[10.011, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H20\u001b[1;120H\u001b[?25h\u001b[?0c"] +[10.011, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H1\u001b[1;121H\u001b[?25h\u001b[?0c"] +[10.078, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H2\u001b[1;122H\u001b[?25h\u001b[?0c"] +[10.079, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H3\u001b[1;123H\u001b[?25h\u001b[?0c"] +[10.144, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H4\u001b[1;124H\u001b[?25h\u001b[?0c"] +[10.145, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H5\u001b[1;125H\u001b[?25h\u001b[?0c"] +[10.211, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H6\u001b[1;126H\u001b[?25h\u001b[?0c"] +[10.213, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H7\u001b[1;127H\u001b[?25h\u001b[?0c"] +[10.278, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H8\u001b[1;128H\u001b[?25h\u001b[?0c"] +[10.279, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H9\u001b[1;129H\u001b[?25h\u001b[?0c"] +[10.345, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H30\u001b[1;130H\u001b[?25h\u001b[?0c"] +[10.345, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H1\u001b[1;131H\u001b[?25h\u001b[?0c"] +[10.412, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H2\u001b[1;132H\u001b[?25h\u001b[?0c"] +[10.413, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H3\u001b[1;133H\u001b[?25h\u001b[?0c"] +[10.479, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H4\u001b[1;134H\u001b[?25h\u001b[?0c"] +[10.479, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H5\u001b[1;135H\u001b[?25h\u001b[?0c"] +[10.545, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H6\u001b[1;136H\u001b[?25h\u001b[?0c"] +[10.545, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H7\u001b[1;137H\u001b[?25h\u001b[?0c"] +[10.611, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H8\u001b[1;138H\u001b[?25h\u001b[?0c"] +[10.612, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H9\u001b[1;139H\u001b[?25h\u001b[?0c"] +[10.624, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H40\u001b[1;140H\u001b[?25h\u001b[?0c"] +[10.679, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H1\u001b[1;141H\u001b[?25h\u001b[?0c"] +[10.69, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H2\u001b[1;142H\u001b[?25h\u001b[?0c"] +[10.746, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H3\u001b[1;143H\u001b[?25h\u001b[?0c"] +[10.757, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H4\u001b[1;144H\u001b[?25h\u001b[?0c"] +[10.812, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H5\u001b[1;145H\u001b[?25h\u001b[?0c"] +[10.822, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H6\u001b[1;146H\u001b[?25h\u001b[?0c"] +[10.879, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H7\u001b[1;147H\u001b[?25h\u001b[?0c"] +[10.888, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H8\u001b[1;148H\u001b[?25h\u001b[?0c"] +[10.946, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H9\u001b[1;149H\u001b[?25h\u001b[?0c"] +[10.954, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H50\u001b[1;150H\u001b[?25h\u001b[?0c"] +[11.011, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H1\u001b[1;151H\u001b[?25h\u001b[?0c"] +[11.02, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H2\u001b[1;152H\u001b[?25h\u001b[?0c"] +[11.078, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H3\u001b[1;153H\u001b[?25h\u001b[?0c"] +[11.086, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H4\u001b[1;154H\u001b[?25h\u001b[?0c"] +[11.145, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H5\u001b[1;155H\u001b[?25h\u001b[?0c"] +[11.152, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H6\u001b[1;156H\u001b[?25h\u001b[?0c"] +[11.212, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H7\u001b[1;157H\u001b[?25h\u001b[?0c"] +[11.218, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H8\u001b[1;158H\u001b[?25h\u001b[?0c"] +[11.278, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H9\u001b[1;159H\u001b[?25h\u001b[?0c"] +[11.284, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H60\u001b[1;160H\u001b[?25h\u001b[?0c"] +[11.345, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H1\u001b[1;161H\u001b[?25h\u001b[?0c"] +[11.35, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H2\u001b[1;162H\u001b[?25h\u001b[?0c"] +[11.411, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H3\u001b[1;163H\u001b[?25h\u001b[?0c"] +[11.415, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H4\u001b[1;164H\u001b[?25h\u001b[?0c"] +[11.479, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H5\u001b[1;165H\u001b[?25h\u001b[?0c"] +[11.481, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H6\u001b[1;166H\u001b[?25h\u001b[?0c"] +[11.546, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H7\u001b[1;167H\u001b[?25h\u001b[?0c"] +[11.548, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H8\u001b[1;168H\u001b[?25h\u001b[?0c"] +[11.612, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H9\u001b[1;169H\u001b[?25h\u001b[?0c"] +[11.613, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H70\u001b[1;170H\u001b[?25h\u001b[?0c"] +[11.679, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H1\u001b[1;171H\u001b[?25h\u001b[?0c"] +[11.68, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H2\u001b[1;172H\u001b[?25h\u001b[?0c"] +[11.746, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H3\u001b[1;173H\u001b[?25h\u001b[?0c"] +[11.746, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H4\u001b[1;174H\u001b[?25h\u001b[?0c"] +[11.812, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H5\u001b[1;175H\u001b[?25h\u001b[?0c"] +[11.813, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H6\u001b[1;176H\u001b[?25h\u001b[?0c"] +[11.879, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H7\u001b[1;177H\u001b[?25h\u001b[?0c"] +[11.88, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H8\u001b[1;178H\u001b[?25h\u001b[?0c"] +[11.944, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H9\u001b[1;179H\u001b[?25h\u001b[?0c"] +[11.945, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H80\u001b[1;180H\u001b[?25h\u001b[?0c"] +[12.011, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H1\u001b[1;181H\u001b[?25h\u001b[?0c"] +[12.012, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H2\u001b[1;182H\u001b[?25h\u001b[?0c"] +[12.077, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H3\u001b[1;183H\u001b[?25h\u001b[?0c"] +[12.078, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H4\u001b[1;184H\u001b[?25h\u001b[?0c"] +[12.145, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H5\u001b[1;185H\u001b[?25h\u001b[?0c"] +[12.146, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H6\u001b[1;186H\u001b[?25h\u001b[?0c"] +[12.211, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H7\u001b[1;187H\u001b[?25h\u001b[?0c"] +[12.212, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H8\u001b[1;188H\u001b[?25h\u001b[?0c"] +[12.279, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H9\u001b[1;189H\u001b[?25h\u001b[?0c\u001b[?25l\u001b[?1ca\u001b[56;199H90\u001b[1;190H\u001b[?25h\u001b[?0c"] +[12.346, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H1\u001b[1;191H\u001b[?25h\u001b[?0c"] +[12.346, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H2\u001b[1;192H\u001b[?25h\u001b[?0c"] +[12.412, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H3\u001b[1;193H\u001b[?25h\u001b[?0c"] +[12.413, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H4\u001b[1;194H\u001b[?25h\u001b[?0c"] +[12.479, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H5\u001b[1;195H\u001b[?25h\u001b[?0c"] +[12.48, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H6\u001b[1;196H\u001b[?25h\u001b[?0c"] +[12.545, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H7\u001b[1;197H\u001b[?25h\u001b[?0c"] +[12.546, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H8\u001b[1;198H\u001b[?25h\u001b[?0c"] +[12.612, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H9\u001b[1;199H\u001b[?25h\u001b[?0c"] +[12.613, "o", "\u001b[?25l\u001b[?1ca\u001b[56;198H200\u001b[1;200H\u001b[?25h\u001b[?0c"] +[12.678, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H1\u001b[1;201H\u001b[?25h\u001b[?0c"] +[12.679, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H2\u001b[1;202H\u001b[?25h\u001b[?0c"] +[12.744, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H3\u001b[1;203H\u001b[?25h\u001b[?0c"] +[12.745, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H4\u001b[1;204H\u001b[?25h\u001b[?0c"] +[12.811, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H5\u001b[1;205H\u001b[?25h\u001b[?0c"] +[12.812, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H6\u001b[1;206H\u001b[?25h\u001b[?0c"] +[12.878, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H7\u001b[1;207H\u001b[?25h\u001b[?0c"] +[12.879, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H8\u001b[1;208H\u001b[?25h\u001b[?0c"] +[12.946, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H9\u001b[1;209H\u001b[?25h\u001b[?0c"] +[12.946, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H10\u001b[1;210H\u001b[?25h\u001b[?0c"] +[13.011, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H1\u001b[1;211H\u001b[?25h\u001b[?0c"] +[13.012, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H2\u001b[1;212H\u001b[?25h\u001b[?0c"] +[13.078, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H3\u001b[1;213H\u001b[?25h\u001b[?0c"] +[13.079, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H4\u001b[2;1H\u001b[?25h\u001b[?0c"] +[13.144, "o", "\u001b[?25l\u001b[?1ca\u001b[2;2H\u001b[K\u001b[56;200H5\u001b[2;2H\u001b[?25h\u001b[?0c"] +[13.144, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H6\u001b[2;3H\u001b[?25h\u001b[?0c"] +[13.21, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H7\u001b[2;4H\u001b[?25h\u001b[?0c"] +[13.21, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H8\u001b[2;5H\u001b[?25h\u001b[?0c"] +[13.278, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H9\u001b[2;6H\u001b[?25h\u001b[?0c"] +[13.278, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H20\u001b[2;7H\u001b[?25h\u001b[?0c"] +[13.343, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H1\u001b[2;8H\u001b[?25h\u001b[?0c"] +[13.344, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H2\u001b[2;9H\u001b[?25h\u001b[?0c"] +[13.411, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H3\u001b[2;10H\u001b[?25h\u001b[?0c"] +[13.412, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H4\u001b[2;11H\u001b[?25h\u001b[?0c"] +[13.477, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H5\u001b[2;12H\u001b[?25h\u001b[?0c"] +[13.478, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H6\u001b[2;13H\u001b[?25h\u001b[?0c"] +[13.543, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H7\u001b[2;14H\u001b[?25h\u001b[?0c"] +[13.544, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H8\u001b[2;15H\u001b[?25h\u001b[?0c"] +[13.61, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H9\u001b[2;16H\u001b[?25h\u001b[?0c"] +[13.61, "o", "\u001b[?25l\u001b[?1ca\u001b[56;199H30\u001b[2;17H\u001b[?25h\u001b[?0c"] +[13.677, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H1\u001b[2;18H\u001b[?25h\u001b[?0c"] +[13.678, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H2\u001b[2;19H\u001b[?25h\u001b[?0c"] +[13.744, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H3\u001b[2;20H\u001b[?25h\u001b[?0c"] +[13.745, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H4\u001b[2;21H\u001b[?25h\u001b[?0c"] +[13.81, "o", "\u001b[?25l\u001b[?1ca\u001b[56;200H5\u001b[2;22H\u001b[?25h\u001b[?0c"] +[13.976, "o", "\u001b[?25l\u001b[?1c\u001b[3;1H\u001b[K\u001b[56;196H2,1 \u001b[3;1H\u001b[?25h\u001b[?0c"] +[14.137, "o", "\u001b[?25l\u001b[?1c\u001b[4;1H\u001b[K\u001b[56;196H3\u001b[4;1H\u001b[?25h\u001b[?0c"] +[14.321, "o", "\u001b[?25l\u001b[?1c\u001b[5;1H\u001b[K\u001b[56;196H4\u001b[5;1H\u001b[?25h\u001b[?0c"] +[14.489, "o", "\u001b[?25l\u001b[?1c\u001b[6;1H\u001b[K\u001b[56;196H5\u001b[6;1H\u001b[?25h\u001b[?0c"] +[14.712, "o", "\u001b[?25l\u001b[?1c\u001b[7;1H\u001b[K\u001b[56;196H6\u001b[7;1H\u001b[?25h\u001b[?0c"] +[14.712, "o", "\u001b[?25l\u001b[?1ca\u001b[56;198H2\u001b[7;2H\u001b[?25h\u001b[?0c"] +[14.765, "o", "\u001b[?25l\u001b[?1cs\u001b[56;198H3\u001b[7;3H\u001b[?25h\u001b[?0c"] +[14.837, "o", "\u001b[?25l\u001b[?1cd\u001b[56;198H4\u001b[7;4H\u001b[?25h\u001b[?0c"] +[14.941, "o", "\u001b[?25l\u001b[?1ca\u001b[56;198H5\u001b[7;5H\u001b[?25h\u001b[?0c"] +[15.029, "o", "\u001b[?25l\u001b[?1cd\u001b[56;198H6\u001b[7;6H\u001b[?25h\u001b[?0c"] +[15.149, "o", "\u001b[?25l\u001b[?1ca\u001b[56;198H7\u001b[7;7H\u001b[?25h\u001b[?0c"] +[15.296, "o", "\u001b[?25l\u001b[?1c\u001b[8;1H\u001b[K\u001b[56;196H7,1\u001b[8;1H\u001b[?25h\u001b[?0c"] +[15.471, "o", "\u001b[?25l\u001b[?1c\u001b[9;1H\u001b[K\u001b[56;196H8\u001b[9;1H\u001b[?25h\u001b[?0c"] +[15.641, "o", "\u001b[?25l\u001b[?1c\u001b[10;1H\u001b[K\u001b[56;196H9\u001b[10;1H\u001b[?25h\u001b[?0c"] +[15.851, "o", "\u001b[?25l\u001b[?1c\u001b[11;1H\u001b[K\u001b[56;196H10,1\u001b[11;1H\u001b[?25h\u001b[?0c"] +[16.315, "o", "\u001b[?25l\u001b[?1c\u001b[12;1H\u001b[K\u001b[56;197H1\u001b[12;1H\u001b[?25h\u001b[?0c"] +[16.377, "o", "\u001b[?25l\u001b[?1c\u001b[13;1H\u001b[K\u001b[56;197H2\u001b[13;1H\u001b[?25h\u001b[?0c"] +[16.456, "o", "\u001b[?25l\u001b[?1c\u001b[14;1H\u001b[K\u001b[56;197H3\u001b[14;1H\u001b[?25h\u001b[?0c"] +[16.5, "o", "\u001b[?25l\u001b[?1c\u001b[15;1H\u001b[K\u001b[56;197H4\u001b[15;1H\u001b[?25h\u001b[?0c"] +[16.529, "o", "\u001b[?25l\u001b[?1c\u001b[16;1H\u001b[K\u001b[56;197H5\u001b[16;1H\u001b[?25h\u001b[?0c"] +[16.54, "o", "\u001b[?25l\u001b[?1c\u001b[17;1H\u001b[K\u001b[56;197H6\u001b[17;1H\u001b[?25h\u001b[?0c"] +[16.552, "o", "\u001b[?25l\u001b[?1c\u001b[18;1H\u001b[K\u001b[56;197H7\u001b[18;1H\u001b[?25h\u001b[?0c"] +[16.563, "o", "\u001b[?25l\u001b[?1c\u001b[19;1H\u001b[K\u001b[56;197H8\u001b[19;1H\u001b[?25h\u001b[?0c"] +[16.575, "o", "\u001b[?25l\u001b[?1c\u001b[20;1H\u001b[K\u001b[56;197H9\u001b[20;1H\u001b[?25h\u001b[?0c"] +[16.619, "o", "\u001b[?25l\u001b[?1c\u001b[21;1H\u001b[K\u001b[56;196H20\u001b[21;1H\u001b[?25h\u001b[?0c"] +[16.672, "o", "\u001b[?25l\u001b[?1c\u001b[22;1H\u001b[K\u001b[56;197H1\u001b[22;1H\u001b[?25h\u001b[?0c"] +[16.692, "o", "\u001b[?25l\u001b[?1c\u001b[23;1H\u001b[K\u001b[56;197H2\u001b[23;1H\u001b[?25h\u001b[?0c"] +[16.706, "o", "\u001b[?25l\u001b[?1c\u001b[24;1H\u001b[K\u001b[56;197H3\u001b[24;1H\u001b[?25h\u001b[?0c"] +[16.767, "o", "\u001b[56;1H\u001b[K\u001b[24;1H"] +[17.645, "o", "\u001b[?25l\u001b[?1c\u001b[56;196H23,0-1\u001b[8CAll\u001b[24;1H\u001b[?25h\u001b[?0c\u001b[?25l\u001b[?1c\u001b[56;196H\u001b[K\u001b[56;1H:\u001b[?25h\u001b[?0c"] +[17.765, "o", "w\u001b[?25l\u001b[?1c\u001b[?25h\u001b[?0c"] +[17.869, "o", "q\u001b[?25l\u001b[?1c\u001b[?25h\u001b[?0c"] +[18.073, "o", "\r\u001b[?25l\u001b[?1c\"test.txt\""] +[18.074, "o", " [New] 23L, 263C written\r\u001b[?25h\u001b[?0c\r\r\n[root@k8s2 ~]# "] +[18.333, "o", "l"] +[18.861, "o", "l"] +[19.135, "o", "\r\n"] +[19.137, "o", "total 4\r\n-rw-r--r-- 1 root root 263 Aug 27 14:07 test.txt\r\n[root@k8s2 ~]# "] +[19.701, "o", "e"] +[19.949, "o", "x"] +[20.053, "o", "i"] +[20.221, "o", "t"] +[20.489, "o", "\r\nlogout\r\n"] diff --git a/terminal_logs/67LVGSK9QH2XyRJx.txt b/terminal_logs/67LVGSK9QH2XyRJx.txt new file mode 100644 index 0000000..b5e57f9 --- /dev/null +++ b/terminal_logs/67LVGSK9QH2XyRJx.txt @@ -0,0 +1 @@ +{"version": 2, "width": 250, "height": 40, "timestamp": 1566886955, "env": {"SHELL": "/bin/sh", "TERM": "linux"}} diff --git a/terminal_logs/dSYE8X4fxNa5pyvG.txt b/terminal_logs/dSYE8X4fxNa5pyvG.txt new file mode 100644 index 0000000..4836624 --- /dev/null +++ b/terminal_logs/dSYE8X4fxNa5pyvG.txt @@ -0,0 +1,3 @@ +{"version": 2, "width": 250, "height": 40, "timestamp": 1566886898, "env": {"SHELL": "/bin/sh", "TERM": "linux"}} +[0.411041, "o", "Last login: Tue Aug 27 14:06:55 2019 from 192.168.223.1\r\r\n"] +[0.413041, "o", "\u001b]0;root@k8s2:~\u0007\u001b[?1034h[root@k8s2 ~]# "] diff --git a/terminal_logs/h9LGTwsbzou6f57Z.txt b/terminal_logs/h9LGTwsbzou6f57Z.txt new file mode 100644 index 0000000..31775d5 --- /dev/null +++ b/terminal_logs/h9LGTwsbzou6f57Z.txt @@ -0,0 +1,203 @@ +{"version": 2, "width": 250, "height": 40, "timestamp": 1566886930, "env": {"SHELL": "/bin/sh", "TERM": "linux"}} +[0.754075, "o", "Last login: Tue Aug 27 14:02:03 2019 from 192.168.223.1\r\r\n[root@k8s1 ~]# "] +[2.263226, "o", "l"] +[2.407241, "o", "l"] +[2.616262, "o", "\r\ntotal 19688\r\ndrwxr-xr-x 11 root root 317 Aug 27 12:42 \u001b[0m\u001b[01;34mcmdb\u001b[0m\r\ndrwxr-xr-x 14 root root 4096 Aug 23 11:33 \u001b[01;34mdevops\u001b[0m\r\n-rw-r--r-- 1 root root 20152008 Aug 23 11:35 \u001b[01;31mdevops.zip\u001b[0m\r\n-rw-r--r-- 1 root root 275 Aug 27 14:02 test.txt\r\n[root@k8s1 ~]# "] +[2.895289, "o", "c"] +[3.038304, "o", "l"] +[3.10231, "o", "e"] +[3.223322, "o", "a"] +[3.342334, "o", "r"] +[3.440344, "o", "\r\n\u001b[H\u001b[J[root@k8s1 ~]# "] +[3.623362, "o", "l"] +[3.759376, "o", "l"] +[3.840384, "o", "\r\ntotal 19688\r\ndrwxr-xr-x 11 root root 317 Aug 27 12:42 \u001b[0m\u001b[01;34mcmdb\u001b[0m\r\ndrwxr-xr-x 14 root root 4096 Aug 23 11:33 \u001b[01;34mdevops\u001b[0m\r\n-rw-r--r-- 1 root root 20152008 Aug 23 11:35 \u001b[01;31mdevops.zip\u001b[0m\r\n-rw-r--r-- 1 root root 275 Aug 27 14:02 test.txt\r\n[root@k8s1 ~]# "] +[5.582558, "o", "v"] +[5.711571, "o", "i"] +[5.870587, "o", "m"] +[5.950595, "o", " "] +[6.015601, "o", "t"] +[6.268627, "o", "est.txt "] +[6.650665, "o", "\r\n"] +[6.659666, "o", "\u001b[2;1H\u25bd\u001b[6n\u001b[1;1H \u001b[1;1H\u001b[1;40r\u001b[?25h\u001b[?8c\u001b[?25h\u001b[?0c\u001b[27m\u001b[24m\u001b[0m\u001b[H\u001b[J\u001b[?25l\u001b[?1c\u001b[40;1H\"test.txt\" 20L, 275C\u001b[3;1H1212weq\r\nasdas\u001b[12;1Hasdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\u001b[13;1Haaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\u001b[14;1Haaaa\r\n\r\nasdasdsada\r\n\r\n131\u001b[22;1H213123\r\n\u001b[1m\u001b[34m~ \u001b[24;1H~ \u001b[25;1H~ \u001b[26;1H~ \u001b[27;1H~ \u001b[28;1H~ "] +[6.661666, "o", " \u001b[29;1H~ \u001b[30;1H~ \u001b[31;1H~ \u001b[32;1H~ \u001b[33;1H~ \u001b[34;1H~ \u001b[35;1H~ \u001b[36;1H~ "] +[6.662666, "o", " \u001b[37;1H~ \u001b[38;1H~ \u001b[39;1H~ \u001b[0m\u001b[40;93H14,1\u001b[10CAll\u001b[16;1H\u001b[?25h\u001b[?0c"] +[7.79978, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H5,0-1\u001b[17;1H\u001b[?25h\u001b[?0c"] +[8.29883, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H6,1 \u001b[18;1H\u001b[?25h\u001b[?0c"] +[8.331833, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H7,0-1\u001b[19;1H\u001b[?25h\u001b[?0c"] +[8.364836, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H8\u001b[20;1H\u001b[?25h\u001b[?0c"] +[8.39784, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H9\u001b[21;1H\u001b[?25h\u001b[?0c"] +[8.430843, "o", "\u001b[?25l\u001b[?1c\u001b[40;93H20,1 \u001b[22;1H\u001b[?25h\u001b[?0c"] +[8.462846, "o", "\u0007"] +[8.495849, "o", "\u0007"] +[8.529853, "o", "\u0007"] +[8.561856, "o", "\u0007"] +[8.594859, "o", "\u0007"] +[8.627862, "o", "\u0007"] +[8.661866, "o", "\u0007"] +[8.693869, "o", "\u0007"] +[8.726872, "o", "\u0007"] +[9.20692, "o", "\u001b[?25l\u001b[?1c\u001b[40;1H\u001b[1m-- INSERT --\u001b[0m\u001b[40;13H\u001b[K\u001b[40;93H21,1\u001b[10CAll\u001b[23;1H\u001b[K\u001b[23;1H\u001b[?25h\u001b[?0c"] +[9.831983, "o", "\u001b[?25l\u001b[?1c\u001b[24;1H\u001b[K\u001b[40;94H2\u001b[24;1H\u001b[?25h\u001b[?0c"] +[10.047004, "o", "\u001b[?25l\u001b[?1ca\u001b[40;96H2\u001b[24;2H\u001b[?25h\u001b[?0c"] +[10.063006, "o", "\u001b[?25l\u001b[?1cs\u001b[40;96H3\u001b[24;3H\u001b[?25h\u001b[?0c"] +[10.167017, "o", "\u001b[?25l\u001b[?1cd\u001b[40;96H4\u001b[24;4H\u001b[?25h\u001b[?0c"] +[10.295029, "o", "\u001b[?25l\u001b[?1ca\u001b[40;96H5\u001b[24;5H\u001b[?25h\u001b[?0c"] +[10.383038, "o", "\u001b[?25l\u001b[?1cs\u001b[40;96H6\u001b[24;6H\u001b[?25h\u001b[?0c"] +[10.407041, "o", "\u001b[?25l\u001b[?1cd\u001b[40;96H7\u001b[24;7H\u001b[?25h\u001b[?0c"] +[10.624062, "o", "\u001b[?25l\u001b[?1c\u001b[25;1H\u001b[K\u001b[40;94H3,1\u001b[25;1H\u001b[?25h\u001b[?0c"] +[11.123112, "o", "\u001b[?25l\u001b[?1c\u001b[26;1H\u001b[K\u001b[40;94H4\u001b[26;1H\u001b[?25h\u001b[?0c"] +[11.156116, "o", "\u001b[?25l\u001b[?1c\u001b[27;1H\u001b[K\u001b[40;94H5\u001b[27;1H\u001b[?25h\u001b[?0c"] +[11.189119, "o", "\u001b[?25l\u001b[?1c\u001b[28;1H\u001b[K\u001b[40;94H6\u001b[28;1H\u001b[?25h\u001b[?0c"] +[11.222122, "o", "\u001b[?25l\u001b[?1c\u001b[29;1H\u001b[K\u001b[40;94H7\u001b[29;1H\u001b[?25h\u001b[?0c"] +[11.255125, "o", "\u001b[?25l\u001b[?1c\u001b[30;1H\u001b[K\u001b[40;94H8\u001b[30;1H\u001b[?25h\u001b[?0c"] +[11.335133, "o", "\u001b[?25l\u001b[?1c\u001b[31;1H\u001b[K\u001b[40;94H9\u001b[31;1H\u001b[?25h\u001b[?0c"] +[11.835183, "o", "\u001b[?25l\u001b[?1c\u001b[32;1H\u001b[K\u001b[40;93H30\u001b[32;1H\u001b[?25h\u001b[?0c"] +[11.868187, "o", "\u001b[?25l\u001b[?1c\u001b[33;1H\u001b[K\u001b[40;94H1\u001b[33;1H\u001b[?25h\u001b[?0c"] +[11.90119, "o", "\u001b[?25l\u001b[?1c\u001b[34;1H\u001b[K\u001b[40;94H2\u001b[34;1H\u001b[?25h\u001b[?0c"] +[11.934193, "o", "\u001b[?25l\u001b[?1c\u001b[35;1H\u001b[K\u001b[40;94H3\u001b[35;1H\u001b[?25h\u001b[?0c"] +[11.967196, "o", "\u001b[?25l\u001b[?1c\u001b[36;1H\u001b[K\u001b[40;94H4\u001b[36;1H\u001b[?25h\u001b[?0c"] +[12.0002, "o", "\u001b[?25l\u001b[?1c\u001b[37;1H\u001b[K\u001b[40;94H5\u001b[37;1H\u001b[?25h\u001b[?0c"] +[12.033203, "o", "\u001b[?25l\u001b[?1c\u001b[38;1H\u001b[K\u001b[40;94H6\u001b[38;1H\u001b[?25h\u001b[?0c"] +[12.066206, "o", "\u001b[?25l\u001b[?1c\u001b[39;1H\u001b[K\u001b[40;94H7\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.09921, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H38,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.132213, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H39,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.164216, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H40,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.19822, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H41,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.231223, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H42,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.264226, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H43,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.29723, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H44,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.330233, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H45,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.363236, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H46,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.396239, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H47,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.429243, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H48,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.462246, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[3M\u001b[1;40r\u001b[38;1H\u001b[1m\u001b[34m~ \u001b[39;1H~ \u001b[0m\u001b[40;93H\u001b[K\u001b[40;93H49,1\u001b[10CBot\u001b[37;1H\u001b[?25h\u001b[?0c"] +[12.495249, "o", "\u001b[?25l\u001b[?1c\u001b[38;1H\u001b[K\u001b[40;93H50\u001b[38;1H\u001b[?25h\u001b[?0c"] +[12.528253, "o", "\u001b[?25l\u001b[?1c\u001b[39;1H\u001b[K\u001b[40;94H1\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.561256, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H52,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.594259, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H53,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.627262, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H54,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.660266, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H55,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.693269, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H56,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.726273, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H57,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.759276, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H58,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.792279, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H59,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.825282, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H60,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.858285, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H61,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.891289, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H62,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[12.924292, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H63,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[13.120312, "o", "\u001b[?25l\u001b[?1ca\u001b[40;96H2\u001b[39;2H\u001b[?25h\u001b[?0c"] +[13.121312, "o", "\u001b[?25l\u001b[?1cs\u001b[40;96H3\u001b[39;3H\u001b[?25h\u001b[?0c"] +[13.20732, "o", "\u001b[?25l\u001b[?1cd\u001b[40;96H4\u001b[39;4H\u001b[?25h\u001b[?0c"] +[13.343334, "o", "\u001b[?25l\u001b[?1ca\u001b[40;96H5\u001b[39;5H\u001b[?25h\u001b[?0c"] +[13.527353, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H64,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[13.728372, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H65,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[13.895389, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[39;1H\r\n\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H66,1\u001b[10CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[14.113411, "o", "\u001b[40;1H\u001b[K\u001b[39;1H"] +[14.575457, "o", "\u001b[?25l\u001b[?1c\u001b[40;93H66,0-1\u001b[8CBot\u001b[39;1H\u001b[?25h\u001b[?0c\u001b[?25l\u001b[?1c\u001b[40;93H\u001b[K\u001b[40;1H:\u001b[?25h\u001b[?0c"] +[14.831483, "o", "w\u001b[?25l\u001b[?1c\u001b[?25h\u001b[?0c"] +[14.951495, "o", "q\u001b[?25l\u001b[?1c\u001b[?25h\u001b[?0c"] +[16.151615, "o", "\u001b[?25l\u001b[?1c\u001b[40;3H\u001b[K\u001b[40;3H\u001b[?25h\u001b[?0c"] +[16.535653, "o", "\r\u001b[?25l\u001b[?1c\"test.txt\""] +[16.538654, "o", " 66L, 331C written\u001b[64C66,0-1\u001b[8CBot\u001b[40;93H\u001b[K\u001b[40;93H66,0-1\u001b[8CBot\u001b[39;1H\u001b[?25h\u001b[?0c"] +[17.0077, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H5\u001b[38;1H\u001b[?25h\u001b[?0c"] +[17.50775, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H4\u001b[37;1H\u001b[?25h\u001b[?0c"] +[17.539754, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H3,1 \u001b[36;1H\u001b[?25h\u001b[?0c"] +[17.573757, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H2,0-1\u001b[35;1H\u001b[?25h\u001b[?0c"] +[17.606761, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H1\u001b[34;1H\u001b[?25h\u001b[?0c"] +[17.639764, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H0\u001b[33;1H\u001b[?25h\u001b[?0c"] +[17.672767, "o", "\u001b[?25l\u001b[?1c\u001b[40;93H59\u001b[32;1H\u001b[?25h\u001b[?0c"] +[17.70577, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H8\u001b[31;1H\u001b[?25h\u001b[?0c"] +[17.738774, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H7\u001b[30;1H\u001b[?25h\u001b[?0c"] +[17.771777, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H6\u001b[29;1H\u001b[?25h\u001b[?0c"] +[17.80478, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H5\u001b[28;1H\u001b[?25h\u001b[?0c"] +[17.837784, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H4\u001b[27;1H\u001b[?25h\u001b[?0c"] +[17.871787, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H3\u001b[26;1H\u001b[?25h\u001b[?0c"] +[17.90379, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H2\u001b[25;1H\u001b[?25h\u001b[?0c"] +[17.936793, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H1\u001b[24;1H\u001b[?25h\u001b[?0c"] +[17.969797, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H0\u001b[23;1H\u001b[?25h\u001b[?0c"] +[18.0028, "o", "\u001b[?25l\u001b[?1c\u001b[40;93H49\u001b[22;1H\u001b[?25h\u001b[?0c"] +[18.034803, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H8\u001b[21;1H\u001b[?25h\u001b[?0c"] +[18.068807, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H7\u001b[20;1H\u001b[?25h\u001b[?0c"] +[18.10081, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H6\u001b[19;1H\u001b[?25h\u001b[?0c"] +[18.134813, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H5\u001b[18;1H\u001b[?25h\u001b[?0c"] +[18.167816, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H4\u001b[17;1H\u001b[?25h\u001b[?0c"] +[18.20082, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H3\u001b[16;1H\u001b[?25h\u001b[?0c"] +[18.233823, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H2\u001b[15;1H\u001b[?25h\u001b[?0c"] +[18.266826, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H1\u001b[14;1H\u001b[?25h\u001b[?0c"] +[18.29983, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H0\u001b[13;1H\u001b[?25h\u001b[?0c"] +[18.332833, "o", "\u001b[?25l\u001b[?1c\u001b[40;93H39\u001b[12;1H\u001b[?25h\u001b[?0c"] +[18.365836, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H8\u001b[11;1H\u001b[?25h\u001b[?0c"] +[18.398839, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H7\u001b[10;1H\u001b[?25h\u001b[?0c"] +[18.431843, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H6\u001b[9;1H\u001b[?25h\u001b[?0c"] +[18.463846, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H5\u001b[8;1H\u001b[?25h\u001b[?0c"] +[18.496849, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H4\u001b[7;1H\u001b[?25h\u001b[?0c"] +[18.529853, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H3\u001b[6;1H\u001b[?25h\u001b[?0c"] +[18.562856, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H2\u001b[5;1H\u001b[?25h\u001b[?0c"] +[18.596859, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H1\u001b[4;1H\u001b[?25h\u001b[?0c"] +[18.629863, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H0\u001b[3;1H\u001b[?25h\u001b[?0c"] +[18.662866, "o", "\u001b[?25l\u001b[?1c\u001b[40;93H29\u001b[2;1H\u001b[?25h\u001b[?0c"] +[18.695869, "o", "\u001b[?25l\u001b[?1c\u001b[40;94H8\u001b[1;1H\u001b[?25h\u001b[?0c"] +[18.728873, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[40;1H\u001b[K\u001b[40;93H27,0-1\u001b[8C96%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[18.761876, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H26,0-1\u001b[8C92%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[18.794879, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H25,0-1\u001b[8C88%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[18.827883, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H24,0-1\u001b[8C85%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[18.860886, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H23,0-1\u001b[8C81%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[18.893889, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[1;1Hasdasd\u001b[40;93H\u001b[K\u001b[40;93H22,1\u001b[10C77%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[18.926892, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H21,0-1\u001b[8C74%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[18.959896, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[1;1H213123\u001b[40;93H\u001b[K\u001b[40;93H20,1\u001b[10C70%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[18.992899, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H19,0-1\u001b[8C66%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[19.025902, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H18,0-1\u001b[8C62%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[19.058906, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H17,0-1\u001b[8C59%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[19.091909, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[1;1H131\u001b[40;93H\u001b[K\u001b[40;93H16,1\u001b[10C55%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[19.124912, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H15,0-1\u001b[8C51%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[19.157915, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[1;1Hasdasdsada\u001b[40;93H\u001b[K\u001b[40;93H14,1\u001b[10C48%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[19.190919, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H13,0-1\u001b[8C44%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[19.223922, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[3L\u001b[1;40r\u001b[1;1Hasdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\u001b[2;1Haaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\u001b[3;1Haaaa\u001b[40;93H\u001b[K\u001b[40;93H12,1\u001b[10C37%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[19.256925, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H11,0-1\u001b[8C34%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[19.289929, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H10,0-1\u001b[8C31%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[19.322932, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H9,0-1\u001b[9C27%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[19.355935, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H8,0-1\u001b[9C24%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[19.388938, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H7,0-1\u001b[9C20%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[19.421942, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H6,0-1\u001b[9C17%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[19.454945, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H5,0-1\u001b[9C13%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[19.487948, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[1;1Hasdas\u001b[40;93H\u001b[K\u001b[40;93H4,1\u001b[11C10%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[19.520952, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[1;1H1212weq\u001b[40;93H\u001b[K\u001b[40;93H3,1\u001b[12C6%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[19.553955, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H2,0-1\u001b[10C3%\u001b[1;1H\u001b[?25h\u001b[?0c"] +[19.586958, "o", "\u001b[?25l\u001b[?1c\u001b[1;39r\u001b[1;1H\u001b[L\u001b[1;40r\u001b[40;93H\u001b[K\u001b[40;93H1,0-1\u001b[9CTop\u001b[1;1H\u001b[?25h\u001b[?0c"] +[19.618962, "o", "\u0007"] +[19.652965, "o", "\u0007"] +[19.684968, "o", "\u0007"] +[19.717971, "o", "\u0007"] +[19.750975, "o", "\u0007"] +[19.783978, "o", "\u0007"] +[19.816982, "o", "\u0007"] +[19.849985, "o", "\u0007"] +[19.883988, "o", "\u0007"] +[19.915991, "o", "\u0007"] +[19.948995, "o", "\u0007"] +[19.982998, "o", "\u0007"] +[20.015001, "o", "\u0007"] +[20.049005, "o", "\u0007"] +[20.528053, "o", "\u001b[?25l\u001b[?1c\u001b[40;1H\u001b[1m-- INSERT --\u001b[0m\u001b[40;93H\u001b[K\u001b[40;93H1,1\u001b[11CTop\u001b[1;1H\u001b[?25h\u001b[?0c"] +[20.640064, "o", "\u001b[?25l\u001b[?1ca\u001b[40;95H2\u001b[1;2H\u001b[?25h\u001b[?0c"] +[20.712071, "o", "\u001b[?25l\u001b[?1cs\u001b[40;95H3\u001b[1;3H\u001b[?25h\u001b[?0c"] +[20.760076, "o", "\u001b[?25l\u001b[?1cd\u001b[40;95H4\u001b[1;4H\u001b[?25h\u001b[?0c"] +[20.90409, "o", "\u001b[?25l\u001b[?1ca\u001b[40;95H5\u001b[1;5H\u001b[?25h\u001b[?0c"] +[21.0001, "o", "\u001b[?25l\u001b[?1cs\u001b[40;95H6\u001b[1;6H\u001b[?25h\u001b[?0c"] +[21.016101, "o", "\u001b[?25l\u001b[?1cd\u001b[40;95H7\u001b[1;7H\u001b[?25h\u001b[?0c"] +[21.152115, "o", "\u001b[?25l\u001b[?1ca\u001b[40;95H8\u001b[1;8H\u001b[?25h\u001b[?0c"] +[21.418141, "o", "\u001b[40;1H\u001b[K\u001b[1;7H"] +[22.256225, "o", "\u001b[?25l\u001b[?1c\u001b[40;93H1,7\u001b[11CTop\u001b[1;7H\u001b[?25h\u001b[?0c\u001b[?25l\u001b[?1c\u001b[40;93H\u001b[K\u001b[40;1H:\u001b[?25h\u001b[?0c"] +[22.472247, "o", "w\u001b[?25l\u001b[?1c\u001b[?25h\u001b[?0c"] +[22.576257, "o", "q\u001b[?25l\u001b[?1c\u001b[?25h\u001b[?0c"] +[22.912291, "o", "\r\u001b[?25l\u001b[?1c\"test.txt\""] +[22.914291, "o", " 66L, 338C written\r\u001b[?25h\u001b[?0c\r\r\n[root@k8s1 ~]# "] +[23.40034, "o", "l"] +[23.544354, "o", "l"] +[23.69837, "o", "\r\ntotal 19688\r\ndrwxr-xr-x 11 root root 317 Aug 27 12:42 \u001b[0m\u001b[01;34mcmdb\u001b[0m\r\ndrwxr-xr-x 14 root root 4096 Aug 23 11:33 \u001b[01;34mdevops\u001b[0m\r\n-rw-r--r-- 1 root root 20152008 Aug 23 11:35 \u001b[01;31mdevops.zip\u001b[0m\r\n-rw-r--r-- 1 root root 338 Aug 27 14:22 test.txt\r\n[root@k8s1 ~]# "] +[24.359436, "o", "e"] +[24.575457, "o", "x"] +[24.680468, "o", "i"] +[24.880488, "o", "t"] +[25.30553, "o", "\r\nlogout\r\n"] diff --git a/test.py b/test.py new file mode 100644 index 0000000..b0b3411 --- /dev/null +++ b/test.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +""" 初始化创建 admin 账号""" +import os +import sys + + +def main(): + # 使用django配置文件进行设置 + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'devops.settings') + + # 让django初始化 + import django + django.setup() + + from django.core.cache import cache + cache.set('test_123', ['x', 'y'], 600) + print(cache.get('test_123')) + print(type(cache.get('test_123'))) + + +if __name__ == '__main__': + main() diff --git a/user/__pycache__/urls.cpython-37.pyc b/user/__pycache__/urls.cpython-37.pyc index af3a81f..0a69f77 100644 Binary files a/user/__pycache__/urls.cpython-37.pyc and b/user/__pycache__/urls.cpython-37.pyc differ diff --git a/util/__pycache__/tool.cpython-37.pyc b/util/__pycache__/tool.cpython-37.pyc index e0a84d2..e1951ea 100644 Binary files a/util/__pycache__/tool.cpython-37.pyc and b/util/__pycache__/tool.cpython-37.pyc differ diff --git a/util/tool.py b/util/tool.py index 7da2ad8..cc50265 100644 --- a/util/tool.py +++ b/util/tool.py @@ -5,6 +5,7 @@ from functools import wraps import hashlib import time +import random try: @@ -56,3 +57,8 @@ def wrapper(request, *args, **kwargs): return func(request, *args, **kwargs) return wrapper + +# 生成随机字符串 +def gen_rand_char(length=10, chars='0123456789zyxwvutsrqponmlkjihgfedcbaZYXWVUTSRQPONMLKJIHGFEDCBA'): + return ''.join(random.sample(chars, length)) + diff --git a/websocket/__pycache__/routing.cpython-37.pyc b/websocket/__pycache__/routing.cpython-37.pyc index 2acca64..715ad1d 100644 Binary files a/websocket/__pycache__/routing.cpython-37.pyc and b/websocket/__pycache__/routing.cpython-37.pyc differ diff --git a/websocket/routing.py b/websocket/routing.py index c9343e0..ab4eba1 100644 --- a/websocket/routing.py +++ b/websocket/routing.py @@ -1,11 +1,12 @@ from django.urls import path # from webssh.websocket import WebSSH -from webssh.websocket_layer import WebSSH, WebSSH_view +from webssh.websocket_layer import WebSSH, WebSSH_view, CliSSH_view # from webtelnet.websocket import WebTelnet from webtelnet.websocket_layer import WebTelnet websocket_urlpatterns = [ path('webssh/', WebSSH), path('webssh/view/', WebSSH_view), + path('clissh/view/', CliSSH_view), path('webtelnet/', WebTelnet), ] diff --git a/webssh/__pycache__/admin.cpython-37.pyc b/webssh/__pycache__/admin.cpython-37.pyc index 0828c5b..1a157ca 100644 Binary files a/webssh/__pycache__/admin.cpython-37.pyc and b/webssh/__pycache__/admin.cpython-37.pyc differ diff --git a/webssh/__pycache__/forms.cpython-37.pyc b/webssh/__pycache__/forms.cpython-37.pyc index 7e4a70f..b4b4b71 100644 Binary files a/webssh/__pycache__/forms.cpython-37.pyc and b/webssh/__pycache__/forms.cpython-37.pyc differ diff --git a/webssh/__pycache__/models.cpython-37.pyc b/webssh/__pycache__/models.cpython-37.pyc index 0dadfc8..b53d616 100644 Binary files a/webssh/__pycache__/models.cpython-37.pyc and b/webssh/__pycache__/models.cpython-37.pyc differ diff --git a/webssh/__pycache__/ssh.cpython-37.pyc b/webssh/__pycache__/ssh.cpython-37.pyc index a7d24bf..58ad4d4 100644 Binary files a/webssh/__pycache__/ssh.cpython-37.pyc and b/webssh/__pycache__/ssh.cpython-37.pyc differ diff --git a/webssh/__pycache__/urls.cpython-37.pyc b/webssh/__pycache__/urls.cpython-37.pyc index bd8cf3e..f54030e 100644 Binary files a/webssh/__pycache__/urls.cpython-37.pyc and b/webssh/__pycache__/urls.cpython-37.pyc differ diff --git a/webssh/__pycache__/urls_api.cpython-37.pyc b/webssh/__pycache__/urls_api.cpython-37.pyc index 63a5191..d2180e6 100644 Binary files a/webssh/__pycache__/urls_api.cpython-37.pyc and b/webssh/__pycache__/urls_api.cpython-37.pyc differ diff --git a/webssh/__pycache__/views.cpython-37.pyc b/webssh/__pycache__/views.cpython-37.pyc index 31e157a..81ab8ec 100644 Binary files a/webssh/__pycache__/views.cpython-37.pyc and b/webssh/__pycache__/views.cpython-37.pyc differ diff --git a/webssh/__pycache__/views_api.cpython-37.pyc b/webssh/__pycache__/views_api.cpython-37.pyc index 0b2fc53..023522d 100644 Binary files a/webssh/__pycache__/views_api.cpython-37.pyc and b/webssh/__pycache__/views_api.cpython-37.pyc differ diff --git a/webssh/__pycache__/websocket.cpython-37.pyc b/webssh/__pycache__/websocket.cpython-37.pyc index 4137681..1f2467a 100644 Binary files a/webssh/__pycache__/websocket.cpython-37.pyc and b/webssh/__pycache__/websocket.cpython-37.pyc differ diff --git a/webssh/__pycache__/websocket_layer.cpython-37.pyc b/webssh/__pycache__/websocket_layer.cpython-37.pyc index 30aa050..8ea3c03 100644 Binary files a/webssh/__pycache__/websocket_layer.cpython-37.pyc and b/webssh/__pycache__/websocket_layer.cpython-37.pyc differ diff --git a/webssh/admin.py b/webssh/admin.py index a4c51e9..93f414c 100644 --- a/webssh/admin.py +++ b/webssh/admin.py @@ -1,5 +1,5 @@ from django.contrib import admin -from .models import TerminalLog, TerminalLogDetail, TerminalSession +from .models import TerminalLog, TerminalSession # Register your models here. admin.site.site_title = "运维管理系统" @@ -8,5 +8,4 @@ admin.site.register(TerminalLog) -admin.site.register(TerminalLogDetail) admin.site.register(TerminalSession) diff --git a/webssh/forms.py b/webssh/forms.py index 0c58dc2..cbfa508 100644 --- a/webssh/forms.py +++ b/webssh/forms.py @@ -5,6 +5,7 @@ class HostForm(forms.Form): hostid = forms.IntegerField(label="主机id") -class HostViewForm(forms.Form): +class SessionViewForm(forms.Form): sessionname = forms.CharField(label="会话名称") group = forms.CharField(label="会话组") + diff --git a/webssh/management/__init__.py b/webssh/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/webssh/management/__pycache__/__init__.cpython-37.pyc b/webssh/management/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000..57bc670 Binary files /dev/null and b/webssh/management/__pycache__/__init__.cpython-37.pyc differ diff --git a/webssh/management/commands/__init__.py b/webssh/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/webssh/management/commands/__pycache__/__init__.cpython-37.pyc b/webssh/management/commands/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000..e1f9a48 Binary files /dev/null and b/webssh/management/commands/__pycache__/__init__.cpython-37.pyc differ diff --git a/webssh/management/commands/__pycache__/proxy_sshd.cpython-37.pyc b/webssh/management/commands/__pycache__/proxy_sshd.cpython-37.pyc new file mode 100644 index 0000000..06ce745 Binary files /dev/null and b/webssh/management/commands/__pycache__/proxy_sshd.cpython-37.pyc differ diff --git a/webssh/management/commands/proxy_sshd.py b/webssh/management/commands/proxy_sshd.py new file mode 100644 index 0000000..8279956 --- /dev/null +++ b/webssh/management/commands/proxy_sshd.py @@ -0,0 +1,29 @@ +# coding=utf-8 + +# import traceback +# import time +# import json +from django.core.management.base import BaseCommand, CommandError +from django.conf import settings +# from cmdb.models import Host + +from webssh.sshd.sshd import SSHServer + + +class Command(BaseCommand): + # 生成SSH服务端,用于透明代理SSH + help = u'生成SSH透明代理服务器,类似堡垒机功能,使网站支持CRT,Xshell等SSH终端' + + # def add_arguments(self, parser): + # parser.add_argument('port', nargs='?', default='2222', type=int, + # help=u''' + # SSH监听端口,默认为2222 + # ''') + + def handle(self, *args, **options): + host = settings.PROXY_SSHD.get('listen_host', '0.0.0.0') + port = settings.PROXY_SSHD.get('listen_port', 2222) + cons = settings.PROXY_SSHD.get('cons', 250) + ssh_server = SSHServer(host, port, cons) + ssh_server.run() + diff --git a/webssh/migrations/0006_terminalsession_type.py b/webssh/migrations/0006_terminalsession_type.py new file mode 100644 index 0000000..f1d73b5 --- /dev/null +++ b/webssh/migrations/0006_terminalsession_type.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.3 on 2019-08-26 13:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('webssh', '0005_auto_20190816_1344'), + ] + + operations = [ + migrations.AddField( + model_name='terminalsession', + name='type', + field=models.SmallIntegerField(choices=[(1, 'webssh'), (2, 'websftp'), (3, 'clissh'), (4, 'clisftp'), (5, 'webtelnet'), (6, 'clitelnet')], default=1, verbose_name='类型'), + ), + ] diff --git a/webssh/migrations/0007_auto_20190827_0830.py b/webssh/migrations/0007_auto_20190827_0830.py new file mode 100644 index 0000000..0e942a0 --- /dev/null +++ b/webssh/migrations/0007_auto_20190827_0830.py @@ -0,0 +1,21 @@ +# Generated by Django 2.2.3 on 2019-08-27 08:30 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('webssh', '0006_terminalsession_type'), + ] + + operations = [ + migrations.AddField( + model_name='terminallog', + name='detail', + field=models.CharField(default='result', max_length=128, verbose_name='结果详情(文件名)'), + ), + migrations.DeleteModel( + name='TerminalLogDetail', + ), + ] diff --git a/webssh/migrations/__pycache__/0006_terminalsession_type.cpython-37.pyc b/webssh/migrations/__pycache__/0006_terminalsession_type.cpython-37.pyc new file mode 100644 index 0000000..3b84162 Binary files /dev/null and b/webssh/migrations/__pycache__/0006_terminalsession_type.cpython-37.pyc differ diff --git a/webssh/migrations/__pycache__/0007_auto_20190827_0830.cpython-37.pyc b/webssh/migrations/__pycache__/0007_auto_20190827_0830.cpython-37.pyc new file mode 100644 index 0000000..ce04add Binary files /dev/null and b/webssh/migrations/__pycache__/0007_auto_20190827_0830.cpython-37.pyc differ diff --git a/webssh/models.py b/webssh/models.py index 5191b9e..52e3506 100644 --- a/webssh/models.py +++ b/webssh/models.py @@ -10,6 +10,7 @@ class TerminalLog(models.Model): port = models.SmallIntegerField(default=22, verbose_name='端口') username = models.CharField(max_length=128, verbose_name="用户名") cmd = models.TextField('命令详情') + detail = models.CharField(max_length=128, default='result', verbose_name="结果详情(文件名)") address = models.GenericIPAddressField('IP地址', blank=True, null=True) useragent = models.CharField(max_length=512, blank=True, null=True, verbose_name='User_Agent') start_time = models.DateTimeField('会话开始时间') @@ -24,21 +25,6 @@ class Meta: verbose_name_plural = '在线会话日志' -class TerminalLogDetail(models.Model): - """ - 结果详情单独以一对一的关系表存储,提高查询速度 - """ - terminallog = models.OneToOneField('TerminalLog', blank=True, null=True, on_delete=models.PROTECT) - res = models.TextField('结果详情', default='未记录') - - def __str__(self): - return '{0}'.format(self.terminallog.user) - - class Meta: - verbose_name = '在线会话日志结果详情' - verbose_name_plural = '在线会话日志结果详情' - - class TerminalSession(models.Model): PROTOCOL_CHOICES = ( # 目前支持ssh, telnet (1, 'ssh'), @@ -48,8 +34,19 @@ class TerminalSession(models.Model): (5, 'sftp'), (6, 'ftp'), ) + + TYPE_CHOICES = ( + (1, 'webssh'), + (2, 'websftp'), + (3, 'clissh'), + (4, 'clisftp'), + (5, 'webtelnet'), + (6, 'clitelnet'), + ) + name = models.CharField(max_length=512, verbose_name='会话名称') group = models.CharField(default='chat_default', max_length=512, verbose_name='会话组') + type = models.SmallIntegerField(default=1, choices=TYPE_CHOICES, verbose_name='类型') user = models.CharField(max_length=128, verbose_name='用户') host = models.GenericIPAddressField(verbose_name='主机') port = models.SmallIntegerField(default=22, verbose_name='端口') diff --git a/webssh/ssh.py b/webssh/ssh.py index db36cb7..8c248af 100644 --- a/webssh/ssh.py +++ b/webssh/ssh.py @@ -4,8 +4,11 @@ from .tools import get_key_obj from asgiref.sync import async_to_sync import socket +from django.conf import settings import json import time +import traceback +from util.tool import gen_rand_char class SSH: @@ -15,10 +18,27 @@ def __init__(self, websocker, message): self.cmd = '' # 多行命令 self.cmd_tmp = '' # 一行命令 self.res = '' + self.tab_mode = False # 使用tab命令补全时需要读取返回数据然后添加到当前输入命令后 + self.history_mode = False + self.res_file = gen_rand_char(16) + '.txt' + self.start_time = time.time() + self.last_save_time = self.start_time + self.res_asciinema = [] + self.res_asciinema.append( + json.dumps( + { + "version": 2, + "width": 250, # 设置足够宽,以便播放时全屏不至于显示错乱 + "height": 40, + "timestamp": int(self.start_time), + "env": {"SHELL": "/bin/sh", "TERM": "linux"} + } + ) + ) # term 可以使用 ansi, linux, vt100, xterm, dumb,除了 dumb外其他都有颜色显示 def connect(self, host, user, password=None, ssh_key=None, port=22, timeout=30, - term='ansi', pty_width=80, pty_height=24): + term='linux', pty_width=80, pty_height=24): try: ssh_client = paramiko.SSHClient() ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) @@ -51,7 +71,10 @@ def connect(self, host, user, password=None, ssh_key=None, port=22, timeout=30, "text": message, }) self.res += recv - + + delay = round(time.time() - self.start_time, 6) + self.res_asciinema.append(json.dumps([delay, 'o', recv])) + # 创建3个线程将服务器返回的数据发送到django websocket(1个线程都可以) Thread(target=self.websocket_to_django).start() # Thread(target=self.websocket_to_django).start() @@ -61,6 +84,10 @@ def connect(self, host, user, password=None, ssh_key=None, port=22, timeout=30, self.message['message'] = 'Connection faild...' self.cmd += self.message['message'] self.res += self.message['message'] + + delay = round(time.time() - self.start_time, 6) + self.res_asciinema.append(json.dumps([delay, 'o', self.message['message']])) + message = json.dumps(self.message) if self.websocker.send_flag == 0: self.websocker.send(message) @@ -90,9 +117,22 @@ def django_to_ssh(self, data): if self.cmd_tmp.strip() != '': self.cmd_tmp += data self.cmd += self.cmd_tmp + + # print('-----------------------------------') + # print(self.cmd_tmp) + # print(self.cmd_tmp.encode()) + # print('-----------------------------------') + self.cmd_tmp = '' + elif data.encode() == b'\x07': + pass else: - self.cmd_tmp += data + if data == '\t' or data.encode() == b'\x1b': # \x1b 点击2下esc键也可以补全 + self.tab_mode = True + elif data.encode() == b'\x1b[A' or data.encode() == b'\x1b[B': + self.history_mode = True + else: + self.cmd_tmp += data except: self.close() @@ -105,6 +145,18 @@ def websocket_to_django(self): self.message['status'] = 0 self.message['message'] = data self.res += data + + delay = round(time.time() - self.start_time, 6) + self.res_asciinema.append(json.dumps([delay, 'o', data])) + # 250条结果或者指定秒数就保存一次,这个任务可以优化为使用 celery + if len(self.res_asciinema) > 250 or int(time.time() - self.last_save_time) > 30: + tmp = list(self.res_asciinema) + self.res_asciinema = [] + self.last_save_time = time.time() + with open(settings.TERMINAL_LOGS + '/' + self.res_file, 'a+') as f: + for line in tmp: + f.write('{}\n'.format(line)) + message = json.dumps(self.message) if self.websocker.send_flag == 0: self.websocker.send(message) @@ -113,6 +165,20 @@ def websocket_to_django(self): "type": "chat.message", "text": message, }) + if self.tab_mode: + tmp = data.split(' ') + # tab 只返回一个命令时匹配 + # print(tmp) + if len(tmp) == 2 and tmp[1] == '' and tmp[0] != '': + self.cmd_tmp = self.cmd_tmp + tmp[0].encode().replace(b'\x07', b'').decode() + elif len(tmp) == 1 and tmp[0].encode() != b'\x07': # \x07 蜂鸣声 + self.cmd_tmp = self.cmd_tmp + tmp[0].encode().replace(b'\x07', b'').decode() + self.tab_mode = False + if self.history_mode: # 不完善,只支持向上翻一个历史命令 + # print(data) + if data.strip() != '': + self.cmd_tmp = data + self.history_mode = False except: self.close() diff --git a/webssh/sshd/__init__.py b/webssh/sshd/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/webssh/sshd/__pycache__/__init__.cpython-37.pyc b/webssh/sshd/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000..07f6a99 Binary files /dev/null and b/webssh/sshd/__pycache__/__init__.cpython-37.pyc differ diff --git a/webssh/sshd/__pycache__/sftpinterface.cpython-37.pyc b/webssh/sshd/__pycache__/sftpinterface.cpython-37.pyc new file mode 100644 index 0000000..475abee Binary files /dev/null and b/webssh/sshd/__pycache__/sftpinterface.cpython-37.pyc differ diff --git a/webssh/sshd/__pycache__/sshd.cpython-37.pyc b/webssh/sshd/__pycache__/sshd.cpython-37.pyc new file mode 100644 index 0000000..c3af618 Binary files /dev/null and b/webssh/sshd/__pycache__/sshd.cpython-37.pyc differ diff --git a/webssh/sshd/__pycache__/sshinterface.cpython-37.pyc b/webssh/sshd/__pycache__/sshinterface.cpython-37.pyc new file mode 100644 index 0000000..c79bd7d Binary files /dev/null and b/webssh/sshd/__pycache__/sshinterface.cpython-37.pyc differ diff --git a/webssh/sshd/sftpinterface.py b/webssh/sshd/sftpinterface.py new file mode 100644 index 0000000..16bbb98 --- /dev/null +++ b/webssh/sshd/sftpinterface.py @@ -0,0 +1,206 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import errno +import os +import paramiko +from .sshinterface import transport_keepalive +import traceback +import warnings +warnings.filterwarnings("ignore") +paramiko.util.log_to_file('./paramiko.log') +from util.tool import gen_rand_char +# ssh_client ===>> proxy_ssh ==>> ssh_server +# ssh_client ===>> (proxy_server -> proxy_client) ==>> ssh_server + + +class SFTPInterface(paramiko.SFTPServerInterface): + def __init__(self, proxy_ssh, *largs, **kwargs): + # print(proxy_ssh, 999999999) + self.char = gen_rand_char(16) + super(SFTPInterface, self).__init__(proxy_ssh, *largs, **kwargs) + # import ipdb; ipdb.set_trace() + self.client, self.transport = self.get_sftp_proxy_client(proxy_ssh.ssh_args) + transport_keepalive(self.transport) + self.root_path = proxy_ssh.root_path if ('root_path' in proxy_ssh.__dict__) else '' + + def get_sftp_proxy_client(self, ssh_args): + # ssh_args = (ip, port, username, password) + # proxy_client ==>> sftp_server + # import ipdb; ipdb.set_trace() + # print ssh_args, 77777777777777 + host = ssh_args[0] + port = ssh_args[1] + username = ssh_args[2] + password = ssh_args[3] + t = paramiko.Transport((host, port)) + t.use_compression() # 开启压缩 + t.connect( + username=username, + password=password, + # gss_host=host, + ) + ssh_proxy_client = paramiko.SFTPClient.from_transport(t) + return ssh_proxy_client, t + + def session_ended(self): + # import ipdb; ipdb.set_trace() + print(self.char) + print('后端SFTP断开: %s@%s' % (self.transport.get_username(), self.transport.getpeername()[0])) + super(SFTPInterface, self).session_ended() + self.client.close() + self.transport.close() + + def _parsePath(self, path): + if not self.root_path: + return path + + # Prevent security violation when root_path provided + result = os.path.normpath(self.root_path + '/' + path) + if not result.startswith(self.root_path): + raise IOError(errno.EACCES) + return result + + def list_folder(self, path): + try: + filelist = self.client.listdir_attr(self._parsePath(path)) + # import ipdb; ipdb.set_trace() + # for fileattr in filelist: + # # Paramiko SFTP生成的用户/组是ID数值,改为字符 + # attrs = [s for s in fileattr.longname.split(' ') if s] + # if len(attrs) > 6: + # pass + # fileattr.st_uid = attrs[2] + # fileattr.st_gid = attrs[3] + return filelist + except IOError as e: + return paramiko.SFTPServer.convert_errno(e.errno) + + def stat(self, path): + try: + return self.client.stat(self._parsePath(path)) + except IOError as e: + return paramiko.SFTPServer.convert_errno(e.errno) + + def lstat(self, path): + try: + return self.client.lstat(self._parsePath(path)) + except IOError as e: + return paramiko.SFTPServer.convert_errno(e.errno) + + def open(self, path, flags, attr): + print('open-----------') + print(self.char) + print(path) + print(flags) + print(attr) + print('open-----------') + try: + if (flags & os.O_CREAT) and (attr is not None): + attr._flags &= ~attr.FLAG_PERMISSIONS + paramiko.SFTPServer.set_file_attr(self._parsePath(path), attr) + + if flags & os.O_WRONLY: + if flags & os.O_APPEND: + fstr = 'ab' + else: + fstr = 'wb' + elif flags & os.O_RDWR: + if flags & os.O_APPEND: + fstr = 'a+b' + else: + fstr = 'r+b' + else: + # O_RDONLY (== 0) + fstr = 'rb' + + f = self.client.open(self._parsePath(path), fstr) + + fobj = paramiko.SFTPHandle(flags) + fobj.filename = self._parsePath(path) + fobj.readfile = f + fobj.writefile = f + fobj.client = self.client + return fobj + + # TODO: verify (socket.error when stopping file upload/download) + except IOError as e: + return paramiko.SFTPServer.convert_errno(e.errno) + + def remove(self, path): + print('remove-----------') + print(self.char) + print(path) + print('remove-----------') + try: + self.client.remove(self._parsePath(path)) + except IOError as e: + return paramiko.SFTPServer.convert_errno(e.errno) + return paramiko.SFTP_OK + + def rename(self, oldpath, newpath): + print('rename-----------') + print(self.char) + print(oldpath) + print(newpath) + print('rename-----------') + try: + self.client.rename(self._parsePath(oldpath), self._parsePath(newpath)) + except IOError as e: + return paramiko.SFTPServer.convert_errno(e.errno) + return paramiko.SFTP_OK + + def mkdir(self, path, attr): + print('mkdir-----------') + print(self.char) + print(path) + print(attr) + print('mkdir-----------') + try: + if attr.st_mode is None: + self.client.mkdir(self._parsePath(path)) + else: + self.client.mkdir(self._parsePath(path), attr.st_mode) + except IOError as e: + return paramiko.SFTPServer.convert_errno(e.errno) + return paramiko.SFTP_OK + + def rmdir(self, path): + print('rmdir-----------') + print(self.char) + print(path) + print('rmdir-----------') + try: + self.client.rmdir(self._parsePath(path)) + except IOError as e: + return paramiko.SFTPServer.convert_errno(e.errno) + return paramiko.SFTP_OK + + def chattr(self, path, attr): + print('chattr-----------') + print(self.char) + print(path) + print(attr) + print('chattr-----------') + try: + if attr._flags & attr.FLAG_PERMISSIONS: + self.client.chmod(self._parsePath(path), attr.st_mode) + if attr._flags & attr.FLAG_UIDGID: + self.client.chown(self._parsePath(path), attr.st_uid, attr.st_gid) + if attr._flags & attr.FLAG_AMTIME: + self.client.utime(self._parsePath(path), (attr.st_atime, attr.st_mtime)) + if attr._flags & attr.FLAG_SIZE: + with self.client.open(self._parsePath(path), 'w+') as f: + f.truncate(attr.st_size) + except IOError as e: + return paramiko.SFTPServer.convert_errno(e.errno) + return paramiko.SFTP_OK + + def symlink(self, target_path, path): + return paramiko.SFTP_OP_UNSUPPORTED + + def readlink(self, path): + try: + return self.client.readlink(self._parsePath(path)) + except: + return paramiko.SFTP_OP_UNSUPPORTED diff --git a/webssh/sshd/ssh_proxy_rsa.key b/webssh/sshd/ssh_proxy_rsa.key new file mode 100644 index 0000000..117bc30 --- /dev/null +++ b/webssh/sshd/ssh_proxy_rsa.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA3C4OCuB++IhaDP70Wafm2Qebx/EYm9Sx00LEmRxaJYdeNlpi +35ik9blimJNQe3VYsKLJu7fM5I7q9TLQqG2T6gnUfUc/8ct6e2K9xOr8qBQaucWa +7+V/ZUOSw4vY6vW/jx9NVLV0L+I77EhdfhjBUs2R6V9djY5guUSxuI2030/XD0ms +fh00cvGvrE/DOgPI/LfeYgXKhzq/lEnyyl57FztADZex7CbxJLp2L8QERdqumPhY +rdC7yTSJcxKvgIbwFfE8XUDBT7g5fNzM0xT/ItSGzg1s7NPaeJ73bT4A6SqKQ4hq +rj9PjlVTe1Kct9SaoRTPgl/3TQAqEg7j55NL/QIDAQABAoIBAQCtPTtlSX/9suMP +qKa/yED1cGwc5FEVg0OrUrR3N/yh3KG/KFz1Sxg4EvZF0FsZ2JnA2UTbA2IeT2kF +JkdQzm78TWG4dJAWgqBLZsSjpLTI1pC0rIscyDj1hzZ5z5YMQPHI/bsNtHvHlTzK +y6FsLrQln4N32MY2M9lczHT9Hdo7fROzte8uMkQdNIG9yNHfkUNrvdOcSf2MmX7m +hij7JVRGJRgCVa5n/y2tqpih3/QES+DXAcfUmL9q+3CgnUz2mqmMXeGmTim2JRtI +AWCcWz9qS8IDt0TDYzRUtHwLPSlyQEYQbL0z9XUw4hNgYWh49J0BhOU5+LT7Gv5x +Buj6bzChAoGBAPF1RKhdK7QW12eSvFQUIn2EcLeRgltEsrVOmtoov0Jo+xRaB9Iz +bTClCmB4THsQQTiuBSBVzfgt33hfMls3/D1CvInPPf+/XEQFihibgMKvVehcfEql +KwDpHW9JbZ8LNKrrQLl0LW2N6AHEa29m85TaTcryVzvKZZUmJEjrbmR1AoGBAOlw +uc2IQS/RDQQ3phKwrgzYo8ZJfO1Df9D17qVJfmDht4i0zLs6dTPHGjOrt7+uCAvs +iSHXohLEzq09NkODbcnzNKC9pGOF1Ib2m3yt6og2nN3iTUUynWDG7ok1at9dhHqv +F5eQ95HU3HxDi+YB6Vkw76T8EwElCnx5yIc/uLhpAoGAOAYDhiUIDOL327o6JC// +yKvAE3eZjV+lL1grqc6mgdwl1ZUGF4mDHjRM8hE3fZ5J48LMwbHm9lx+a0l7P5r/ +1Z70a+0/72URHV9DqW37NDDGeAFtfUxRbAaqo7Wfz7Uj5TxsahtApxiz6iUO4Gw8 +vB7iyeHsx5ywcSjGZnzpwjkCgYEA47O3KUp8+11Y6wI1FgoM3C79IU9RckXjCTq6 +u7NCeNHzKn/hK8fLxuOxJTGcnHXvF2J0KPSi/NfIGaeZpKUwlEqMzTXugb1rHvKx +nB4wpQlQXgZ+BL9oT5v71Q6r3pDjxp+/zXH0auVM5FEmxwaaTQu01iOjjfxJjD1m +Yra/QfECgYBNXoAr7qxW0qV/gBUdiKo6VBqKO6EvFNHWXirB3I4bdSdW3v0uxoU9 +bLceYw6nZWwldfDH3iDCQuZSlhpSi1puH9A9bRm2ZRMAnd5ELTliv3n8jA6Bq2sQ +rfZuzWat8Ib7gi22uzcMLSJxPZLE+ix43Jrrk1k70JYwxu99erdknw== +-----END RSA PRIVATE KEY----- diff --git a/webssh/sshd/sshd.py b/webssh/sshd/sshd.py new file mode 100644 index 0000000..6449774 --- /dev/null +++ b/webssh/sshd/sshd.py @@ -0,0 +1,97 @@ +# coding=utf-8 +import os +import socket +import threading +import paramiko +from webssh.sshd.sftpinterface import SFTPInterface +from webssh.sshd.sshinterface import ServerInterface +import warnings +warnings.filterwarnings("ignore") +paramiko.util.log_to_file('./paramiko.log') + + +class SSHServer: + + def __init__(self, host, port, cons=100): + self.listen_host = host + self.listen_port = port + self.cons = cons + + @property + def host_key(self): + # ssh-keygen -t rsa -P '' -f '/root/.ssh/id_rsa' 快速生成密钥 + host_key_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'ssh_proxy_rsa.key') + if not os.path.isfile(host_key_path): + pass + return paramiko.RSAKey(filename=host_key_path) + + def run(self): + print('Starting ssh server at {}:{}'.format(self.listen_host, self.listen_port)) + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sock.bind((self.listen_host, self.listen_port)) + sock.listen(self.cons) + + while 1: + # import ipdb; ipdb.set_trace() + client, addr = sock.accept() # 阻塞等待客户端连接 + t = threading.Thread(target=self.handle_connection, args=(client, addr)) + t.daemon = True + t.start() + + def handle_connection(self, sock, addr): + transport = paramiko.Transport(sock, gss_kex=False) + transport.load_server_moduli() + + transport.add_server_key(self.host_key) + transport.set_subsystem_handler( + 'sftp', paramiko.SFTPServer, SFTPInterface + ) + # print('client socket:', addr) + proxy_ssh = ServerInterface() + + # import ipdb; ipdb.set_trace() + transport.start_server(server=proxy_ssh) # SSH时输密码 或 SFTP时调用子系统开启SFTP + # print('start Transport.start_server') + + while transport.is_active(): + chan_cli = transport.accept() + proxy_ssh.chan_cli = chan_cli + proxy_ssh.event.wait(10) # 等待 + if not chan_cli: + continue + + if not proxy_ssh.event.is_set(): + sock.close() + return + else: + proxy_ssh.event.clear() + + t = threading.Thread(target=self.dispatch, args=(proxy_ssh,)) + t.daemon = True + t.start() + + @staticmethod + def dispatch(proxy_ssh): + supported = {'pty', 'x11', 'forward-agent'} + chan_type = proxy_ssh.type + if chan_type in supported: + proxy_ssh.conn_ssh() # 连接后端真实SSH服务器 + proxy_ssh.bridge() # 链接SSH客户端和后端真实SSH服务器,进行数据交换,阻塞函数 + if not proxy_ssh.closed: # 避免重复记录操作记录 + proxy_ssh.close() + elif chan_type == 'subsystem': # sftp 连接 + # SFTP + pass + else: + msg = "Request type `{}` not support now".format(chan_type) + proxy_ssh.chan_cli.send(msg) + + +if __name__ == '__main__': + host = '0.0.0.0' + port = 2222 + cons = 250 # SSHD 连接数 + ssh_server = SSHServer(host, port, cons=cons) + ssh_server.run() + diff --git a/webssh/sshd/sshinterface.py b/webssh/sshd/sshinterface.py new file mode 100644 index 0000000..2d62e14 --- /dev/null +++ b/webssh/sshd/sshinterface.py @@ -0,0 +1,419 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import threading +import socket +import paramiko +import selectors2 as selectors # 基于 select 封装的多路复用 IO 库 +import time +import json +from django.core.cache import cache +import django.utils.timezone as timezone +from server.models import RemoteUserBindHost +from webssh.models import TerminalLog, TerminalSession +from util.tool import gen_rand_char +from channels.layers import get_channel_layer +from asgiref.sync import async_to_sync +from django.conf import settings +import traceback +import warnings +warnings.filterwarnings("ignore") +paramiko.util.log_to_file('./paramiko.log') + +# ssh_client ===>> proxy_ssh ==>> ssh_server +# ssh_client ===>> (proxy_server -> proxy_client) ==>> ssh_server + + +def terminal_log(user, hostname, ip, protocol, port, username, cmd, detail, address, useragent, start_time): + event = TerminalLog() + event.user = user + event.hostname = hostname + event.ip = ip + event.protocol = protocol + event.port = port + event.username = username + event.cmd = cmd + event.detail = detail + event.address = address + event.useragent = useragent + event.start_time = start_time + event.save() + + +def transport_keepalive(transport): + # 对后端transport每隔x秒发送空数据以保持连接 + # send_keepalive = CliSSH.get('send_keepalive', 0) + send_keepalive = 15 + transport.set_keepalive(send_keepalive) + + +class ServerInterface(paramiko.ServerInterface): + # proxy_ssh = (proxy_server + proxy_client) + def __init__(self): + self.event = threading.Event() + self.tty_args = ['?', 80, 40] # 终端参数(终端, 长, 宽) + # self.ssh_args = None # ssh连接参数 + self.ssh_args = None + self.type = None + self.http_user = None # 终端日志 -- http用户 + self.hostname = None # 后端主机名称 + self.password = None + self.hostid = None # 终端日志 -- hostid + self.closed = False + self.chan_cli = None + self.client = None + self.client_addr = None + self.group = 'session_' + gen_rand_char() + self.cmd = '' # 多行命令 + self.cmd_tmp = '' # 一行命令 + self.tab_mode = False # 使用tab命令补全时需要读取返回数据然后添加到当前输入命令后 + self.history_mode = False + self.res_file = gen_rand_char(16) + '.txt' + self.start_time = time.time() + self.log_start_time = timezone.now() + self.last_save_time = self.start_time + self.res_asciinema = [] + self.res_asciinema.append( + json.dumps( + { + "version": 2, + "width": 250, # 设置足够宽,以便播放时全屏不至于显示错乱 + "height": 40, + "timestamp": int(self.start_time), + "env": {"SHELL": "/bin/sh", "TERM": "linux"} + } + ) + ) + + def close_ssh_self(self, sleep_time=5): + try: + while 1: + time.sleep(sleep_time) # 每次循环暂停5秒,以免对 redis 造成压力 + if not cache.get('{}_{}_ssh_session'.format(self.http_user, self.password), False): + if not self.closed: + try: + self.chan_cli.send('\n\r系统管理员已强制中止了您的终端连接\r\n') + except: + pass + try: + self.close() + except: + pass + try: + # 发送数据给查看会话的 websocket 链接 + message = dict() + message['status'] = 2 + message['message'] = '\n\r系统管理员已强制中止了您的终端连接\r\n' + channel_layer = get_channel_layer() + async_to_sync(channel_layer.group_send)(self.group, { + "type": "chat.message", + "text": message, + }) + except: + pass + break + except: + pass + + def conn_ssh(self): + # proxy_client ==>> ssh_server + proxy_client = paramiko.SSHClient() + proxy_client.load_system_host_keys() + proxy_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + + try: + print("*** Connecting SSH (%s@%s) ...." % (self.ssh_args[2], self.ssh_args[0])) + proxy_client.connect(*self.ssh_args) + self.chan_ser = proxy_client.invoke_shell(*self.tty_args) + print("*** Connecting SSH ok") + + data = { + 'name': '{}_{}_ssh_session'.format(self.http_user, self.password), + 'group': self.group, + 'user': self.http_user, + 'host': self.ssh_args[0], + 'username': self.ssh_args[2], + 'protocol': 1, # 1 ssh + 'port': self.ssh_args[1], + 'type': 3, # 3 clissh + } + TerminalSession.objects.create(**data) + + # 设置连接到redis,使管理员可强制关闭软件终端 会话最大有效时间 30 天 + cache.set('{}_{}_ssh_session'.format(self.http_user, self.password), True, timeout=60 * 60 * 24 * 30) + t = threading.Thread(target=self.close_ssh_self) + t.daemon = True + t.start() + + try: + self.client = self.chan_cli.transport.remote_version + except: + self.client = 'clissh' + try: + self.client_addr = self.chan_cli.transport.sock.getpeername()[0] + except: + self.client_addr = '1.0.0.0' + + except BaseException: + print(traceback.format_exc()) + self.close() + + def bridge(self): + # 桥接 客户终端 和 代理服务终端 交互 + # transport_keepalive(self.chan_ser.transport) + sel = selectors.DefaultSelector() # Linux epol + sel.register(self.chan_cli, selectors.EVENT_READ) + sel.register(self.chan_ser, selectors.EVENT_READ) + while self.chan_ser and self.chan_cli and not (self.chan_ser.closed or self.chan_cli.closed): + events = sel.select(timeout=60) + for key, n in events: + if key.fileobj == self.chan_ser: + try: + recv_message = self.chan_ser.recv(1024) + if len(recv_message) == 0: + self.chan_cli.send("\r\n服务端已断开连接....\r\n") + time.sleep(1) + break + else: + try: + # 发送数据给查看会话的 websocket 组 + message = dict() + message['status'] = 0 + message['message'] = recv_message.decode('utf-8') + channel_layer = get_channel_layer() + async_to_sync(channel_layer.group_send)(self.group, { + "type": "chat.message", + "text": message, + }) + except: + pass + self.chan_cli.send(recv_message) + # 记录操作录像 + try: + """ + 防止 sz rz 传输文件时的报错 + """ + delay = round(time.time() - self.start_time, 6) + self.res_asciinema.append(json.dumps([delay, 'o', recv_message.decode('utf-8')])) + # 250条结果或者指定秒数就保存一次,这个任务可以优化为使用 celery + if len(self.res_asciinema) > 250 or int(time.time() - self.last_save_time) > 30: + tmp = list(self.res_asciinema) + self.res_asciinema = [] + self.last_save_time = time.time() + with open(settings.TERMINAL_LOGS + '/' + self.res_file, 'a+') as f: + for line in tmp: + f.write('{}\n'.format(line)) + except BaseException: + pass + except socket.timeout: + pass + if key.fileobj == self.chan_cli: + try: + send_message = self.chan_cli.recv(1024) + if len(send_message) == 0: + print("\r\n客户端断开了连接....\r\n") + time.sleep(1) + break + else: + self.chan_ser.send(send_message) + except socket.timeout: + pass + except socket.error: + break + + def close(self): + # 关闭ssh终端,必须分开 try 关闭,否则当强制关闭一方时,另一方连接可能被挂起 + try: + self.chan_cli.transport.close() + except: + pass + + try: + self.chan_ser.transport.close() + except: + pass + + try: + if self.res_asciinema: + terminal_log( + self.http_user, + self.hostname, + self.ssh_args[0], + 'ssh', + self.ssh_args[1], + self.ssh_args[2], + # self.ssh.cmd, + '', + self.res_file, + self.client_addr, # 客户端 ip + self.client, + self.log_start_time, + ) + except: + pass + + try: + tmp = list(self.res_asciinema) + self.res_asciinema = [] + with open(settings.TERMINAL_LOGS + '/' + self.res_file, 'a+') as f: + for line in tmp: + f.write('{}\n'.format(line)) + except: + pass + + try: + TerminalSession.objects.filter(name='{}_{}_ssh_session'.format(self.http_user, self.password)).delete() + except: + pass + + try: + # 发送数据给查看会话的 websocket 链接 + message = dict() + message['status'] = 1 + message['message'] = '\n\r连接已断开\r\n' + channel_layer = get_channel_layer() + async_to_sync(channel_layer.group_send)(self.group, { + "type": "chat.message", + "text": message, + }) + except: + pass + + try: + cache.delete('{}_{}_ssh_session'.format(self.http_user, self.password)) + except: + pass + + if not self.closed: + print('SSH ({0[2]}@{0[0]}) end..................'.format(self.ssh_args)) + self.closed = True + + def set_ssh_args(self, hostid): + # 准备proxy_client ==>> ssh_server连接参数,用于后续SSH、SFTP + remote_host = RemoteUserBindHost.objects.get(id=hostid) + self.hostname = remote_host.hostname + host = remote_host.ip + port = remote_host.port + user = remote_host.remote_user.username + passwd = remote_host.remote_user.password + # self.ssh_args = ('192.168.223.112', 22, 'root', '123456') + self.ssh_args = (host, port, user, passwd) + + def check_channel_request(self, kind, chanid): + """ + securecrt 和 xshell 会话克隆功能(包括 securecrt 的 sftp session)会在 + 同一个socket连接下(transport)开启多个channel,第一个channel id 为 0 后面 +1 递增 + 由于 paramiko 实现的 ssh server 在克隆会话后,被克隆的会话就无法操作了,解决方法还没研究出来, + 所以这里使用 and chanid is 0 禁止克隆会话(开启多个 channel) + """ + if kind == "session" and chanid is 0: + return paramiko.OPEN_SUCCEEDED + return paramiko.OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED + + def check_auth_password(self, http_user, password): + # 验证密码 + try: + self.http_user = http_user + self.password = password + return paramiko.AUTH_SUCCESSFUL + except BaseException: + return paramiko.AUTH_FAILED + + def check_auth_gssapi_keyex( + self, username, gss_authenticated=paramiko.AUTH_FAILED, cc_file=None + ): + if gss_authenticated == paramiko.AUTH_SUCCESSFUL: + return paramiko.AUTH_SUCCESSFUL + return paramiko.AUTH_FAILED + + def enable_auth_gssapi(self): + return True + + def get_allowed_auths(self, username): + return "gssapi-keyex,gssapi-with-mic,password,publickey" + + def check_channel_shell_request(self, channel): + self.event.set() + return True + + def check_channel_pty_request( + self, channel, term, width, height, pixelwidth, pixelheight, modes + ): + key = 'ssh_%s_%s' % (self.http_user, self.password) + key_ssh = 'ssh_%s_%s_ssh_count' % (self.http_user, self.password) + key_sftp = 'ssh_%s_%s_sftp_count' % (self.http_user, self.password) + try: + ssh_count = cache.get(key_ssh, 0) + sftp_count = cache.get(key_sftp, 0) + if ssh_count > 0: + hostid = cache.get(key) + cache.set(key_ssh, ssh_count - 1, timeout=60 * 60 * 24) + if hostid: + # cache.delete(key) + self.hostid = hostid + if not self.ssh_args: + self.set_ssh_args(self.hostid) + self.tty_args = [term, width, height] + self.type = 'pty' + else: + try: + if ssh_count == 0 and sftp_count == 0: + cache.delete(key) + cache.delete(key_ssh) + else: + cache.delete(key_ssh) + except: + pass + finally: + self.close() # 超过随机密码使用次数限制直接断开连接 + return True + except BaseException: + self.close() + + def check_channel_subsystem_request(self, channel, name): + # SFTP子系统 + # print(channel, name, 'subsystem') + key = 'ssh_%s_%s' % (self.http_user, self.password) + key_ssh = 'ssh_%s_%s_ssh_count' % (self.http_user, self.password) + key_sftp = 'ssh_%s_%s_sftp_count' % (self.http_user, self.password) + try: + ssh_count = cache.get(key_ssh, 0) + sftp_count = cache.get(key_sftp, 0) + if sftp_count > 0: + hostid = cache.get(key) + cache.set(key_sftp, sftp_count - 1, timeout=60 * 60 * 24) + if hostid: + # cache.delete(key) + self.hostid = hostid + if not self.ssh_args: + self.set_ssh_args(self.hostid) + self.type = 'subsystem' + self.event.set() + else: + try: + if ssh_count == 0 and sftp_count == 0: + cache.delete(key) + cache.delete(key_sftp) + else: + cache.delete(key_sftp) + except: + pass + finally: + self.close() # 超过随机密码使用次数限制直接断开连接 + return super(ServerInterface, self).check_channel_subsystem_request(channel, name) + except BaseException: + self.close() + + def check_channel_window_change_request(self, channel, width, height, + pixelwidth, pixelheight): + try: + self.chan_ser.resize_pty(width=width, height=height) # 必须 try 错误,否则在打开 xshell 后关闭,再连接会出错 + except BaseException: + pass + return True + + def check_channel_direct_tcpip_request(self, chan_id, origin, destination): + # SSH隧道 + self.type = 'direct-tcpip' + self.event.set() + return 0 diff --git a/webssh/urls.py b/webssh/urls.py index 1b067c8..a92edd4 100644 --- a/webssh/urls.py +++ b/webssh/urls.py @@ -6,8 +6,11 @@ urlpatterns = [ path('hosts/', views.hosts, name='hosts'), path('terminal/', views.terminal, name='terminal'), + path('terminal/cli/', views.terminal_cli, name='terminal_cli'), path('terminal/view/', views.terminal_view, name='terminal_view'), + path('terminal/clissh/view/', views.terminal_clissh_view, name='terminal_clissh_view'), path('logs/', views.logs, name='logs'), + path('test/', views.test, name='test'), path('sessions/', views.sessions, name='sessions'), ] diff --git a/webssh/urls_api.py b/webssh/urls_api.py index 87c9cde..2a815bf 100644 --- a/webssh/urls_api.py +++ b/webssh/urls_api.py @@ -5,5 +5,6 @@ app_name = "webssh" urlpatterns = [ path('session/close/', views_api.session_close, name='session_close'), + path('session/clissh/close/', views_api.session_clissh_close, name='session_clissh_close'), ] diff --git a/webssh/views.py b/webssh/views.py index d14e681..24cf8a1 100644 --- a/webssh/views.py +++ b/webssh/views.py @@ -1,73 +1,165 @@ -from django.shortcuts import render -from server.models import RemoteUserBindHost -from .models import TerminalLog, TerminalSession -from util.tool import login_required, post_required, admin_required -from django.http import JsonResponse -from django.db.models import Q -from .forms import HostForm, HostViewForm -from channels.layers import get_channel_layer -from asgiref.sync import async_to_sync -# Create your views here. - - -@login_required -def hosts(request): - if request.session['issuperuser']: - hosts = RemoteUserBindHost.objects.all() - else: - hosts = RemoteUserBindHost.objects.filter( - Q(user__username=request.session['username']) | Q(group__user__username=request.session['username']) - ).distinct() - return render(request, 'webssh/hosts.html', locals()) - - -@login_required -@post_required -def terminal(request): - host_form = HostForm(request.POST) - error_message = '请检查填写的内容!' - if host_form.is_valid(): - host_id = host_form.cleaned_data.get('hostid') - host = RemoteUserBindHost.objects.get(id=host_id) - return render(request, 'webssh/terminal.html', locals()) - - return JsonResponse({"code": 406, "err": error_message}) - - -@login_required -@admin_required -def logs(request): - logs = TerminalLog.objects.all() - return render(request, 'webssh/logs.html', locals()) - - -@login_required -@admin_required -def sessions(request): - sessions = TerminalSession.objects.all() - return render(request, 'webssh/sessions.html', locals()) - - -@login_required -@post_required -def terminal_view(request): - hostview_form = HostViewForm(request.POST) - error_message = '请检查填写的内容!' - if hostview_form.is_valid(): - name = hostview_form.cleaned_data.get('sessionname') - group = hostview_form.cleaned_data.get('group') - session = TerminalSession.objects.get(name=name, group=group) - return render(request, 'webssh/terminal_view.html', locals()) - - return JsonResponse({"code": 406, "err": error_message}) - - -# 每次重启时清空在线会话表 -def cls_terminalsession(): - try: - TerminalSession.objects.all().delete() - except: - pass - - -cls_terminalsession() +from django.shortcuts import render, HttpResponse +from server.models import RemoteUserBindHost +from .models import TerminalLog, TerminalSession +from util.tool import login_required, post_required, admin_required +from django.http import JsonResponse +from django.db.models import Q +from .forms import HostForm, SessionViewForm +from channels.layers import get_channel_layer +from asgiref.sync import async_to_sync +from util.tool import gen_rand_char +from django.core.cache import cache +from django.conf import settings +# Create your views here. + + +@login_required +def hosts(request): + if request.session['issuperuser']: + hosts = RemoteUserBindHost.objects.all() + else: + hosts = RemoteUserBindHost.objects.filter( + Q(user__username=request.session['username']) | Q(group__user__username=request.session['username']) + ).distinct() + return render(request, 'webssh/hosts.html', locals()) + + +@login_required +@post_required +def terminal(request): + host_form = HostForm(request.POST) + error_message = '请检查填写的内容!' + if host_form.is_valid(): + host_id = host_form.cleaned_data.get('hostid') + host = RemoteUserBindHost.objects.get(id=host_id) + return render(request, 'webssh/terminal.html', locals()) + + return JsonResponse({"code": 406, "err": error_message}) + + +@login_required +@post_required +def terminal_cli(request): + host_id = request.POST.get('hostid', None) + username = request.session.get('username') + password = gen_rand_char(16) # 生成随机密码 + terminal_type = 'ssh' + key = '%s_%s_%s' % (terminal_type, username, password) + key_ssh = '%s_%s_%s_ssh_count' % (terminal_type, username, password) + key_sftp = '%s_%s_%s_sftp_count' % (terminal_type, username, password) + cache.set(key, host_id, timeout=60 * 60 * 24) # 写入 redis 缓存以便 proxy_sshd 读取 + # 用于限制随机密码ssh和sftp登陆次数 + cache.set(key_ssh, 1, timeout=60 * 60 * 24) # 写入 redis 缓存以便 proxy_sshd 读取 + cache.set(key_sftp, 1, timeout=60 * 60 * 24) # 写入 redis 缓存以便 proxy_sshd 读取 + # Xshell.exe" ssh://网站用户:临时密码@堡垒机:端口 -newtab SSH用户/SSH主机 + # link = '{scheme}://{user}:{passwd}@{cmdb}:{port}\\" \\"-newtab\\" \\"{username}/{host}\\"' + host = RemoteUserBindHost.objects.get(pk=host_id) + + link_crt_ssh = '{scheme}://C:\\Program Files\\VanDyke Software\\Clients\\SecureCRT.exe /T /N "{username}@{host}" /SSH2 /L {user} /PASSWORD {passwd} {cmdb} /P {port}' + link_xshell_ssh = '{scheme}://C:\\Program Files (x86)\\NetSarang\\Xmanager Enterprise 5\\Xshell.exe -newtab "{username}@{host}" -url ssh://{user}:{passwd}@{cmdb}:{port}' + link_putty_ssh = '{scheme}://C:\\Users\\xx\\AppData\\Roaming\\TP4A\\Teleport-Assist\\tools\\putty\\putty.exe -l {user} -pw {passwd} {cmdb} -P {port}' + link_winscp_sftp = '{scheme}://C:\\Users\\xx\\AppData\\Roaming\\TP4A\\Teleport-Assist\\tools\\winscp\\WinSCP.exe /sessionname="{username}@{host}" {user}:{passwd}@{cmdb}:{port}' + clissh = 'link_crt_ssh' + + if clissh == 'link_crt_ssh': + return HttpResponse(link_crt_ssh.format( + scheme='apploader', + cmdb=request.META['HTTP_HOST'].split(':')[0], + port=settings.PROXY_SSHD.get('listen_port', 2222), + user=username, + passwd=password, + host=host.ip, + username=host.remote_user.username, + )) + elif clissh == 'link_xshell_ssh': + return HttpResponse(link_xshell_ssh.format( + scheme='apploader', # 自定义的网页调用外部软件(xshell)协议 + cmdb=request.META['HTTP_HOST'].split(':')[0], # xshell连接主机(cmdb堡垒机代理) + port=settings.PROXY_SSHD.get('listen_port', 2222), + user=username, # xshell连接主机的用户(cmdb堡垒机代理) + passwd=password, + host=host.ip, # xshell标签显示连接的主机(后端SSH实际主机) + username=host.remote_user.username, # xshell标签显示连接的用户(后端SSH实际用户) + )) + elif clissh == 'link_winscp_sftp': + return HttpResponse(link_winscp_sftp.format( + scheme='apploader', + cmdb=request.META['HTTP_HOST'].split(':')[0], + port=settings.PROXY_SSHD.get('listen_port', 2222), + user=username, + passwd=password, + host=host.ip, + username=host.remote_user.username, + )) + elif clissh in ('link_putty_ssh'): + return HttpResponse(link_putty_ssh.format( + scheme='apploader', + cmdb=request.META['HTTP_HOST'].split(':')[0], + port=settings.PROXY_SSHD.get('listen_port', 2222), + user=username, + passwd=password, + host=host.ip, + username=host.remote_user.username, + )) + + +@login_required +@admin_required +def logs(request): + logs = TerminalLog.objects.all() + return render(request, 'webssh/logs.html', locals()) + + +@login_required +@admin_required +def test(request): + log = TerminalLog.objects.get(pk=219) + return render(request, 'webssh/test.html', locals()) + + +@login_required +@admin_required +def sessions(request): + sessions = TerminalSession.objects.all() + return render(request, 'webssh/sessions.html', locals()) + + +@login_required +@admin_required +@post_required +def terminal_view(request): + sessionview_form = SessionViewForm(request.POST) + error_message = '请检查填写的内容!' + if sessionview_form.is_valid(): + name = sessionview_form.cleaned_data.get('sessionname') + group = sessionview_form.cleaned_data.get('group') + session = TerminalSession.objects.get(name=name, group=group) + return render(request, 'webssh/terminal_view.html', locals()) + + return JsonResponse({"code": 406, "err": error_message}) + + +@login_required +@admin_required +@post_required +def terminal_clissh_view(request): + sessionview_form = SessionViewForm(request.POST) + error_message = '请检查填写的内容!' + if sessionview_form.is_valid(): + name = sessionview_form.cleaned_data.get('sessionname') + group = sessionview_form.cleaned_data.get('group') + session = TerminalSession.objects.get(name=name, group=group) + return render(request, 'webssh/terminal_clissh_view.html', locals()) + + return JsonResponse({"code": 406, "err": error_message}) + + +# 每次重启时清空在线会话表 +def cls_terminalsession(): + try: + TerminalSession.objects.all().delete() + except: + pass + + +cls_terminalsession() diff --git a/webssh/views_api.py b/webssh/views_api.py index 5d9c5a9..4e24612 100644 --- a/webssh/views_api.py +++ b/webssh/views_api.py @@ -5,6 +5,7 @@ from util.tool import login_required, post_required, admin_required from channels.layers import get_channel_layer from asgiref.sync import async_to_sync +from django.core.cache import cache import time import traceback # Create your views here. @@ -38,7 +39,7 @@ def session_close(request): # }) async_to_sync(channel_layer.group_send)(group, { "type": "chat.message", - "text": '{"status":2, "message":"\\n\\rAdministrator forcibly interrupts your connection"}', + "text": '{"status":2, "message":"\\n\\r系统管理员已强制中止了您的终端连接"}', }) try: terminalsession.delete() @@ -51,3 +52,31 @@ def session_close(request): error_message = '未知错误!' return JsonResponse({"code": 401, "err": error_message}) + +@login_required +@admin_required +@post_required +def session_clissh_close(request): + pk = request.POST.get('id', None) + name = request.POST.get('session', None) + if not pk or not name: + error_message = '不合法的请求参数!' + return JsonResponse({"code": 400, "err": error_message}) + name = name.strip() + terminalsession = get_object_or_404(TerminalSession, pk=pk) + if terminalsession.name != name: + error_message = '不合法的请求参数!' + return JsonResponse({"code": 400, "err": error_message}) + try: + cache.delete(name) + try: + terminalsession.delete() + except BaseException: + pass + login_event_log(request.session.get('username'), 18, '会话 [{}] 强制停止成功'.format(terminalsession.name), + request.META.get('REMOTE_ADDR', None), request.META.get('HTTP_USER_AGENT', None)) + return JsonResponse({"code": 200, "err": ""}) + except BaseException: + error_message = '未知错误!' + return JsonResponse({"code": 401, "err": error_message}) + diff --git a/webssh/websocket.py b/webssh/websocket.py index 75a8864..6a02dd3 100644 --- a/webssh/websocket.py +++ b/webssh/websocket.py @@ -6,7 +6,7 @@ import django.utils.timezone as timezone from devops.settings import TMP_DIR from server.models import RemoteUserBindHost -from webssh.models import TerminalLog, TerminalLogDetail +from webssh.models import TerminalLog from django.db.models import Q import os import json @@ -19,7 +19,7 @@ session_exipry_time = 60 * 30 -def terminal_log(user, hostname, ip, protocol, port, username, cmd, res, address, useragent, start_time): +def terminal_log(user, hostname, ip, protocol, port, username, cmd, detail, address, useragent, start_time): event = TerminalLog() event.user = user event.hostname = hostname @@ -28,15 +28,11 @@ def terminal_log(user, hostname, ip, protocol, port, username, cmd, res, address event.port = port event.username = username event.cmd = cmd - # event.res = res + event.detail = detail event.address = address event.useragent = useragent event.start_time = start_time event.save() - event_detail = TerminalLogDetail() - event_detail.terminallog = event - event_detail.res = res - event_detail.save() class WebSSH(WebsocketConsumer): diff --git a/webssh/websocket_layer.py b/webssh/websocket_layer.py index cacd351..bbea20d 100644 --- a/webssh/websocket_layer.py +++ b/webssh/websocket_layer.py @@ -6,16 +6,16 @@ import django.utils.timezone as timezone from devops.settings import TMP_DIR from server.models import RemoteUserBindHost -from webssh.models import TerminalLog, TerminalLogDetail, TerminalSession +from webssh.models import TerminalLog, TerminalSession from django.db.models import Q +from django.core.cache import cache from channels.layers import get_channel_layer from asgiref.sync import async_to_sync import os import json -import re import time import traceback -import random +from util.tool import gen_rand_char try: session_exipry_time = settings.CUSTOM_SESSION_EXIPRY_TIME @@ -23,7 +23,7 @@ session_exipry_time = 60 * 30 -def terminal_log(user, hostname, ip, protocol, port, username, cmd, res, address, useragent, start_time): +def terminal_log(user, hostname, ip, protocol, port, username, cmd, detail, address, useragent, start_time): event = TerminalLog() event.user = user event.hostname = hostname @@ -32,15 +32,11 @@ def terminal_log(user, hostname, ip, protocol, port, username, cmd, res, address event.port = port event.username = username event.cmd = cmd - # event.res = res + event.detail = detail event.address = address event.useragent = useragent event.start_time = start_time event.save() - event_detail = TerminalLogDetail() - event_detail.terminallog = event - event_detail.res = res - event_detail.save() class WebSSH(WebsocketConsumer): @@ -60,7 +56,7 @@ def __init__(self, *args, **kwargs): self.remote_host = None self.start_time = None self.send_flag = 0 # 0 发送自身通道,1 发送 group 通道,作用为当管理员查看会话时,进入 group 通道 - self.group = 'session_' + ''.join(random.sample('zyxwvutsrqponmlkjihgfedcbaZYXWVUTSRQPONMLKJIHGFEDCBA', 10)) + self.group = 'session_' + gen_rand_char() def connect(self): """ @@ -188,6 +184,7 @@ def connect(self): 'username': user, 'protocol': self.remote_host.protocol, 'port': port, + 'type': 1, # 1 webssh } TerminalSession.objects.create(**data) @@ -201,13 +198,15 @@ def disconnect(self, close_code): pass finally: async_to_sync(self.channel_layer.group_discard)(self.group, self.channel_name) + try: + tmp = list(self.ssh.res_asciinema) + self.ssh.res_asciinema = [] + with open(settings.TERMINAL_LOGS + '/' + self.ssh.res_file, 'a+') as f: + for line in tmp: + f.write('{}\n'.format(line)) + except: + print(traceback.format_exc()) - # 过滤点结果中的颜色字符 - self.ssh.res = re.sub(r'(\[\d{2};\d{2}m|\[0m)', '', self.ssh.res) - # print('命令: ') - # print(self.ssh.cmd) - # print('结果: ') - # print(res) user_agent = None for i in self.scope['headers']: if i[0].decode('utf-8') == 'user-agent': @@ -222,7 +221,7 @@ def disconnect(self, close_code): self.remote_host.port, self.remote_host.remote_user.username, self.ssh.cmd, - self.ssh.res, + self.ssh.res_file, self.scope['client'][0], user_agent, self.start_time, @@ -354,3 +353,56 @@ def chat_message(self, data): except BaseException: print(traceback.format_exc()) + +class CliSSH_view(WebsocketConsumer): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.message = {'status': 0, 'message': None} + self.session = None + self.group = None + + def connect(self): + self.accept() + self.session = self.scope.get('session', None) + if not self.session.get('islogin', None): # 未登录直接断开 websocket 连接 + self.message['status'] = 2 + self.message['message'] = 'You are not login in...' + message = json.dumps(self.message) + self.send(message) + self.close() + query_string = self.scope.get('query_string').decode() + args = QueryDict(query_string=query_string, encoding='utf-8') + self.group = args.get('group') + # 把自身加入 cliwebssh 的组中 + async_to_sync(self.channel_layer.group_add)(self.group, self.channel_name) # 加入组 + + def disconnect(self, close_code): + try: + # 退出组 + async_to_sync(self.channel_layer.group_discard)(self.group, self.channel_name) + except: + pass + + def receive(self, text_data=None, bytes_data=None): + pass + + # 会话外使用 channels.layers 设置 type 为 chat.message 调用此函数 + def chat_message(self, data): + try: + # message = json.loads(data['text']) + message = data['text'] + if message['status'] == 0: + # self.send(data['text']) + self.send(json.dumps(data['text'])) + elif message['status'] == 1 or message['status'] == 2: # 会话关闭 + # self.send(data['text']) + self.send(json.dumps(data['text'])) + self.close() + elif message['status'] == 3: # 测试客户端显示消息框 + # self.send(data['text']) + self.send(json.dumps(data['text'])) + else: + pass + except BaseException: + print(traceback.format_exc()) + diff --git a/webtelnet/__pycache__/telnet.cpython-37.pyc b/webtelnet/__pycache__/telnet.cpython-37.pyc index 63d8736..5c0835b 100644 Binary files a/webtelnet/__pycache__/telnet.cpython-37.pyc and b/webtelnet/__pycache__/telnet.cpython-37.pyc differ diff --git a/webtelnet/__pycache__/websocket.cpython-37.pyc b/webtelnet/__pycache__/websocket.cpython-37.pyc index 18ae6ae..3b64a16 100644 Binary files a/webtelnet/__pycache__/websocket.cpython-37.pyc and b/webtelnet/__pycache__/websocket.cpython-37.pyc differ diff --git a/webtelnet/__pycache__/websocket_layer.cpython-37.pyc b/webtelnet/__pycache__/websocket_layer.cpython-37.pyc index a6131d4..92c344f 100644 Binary files a/webtelnet/__pycache__/websocket_layer.cpython-37.pyc and b/webtelnet/__pycache__/websocket_layer.cpython-37.pyc differ diff --git a/webtelnet/telnet.py b/webtelnet/telnet.py index 78166af..9c79833 100644 --- a/webtelnet/telnet.py +++ b/webtelnet/telnet.py @@ -2,6 +2,7 @@ from threading import Thread import json import time +from util.tool import gen_rand_char class Telnet: @@ -13,6 +14,7 @@ def __init__(self, websocker, message): self.message = message self.cmd = '' # 多行命令 self.cmd_tmp = '' # 一行命令 + self.res_file = gen_rand_char(16) + '.txt' self.res = '' self.tn = telnetlib.Telnet() diff --git a/webtelnet/websocket.py b/webtelnet/websocket.py index aa5fd8a..c9d5c36 100644 --- a/webtelnet/websocket.py +++ b/webtelnet/websocket.py @@ -4,7 +4,7 @@ from django.http.request import QueryDict import django.utils.timezone as timezone from server.models import RemoteUserBindHost -from webssh.models import TerminalLog, TerminalLogDetail +from webssh.models import TerminalLog from django.db.models import Q import json import time @@ -15,7 +15,7 @@ session_exipry_time = 60 * 30 -def terminal_log(user, hostname, ip, protocol, port, username, cmd, res, address, useragent, start_time): +def terminal_log(user, hostname, ip, protocol, port, username, cmd, detail, address, useragent, start_time): event = TerminalLog() event.user = user event.hostname = hostname @@ -24,15 +24,11 @@ def terminal_log(user, hostname, ip, protocol, port, username, cmd, res, address event.port = port event.username = username event.cmd = cmd - # event.res = res + event.detail = detail event.address = address event.useragent = useragent event.start_time = start_time event.save() - event_detail = TerminalLogDetail() - event_detail.terminallog = event - event_detail.res = res - event_detail.save() class WebTelnet(WebsocketConsumer): diff --git a/webtelnet/websocket_layer.py b/webtelnet/websocket_layer.py index 1513d07..6675530 100644 --- a/webtelnet/websocket_layer.py +++ b/webtelnet/websocket_layer.py @@ -4,7 +4,7 @@ from django.http.request import QueryDict import django.utils.timezone as timezone from server.models import RemoteUserBindHost -from webssh.models import TerminalLog, TerminalLogDetail, TerminalSession +from webssh.models import TerminalLog, TerminalSession from django.db.models import Q import json import time @@ -16,7 +16,7 @@ session_exipry_time = 60 * 30 -def terminal_log(user, hostname, ip, protocol, port, username, cmd, res, address, useragent, start_time): +def terminal_log(user, hostname, ip, protocol, port, username, cmd, detail, address, useragent, start_time): event = TerminalLog() event.user = user event.hostname = hostname @@ -25,15 +25,11 @@ def terminal_log(user, hostname, ip, protocol, port, username, cmd, res, address event.port = port event.username = username event.cmd = cmd - # event.res = res + event.detail = detail event.address = address event.useragent = useragent event.start_time = start_time event.save() - event_detail = TerminalLogDetail() - event_detail.terminallog = event - event_detail.res = res - event_detail.save() class WebTelnet(WebsocketConsumer): @@ -133,6 +129,7 @@ def connect(self): 'username': user, 'protocol': self.remote_host.protocol, 'port': port, + 'type': 5, # 5 webtelnet } TerminalSession.objects.create(**data) @@ -163,7 +160,7 @@ def disconnect(self, close_code): self.remote_host.port, self.remote_host.remote_user.username, self.telnet.cmd, - self.telnet.res, + self.telnet.res_file, self.scope['client'][0], user_agent, self.start_time,