You can subscribe to this list here.
2008 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(2) |
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2009 |
Jan
(3) |
Feb
(15) |
Mar
|
Apr
(9) |
May
|
Jun
(6) |
Jul
|
Aug
|
Sep
(23) |
Oct
(25) |
Nov
(44) |
Dec
(9) |
2010 |
Jan
(14) |
Feb
|
Mar
(4) |
Apr
(1) |
May
|
Jun
(3) |
Jul
|
Aug
(4) |
Sep
|
Oct
(10) |
Nov
(4) |
Dec
(22) |
2011 |
Jan
(14) |
Feb
|
Mar
(3) |
Apr
(7) |
May
(16) |
Jun
(4) |
Jul
(6) |
Aug
(3) |
Sep
|
Oct
(4) |
Nov
|
Dec
|
2012 |
Jan
|
Feb
|
Mar
(10) |
Apr
(24) |
May
|
Jun
|
Jul
(2) |
Aug
(2) |
Sep
|
Oct
|
Nov
|
Dec
|
From: <jh...@us...> - 2012-04-24 16:58:44
|
Revision: 316 http://etch.svn.sourceforge.net/etch/?rev=316&view=rev Author: jheiss Date: 2012-04-24 16:58:35 +0000 (Tue, 24 Apr 2012) Log Message: ----------- Fix syntax error in CSS file Modified Paths: -------------- trunk/server/app/assets/stylesheets/design.css Modified: trunk/server/app/assets/stylesheets/design.css =================================================================== --- trunk/server/app/assets/stylesheets/design.css 2012-04-21 04:22:22 UTC (rev 315) +++ trunk/server/app/assets/stylesheets/design.css 2012-04-24 16:58:35 UTC (rev 316) @@ -122,7 +122,7 @@ } -table.styled thead a { color: #fff; } +table.styled thead a { color: #fff; background-color: #666; @@ -213,7 +213,7 @@ .record_view .note { - color: grey; + color: #808080; font-weight: normal; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2012-04-21 04:22:32
|
Revision: 315 http://etch.svn.sourceforge.net/etch/?rev=315&view=rev Author: jheiss Date: 2012-04-21 04:22:22 +0000 (Sat, 21 Apr 2012) Log Message: ----------- Replace open flash chart graphs on dashboard with flot graph. Yay, no more flash. I never liked the way the dashboard looked with the status pie chart and the client count chart, and it looked even worse with the flot graphs. The status pie chart was a bit superfluous given that the same data is right there in the Client Summary. So I've commented it out for now. If someone misses it we'll figure out a way to display it without burning anyone's eyes. Otherwise we can toast the commented out bits at a later time. Modified Paths: -------------- trunk/server/app/assets/stylesheets/design.css trunk/server/app/controllers/dashboard_controller.rb trunk/server/app/views/dashboard/index.html.erb trunk/server/app/views/layouts/application.html.erb trunk/server/config/routes.rb Added Paths: ----------- trunk/server/app/assets/javascripts/dashboard.js.coffee trunk/server/app/assets/javascripts/jquery.flot.min.js trunk/server/app/assets/javascripts/jquery.flot.pie.min.js trunk/server/app/assets/stylesheets/dashboard.css.scss Removed Paths: ------------- trunk/server/app/assets/javascripts/swfobject.js trunk/server/app/views/dashboard/_client_chart.html.erb trunk/server/app/views/dashboard/_status_chart.html.erb trunk/server/vendor/plugins/open_flash_chart/ Added: trunk/server/app/assets/javascripts/dashboard.js.coffee =================================================================== --- trunk/server/app/assets/javascripts/dashboard.js.coffee (rev 0) +++ trunk/server/app/assets/javascripts/dashboard.js.coffee 2012-04-21 04:22:22 UTC (rev 315) @@ -0,0 +1,35 @@ +jQuery -> + # $.getJSON $("#status_chart").data("url"), (data) -> + # $.plot $("#status_chart"), data, { series: { pie: {show: true} } } + + $.getJSON $("#client_chart").data("url"), (data) -> + $.plot $("#client_chart"), data, { series: {lines: {show: true}, points: {show: true }}, xaxis: {mode: "time"}, legend: {position: 'nw'}, grid: {hoverable: true} } + + showTooltip = (x, y, contents) -> + $('<div id="tooltip">' + contents + '</div>').css( { + position: 'absolute', + display: 'none', + top: y + 5, + left: x + 5, + border: '1px solid #fdd', + padding: '2px', + 'background-color': '#fee', + opacity: 0.80 + }).appendTo("body").fadeIn(200) + + previousPoint = null + monthNames = [ "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" ] + $("#client_chart").bind "plothover", (event, pos, item) -> + $("#x").text pos.x.toFixed(2) + $("#y").text pos.y.toFixed(2) + if item + if previousPoint != item.dataIndex + previousPoint = item.dataIndex + $("#tooltip").remove() + d = new Date(item.datapoint[0]) + showTooltip(item.pageX, item.pageY, + monthNames[d.getMonth()] + " " + d.getDate() + " " + d.getFullYear() + ": " + item.datapoint[1] + " clients") + else + $("#tooltip").remove() + previousPoint = null Added: trunk/server/app/assets/javascripts/jquery.flot.min.js =================================================================== --- trunk/server/app/assets/javascripts/jquery.flot.min.js (rev 0) +++ trunk/server/app/assets/javascripts/jquery.flot.min.js 2012-04-21 04:22:22 UTC (rev 315) @@ -0,0 +1,6 @@ +/* Javascript plotting library for jQuery, v. 0.7. + * + * Released under the MIT license by IOLA, December 2007. + * + */ +(function(b){b.color={};b.color.make=function(d,e,g,f){var c={};c.r=d||0;c.g=e||0;c.b=g||0;c.a=f!=null?f:1;c.add=function(h,j){for(var k=0;k<h.length;++k){c[h.charAt(k)]+=j}return c.normalize()};c.scale=function(h,j){for(var k=0;k<h.length;++k){c[h.charAt(k)]*=j}return c.normalize()};c.toString=function(){if(c.a>=1){return"rgb("+[c.r,c.g,c.b].join(",")+")"}else{return"rgba("+[c.r,c.g,c.b,c.a].join(",")+")"}};c.normalize=function(){function h(k,j,l){return j<k?k:(j>l?l:j)}c.r=h(0,parseInt(c.r),255);c.g=h(0,parseInt(c.g),255);c.b=h(0,parseInt(c.b),255);c.a=h(0,c.a,1);return c};c.clone=function(){return b.color.make(c.r,c.b,c.g,c.a)};return c.normalize()};b.color.extract=function(d,e){var c;do{c=d.css(e).toLowerCase();if(c!=""&&c!="transparent"){break}d=d.parent()}while(!b.nodeName(d.get(0),"body"));if(c=="rgba(0, 0, 0, 0)"){c="transparent"}return b.color.parse(c)};b.color.parse=function(c){var d,f=b.color.make;if(d=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c)){return f(parseInt(d[1],10),parseInt(d[2],10),parseInt(d[3],10))}if(d=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(c)){return f(parseInt(d[1],10),parseInt(d[2],10),parseInt(d[3],10),parseFloat(d[4]))}if(d=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c)){return f(parseFloat(d[1])*2.55,parseFloat(d[2])*2.55,parseFloat(d[3])*2.55)}if(d=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(c)){return f(parseFloat(d[1])*2.55,parseFloat(d[2])*2.55,parseFloat(d[3])*2.55,parseFloat(d[4]))}if(d=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c)){return f(parseInt(d[1],16),parseInt(d[2],16),parseInt(d[3],16))}if(d=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c)){return f(parseInt(d[1]+d[1],16),parseInt(d[2]+d[2],16),parseInt(d[3]+d[3],16))}var e=b.trim(c).toLowerCase();if(e=="transparent"){return f(255,255,255,0)}else{d=a[e]||[0,0,0];return f(d[0],d[1],d[2])}};var a={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);(function(c){function b(av,ai,J,af){var Q=[],O={colors:["#edc240","#afd8f8","#cb4b4b","#4da74d","#9440ed"],legend:{show:true,noColumns:1,labelFormatter:null,labelBoxBorderColor:"#ccc",container:null,position:"ne",margin:5,backgroundColor:null,backgroundOpacity:0.85},xaxis:{show:null,position:"bottom",mode:null,color:null,tickColor:null,transform:null,inverseTransform:null,min:null,max:null,autoscaleMargin:null,ticks:null,tickFormatter:null,labelWidth:null,labelHeight:null,reserveSpace:null,tickLength:null,alignTicksWithAxis:null,tickDecimals:null,tickSize:null,minTickSize:null,monthNames:null,timeformat:null,twelveHourClock:false},yaxis:{autoscaleMargin:0.02,position:"left"},xaxes:[],yaxes:[],series:{points:{show:false,radius:3,lineWidth:2,fill:true,fillColor:"#ffffff",symbol:"circle"},lines:{lineWidth:2,fill:false,fillColor:null,steps:false},bars:{show:false,lineWidth:2,barWidth:1,fill:true,fillColor:null,align:"left",horizontal:false},shadowSize:3},grid:{show:true,aboveData:false,color:"#545454",backgroundColor:null,borderColor:null,tickColor:null,labelMargin:5,axisMargin:8,borderWidth:2,minBorderMargin:null,markings:null,markingsColor:"#f4f4f4",markingsLineWidth:2,clickable:false,hoverable:false,autoHighlight:true,mouseActiveRadius:10},hooks:{}},az=null,ad=null,y=null,H=null,A=null,p=[],aw=[],q={left:0,right:0,top:0,bottom:0},G=0,I=0,h=0,w=0,ak={processOptions:[],processRawData:[],processDatapoints:[],drawSeries:[],draw:[],bindEvents:[],drawOverlay:[],shutdown:[]},aq=this;aq.setData=aj;aq.setupGrid=t;aq.draw=W;aq.getPlaceholder=function(){return av};aq.getCanvas=function(){return az};aq.getPlotOffset=function(){return q};aq.width=function(){return h};aq.height=function(){return w};aq.offset=function(){var aB=y.offset();aB.left+=q.left;aB.top+=q.top;return aB};aq.getData=function(){return Q};aq.getAxes=function(){var aC={},aB;c.each(p.concat(aw),function(aD,aE){if(aE){aC[aE.direction+(aE.n!=1?aE.n:"")+"axis"]=aE}});return aC};aq.getXAxes=function(){return p};aq.getYAxes=function(){return aw};aq.c2p=C;aq.p2c=ar;aq.getOptions=function(){return O};aq.highlight=x;aq.unhighlight=T;aq.triggerRedrawOverlay=f;aq.pointOffset=function(aB){return{left:parseInt(p[aA(aB,"x")-1].p2c(+aB.x)+q.left),top:parseInt(aw[aA(aB,"y")-1].p2c(+aB.y)+q.top)}};aq.shutdown=ag;aq.resize=function(){B();g(az);g(ad)};aq.hooks=ak;F(aq);Z(J);X();aj(ai);t();W();ah();function an(aD,aB){aB=[aq].concat(aB);for(var aC=0;aC<aD.length;++aC){aD[aC].apply(this,aB)}}function F(){for(var aB=0;aB<af.length;++aB){var aC=af[aB];aC.init(aq);if(aC.options){c.extend(true,O,aC.options)}}}function Z(aC){var aB;c.extend(true,O,aC);if(O.xaxis.color==null){O.xaxis.color=O.grid.color}if(O.yaxis.color==null){O.yaxis.color=O.grid.color}if(O.xaxis.tickColor==null){O.xaxis.tickColor=O.grid.tickColor}if(O.yaxis.tickColor==null){O.yaxis.tickColor=O.grid.tickColor}if(O.grid.borderColor==null){O.grid.borderColor=O.grid.color}if(O.grid.tickColor==null){O.grid.tickColor=c.color.parse(O.grid.color).scale("a",0.22).toString()}for(aB=0;aB<Math.max(1,O.xaxes.length);++aB){O.xaxes[aB]=c.extend(true,{},O.xaxis,O.xaxes[aB])}for(aB=0;aB<Math.max(1,O.yaxes.length);++aB){O.yaxes[aB]=c.extend(true,{},O.yaxis,O.yaxes[aB])}if(O.xaxis.noTicks&&O.xaxis.ticks==null){O.xaxis.ticks=O.xaxis.noTicks}if(O.yaxis.noTicks&&O.yaxis.ticks==null){O.yaxis.ticks=O.yaxis.noTicks}if(O.x2axis){O.xaxes[1]=c.extend(true,{},O.xaxis,O.x2axis);O.xaxes[1].position="top"}if(O.y2axis){O.yaxes[1]=c.extend(true,{},O.yaxis,O.y2axis);O.yaxes[1].position="right"}if(O.grid.coloredAreas){O.grid.markings=O.grid.coloredAreas}if(O.grid.coloredAreasColor){O.grid.markingsColor=O.grid.coloredAreasColor}if(O.lines){c.extend(true,O.series.lines,O.lines)}if(O.points){c.extend(true,O.series.points,O.points)}if(O.bars){c.extend(true,O.series.bars,O.bars)}if(O.shadowSize!=null){O.series.shadowSize=O.shadowSize}for(aB=0;aB<O.xaxes.length;++aB){V(p,aB+1).options=O.xaxes[aB]}for(aB=0;aB<O.yaxes.length;++aB){V(aw,aB+1).options=O.yaxes[aB]}for(var aD in ak){if(O.hooks[aD]&&O.hooks[aD].length){ak[aD]=ak[aD].concat(O.hooks[aD])}}an(ak.processOptions,[O])}function aj(aB){Q=Y(aB);ax();z()}function Y(aE){var aC=[];for(var aB=0;aB<aE.length;++aB){var aD=c.extend(true,{},O.series);if(aE[aB].data!=null){aD.data=aE[aB].data;delete aE[aB].data;c.extend(true,aD,aE[aB]);aE[aB].data=aD.data}else{aD.data=aE[aB]}aC.push(aD)}return aC}function aA(aC,aD){var aB=aC[aD+"axis"];if(typeof aB=="object"){aB=aB.n}if(typeof aB!="number"){aB=1}return aB}function m(){return c.grep(p.concat(aw),function(aB){return aB})}function C(aE){var aC={},aB,aD;for(aB=0;aB<p.length;++aB){aD=p[aB];if(aD&&aD.used){aC["x"+aD.n]=aD.c2p(aE.left)}}for(aB=0;aB<aw.length;++aB){aD=aw[aB];if(aD&&aD.used){aC["y"+aD.n]=aD.c2p(aE.top)}}if(aC.x1!==undefined){aC.x=aC.x1}if(aC.y1!==undefined){aC.y=aC.y1}return aC}function ar(aF){var aD={},aC,aE,aB;for(aC=0;aC<p.length;++aC){aE=p[aC];if(aE&&aE.used){aB="x"+aE.n;if(aF[aB]==null&&aE.n==1){aB="x"}if(aF[aB]!=null){aD.left=aE.p2c(aF[aB]);break}}}for(aC=0;aC<aw.length;++aC){aE=aw[aC];if(aE&&aE.used){aB="y"+aE.n;if(aF[aB]==null&&aE.n==1){aB="y"}if(aF[aB]!=null){aD.top=aE.p2c(aF[aB]);break}}}return aD}function V(aC,aB){if(!aC[aB-1]){aC[aB-1]={n:aB,direction:aC==p?"x":"y",options:c.extend(true,{},aC==p?O.xaxis:O.yaxis)}}return aC[aB-1]}function ax(){var aG;var aM=Q.length,aB=[],aE=[];for(aG=0;aG<Q.length;++aG){var aJ=Q[aG].color;if(aJ!=null){--aM;if(typeof aJ=="number"){aE.push(aJ)}else{aB.push(c.color.parse(Q[aG].color))}}}for(aG=0;aG<aE.length;++aG){aM=Math.max(aM,aE[aG]+1)}var aC=[],aF=0;aG=0;while(aC.length<aM){var aI;if(O.colors.length==aG){aI=c.color.make(100,100,100)}else{aI=c.color.parse(O.colors[aG])}var aD=aF%2==1?-1:1;aI.scale("rgb",1+aD*Math.ceil(aF/2)*0.2);aC.push(aI);++aG;if(aG>=O.colors.length){aG=0;++aF}}var aH=0,aN;for(aG=0;aG<Q.length;++aG){aN=Q[aG];if(aN.color==null){aN.color=aC[aH].toString();++aH}else{if(typeof aN.color=="number"){aN.color=aC[aN.color].toString()}}if(aN.lines.show==null){var aL,aK=true;for(aL in aN){if(aN[aL]&&aN[aL].show){aK=false;break}}if(aK){aN.lines.show=true}}aN.xaxis=V(p,aA(aN,"x"));aN.yaxis=V(aw,aA(aN,"y"))}}function z(){var aO=Number.POSITIVE_INFINITY,aI=Number.NEGATIVE_INFINITY,aB=Number.MAX_VALUE,aU,aS,aR,aN,aD,aJ,aT,aP,aH,aG,aC,a0,aX,aL;function aF(a3,a2,a1){if(a2<a3.datamin&&a2!=-aB){a3.datamin=a2}if(a1>a3.datamax&&a1!=aB){a3.datamax=a1}}c.each(m(),function(a1,a2){a2.datamin=aO;a2.datamax=aI;a2.used=false});for(aU=0;aU<Q.length;++aU){aJ=Q[aU];aJ.datapoints={points:[]};an(ak.processRawData,[aJ,aJ.data,aJ.datapoints])}for(aU=0;aU<Q.length;++aU){aJ=Q[aU];var aZ=aJ.data,aW=aJ.datapoints.format;if(!aW){aW=[];aW.push({x:true,number:true,required:true});aW.push({y:true,number:true,required:true});if(aJ.bars.show||(aJ.lines.show&&aJ.lines.fill)){aW.push({y:true,number:true,required:false,defaultValue:0});if(aJ.bars.horizontal){delete aW[aW.length-1].y;aW[aW.length-1].x=true}}aJ.datapoints.format=aW}if(aJ.datapoints.pointsize!=null){continue}aJ.datapoints.pointsize=aW.length;aP=aJ.datapoints.pointsize;aT=aJ.datapoints.points;insertSteps=aJ.lines.show&&aJ.lines.steps;aJ.xaxis.used=aJ.yaxis.used=true;for(aS=aR=0;aS<aZ.length;++aS,aR+=aP){aL=aZ[aS];var aE=aL==null;if(!aE){for(aN=0;aN<aP;++aN){a0=aL[aN];aX=aW[aN];if(aX){if(aX.number&&a0!=null){a0=+a0;if(isNaN(a0)){a0=null}else{if(a0==Infinity){a0=aB}else{if(a0==-Infinity){a0=-aB}}}}if(a0==null){if(aX.required){aE=true}if(aX.defaultValue!=null){a0=aX.defaultValue}}}aT[aR+aN]=a0}}if(aE){for(aN=0;aN<aP;++aN){a0=aT[aR+aN];if(a0!=null){aX=aW[aN];if(aX.x){aF(aJ.xaxis,a0,a0)}if(aX.y){aF(aJ.yaxis,a0,a0)}}aT[aR+aN]=null}}else{if(insertSteps&&aR>0&&aT[aR-aP]!=null&&aT[aR-aP]!=aT[aR]&&aT[aR-aP+1]!=aT[aR+1]){for(aN=0;aN<aP;++aN){aT[aR+aP+aN]=aT[aR+aN]}aT[aR+1]=aT[aR-aP+1];aR+=aP}}}}for(aU=0;aU<Q.length;++aU){aJ=Q[aU];an(ak.processDatapoints,[aJ,aJ.datapoints])}for(aU=0;aU<Q.length;++aU){aJ=Q[aU];aT=aJ.datapoints.points,aP=aJ.datapoints.pointsize;var aK=aO,aQ=aO,aM=aI,aV=aI;for(aS=0;aS<aT.length;aS+=aP){if(aT[aS]==null){continue}for(aN=0;aN<aP;++aN){a0=aT[aS+aN];aX=aW[aN];if(!aX||a0==aB||a0==-aB){continue}if(aX.x){if(a0<aK){aK=a0}if(a0>aM){aM=a0}}if(aX.y){if(a0<aQ){aQ=a0}if(a0>aV){aV=a0}}}}if(aJ.bars.show){var aY=aJ.bars.align=="left"?0:-aJ.bars.barWidth/2;if(aJ.bars.horizontal){aQ+=aY;aV+=aY+aJ.bars.barWidth}else{aK+=aY;aM+=aY+aJ.bars.barWidth}}aF(aJ.xaxis,aK,aM);aF(aJ.yaxis,aQ,aV)}c.each(m(),function(a1,a2){if(a2.datamin==aO){a2.datamin=null}if(a2.datamax==aI){a2.datamax=null}})}function j(aB,aC){var aD=document.createElement("canvas");aD.className=aC;aD.width=G;aD.height=I;if(!aB){c(aD).css({position:"absolute",left:0,top:0})}c(aD).appendTo(av);if(!aD.getContext){aD=window.G_vmlCanvasManager.initElement(aD)}aD.getContext("2d").save();return aD}function B(){G=av.width();I=av.height();if(G<=0||I<=0){throw"Invalid dimensions for plot, width = "+G+", height = "+I}}function g(aC){if(aC.width!=G){aC.width=G}if(aC.height!=I){aC.height=I}var aB=aC.getContext("2d");aB.restore();aB.save()}function X(){var aC,aB=av.children("canvas.base"),aD=av.children("canvas.overlay");if(aB.length==0||aD==0){av.html("");av.css({padding:0});if(av.css("position")=="static"){av.css("position","relative")}B();az=j(true,"base");ad=j(false,"overlay");aC=false}else{az=aB.get(0);ad=aD.get(0);aC=true}H=az.getContext("2d");A=ad.getContext("2d");y=c([ad,az]);if(aC){av.data("plot").shutdown();aq.resize();A.clearRect(0,0,G,I);y.unbind();av.children().not([az,ad]).remove()}av.data("plot",aq)}function ah(){if(O.grid.hoverable){y.mousemove(aa);y.mouseleave(l)}if(O.grid.clickable){y.click(R)}an(ak.bindEvents,[y])}function ag(){if(M){clearTimeout(M)}y.unbind("mousemove",aa);y.unbind("mouseleave",l);y.unbind("click",R);an(ak.shutdown,[y])}function r(aG){function aC(aH){return aH}var aF,aB,aD=aG.options.transform||aC,aE=aG.options.inverseTransform;if(aG.direction=="x"){aF=aG.scale=h/Math.abs(aD(aG.max)-aD(aG.min));aB=Math.min(aD(aG.max),aD(aG.min))}else{aF=aG.scale=w/Math.abs(aD(aG.max)-aD(aG.min));aF=-aF;aB=Math.max(aD(aG.max),aD(aG.min))}if(aD==aC){aG.p2c=function(aH){return(aH-aB)*aF}}else{aG.p2c=function(aH){return(aD(aH)-aB)*aF}}if(!aE){aG.c2p=function(aH){return aB+aH/aF}}else{aG.c2p=function(aH){return aE(aB+aH/aF)}}}function L(aD){var aB=aD.options,aF,aJ=aD.ticks||[],aI=[],aE,aK=aB.labelWidth,aG=aB.labelHeight,aC;function aH(aM,aL){return c('<div style="position:absolute;top:-10000px;'+aL+'font-size:smaller"><div class="'+aD.direction+"Axis "+aD.direction+aD.n+'Axis">'+aM.join("")+"</div></div>").appendTo(av)}if(aD.direction=="x"){if(aK==null){aK=Math.floor(G/(aJ.length>0?aJ.length:1))}if(aG==null){aI=[];for(aF=0;aF<aJ.length;++aF){aE=aJ[aF].label;if(aE){aI.push('<div class="tickLabel" style="float:left;width:'+aK+'px">'+aE+"</div>")}}if(aI.length>0){aI.push('<div style="clear:left"></div>');aC=aH(aI,"width:10000px;");aG=aC.height();aC.remove()}}}else{if(aK==null||aG==null){for(aF=0;aF<aJ.length;++aF){aE=aJ[aF].label;if(aE){aI.push('<div class="tickLabel">'+aE+"</div>")}}if(aI.length>0){aC=aH(aI,"");if(aK==null){aK=aC.children().width()}if(aG==null){aG=aC.find("div.tickLabel").height()}aC.remove()}}}if(aK==null){aK=0}if(aG==null){aG=0}aD.labelWidth=aK;aD.labelHeight=aG}function au(aD){var aC=aD.labelWidth,aL=aD.labelHeight,aH=aD.options.position,aF=aD.options.tickLength,aG=O.grid.axisMargin,aJ=O.grid.labelMargin,aK=aD.direction=="x"?p:aw,aE;var aB=c.grep(aK,function(aN){return aN&&aN.options.position==aH&&aN.reserveSpace});if(c.inArray(aD,aB)==aB.length-1){aG=0}if(aF==null){aF="full"}var aI=c.grep(aK,function(aN){return aN&&aN.reserveSpace});var aM=c.inArray(aD,aI)==0;if(!aM&&aF=="full"){aF=5}if(!isNaN(+aF)){aJ+=+aF}if(aD.direction=="x"){aL+=aJ;if(aH=="bottom"){q.bottom+=aL+aG;aD.box={top:I-q.bottom,height:aL}}else{aD.box={top:q.top+aG,height:aL};q.top+=aL+aG}}else{aC+=aJ;if(aH=="left"){aD.box={left:q.left+aG,width:aC};q.left+=aC+aG}else{q.right+=aC+aG;aD.box={left:G-q.right,width:aC}}}aD.position=aH;aD.tickLength=aF;aD.box.padding=aJ;aD.innermost=aM}function U(aB){if(aB.direction=="x"){aB.box.left=q.left;aB.box.width=h}else{aB.box.top=q.top;aB.box.height=w}}function t(){var aC,aE=m();c.each(aE,function(aF,aG){aG.show=aG.options.show;if(aG.show==null){aG.show=aG.used}aG.reserveSpace=aG.show||aG.options.reserveSpace;n(aG)});allocatedAxes=c.grep(aE,function(aF){return aF.reserveSpace});q.left=q.right=q.top=q.bottom=0;if(O.grid.show){c.each(allocatedAxes,function(aF,aG){S(aG);P(aG);ap(aG,aG.ticks);L(aG)});for(aC=allocatedAxes.length-1;aC>=0;--aC){au(allocatedAxes[aC])}var aD=O.grid.minBorderMargin;if(aD==null){aD=0;for(aC=0;aC<Q.length;++aC){aD=Math.max(aD,Q[aC].points.radius+Q[aC].points.lineWidth/2)}}for(var aB in q){q[aB]+=O.grid.borderWidth;q[aB]=Math.max(aD,q[aB])}}h=G-q.left-q.right;w=I-q.bottom-q.top;c.each(aE,function(aF,aG){r(aG)});if(O.grid.show){c.each(allocatedAxes,function(aF,aG){U(aG)});k()}o()}function n(aE){var aF=aE.options,aD=+(aF.min!=null?aF.min:aE.datamin),aB=+(aF.max!=null?aF.max:aE.datamax),aH=aB-aD;if(aH==0){var aC=aB==0?1:0.01;if(aF.min==null){aD-=aC}if(aF.max==null||aF.min!=null){aB+=aC}}else{var aG=aF.autoscaleMargin;if(aG!=null){if(aF.min==null){aD-=aH*aG;if(aD<0&&aE.datamin!=null&&aE.datamin>=0){aD=0}}if(aF.max==null){aB+=aH*aG;if(aB>0&&aE.datamax!=null&&aE.datamax<=0){aB=0}}}}aE.min=aD;aE.max=aB}function S(aG){var aM=aG.options;var aH;if(typeof aM.ticks=="number"&&aM.ticks>0){aH=aM.ticks}else{aH=0.3*Math.sqrt(aG.direction=="x"?G:I)}var aT=(aG.max-aG.min)/aH,aO,aB,aN,aR,aS,aQ,aI;if(aM.mode=="time"){var aJ={second:1000,minute:60*1000,hour:60*60*1000,day:24*60*60*1000,month:30*24*60*60*1000,year:365.2425*24*60*60*1000};var aK=[[1,"second"],[2,"second"],[5,"second"],[10,"second"],[30,"second"],[1,"minute"],[2,"minute"],[5,"minute"],[10,"minute"],[30,"minute"],[1,"hour"],[2,"hour"],[4,"hour"],[8,"hour"],[12,"hour"],[1,"day"],[2,"day"],[3,"day"],[0.25,"month"],[0.5,"month"],[1,"month"],[2,"month"],[3,"month"],[6,"month"],[1,"year"]];var aC=0;if(aM.minTickSize!=null){if(typeof aM.tickSize=="number"){aC=aM.tickSize}else{aC=aM.minTickSize[0]*aJ[aM.minTickSize[1]]}}for(var aS=0;aS<aK.length-1;++aS){if(aT<(aK[aS][0]*aJ[aK[aS][1]]+aK[aS+1][0]*aJ[aK[aS+1][1]])/2&&aK[aS][0]*aJ[aK[aS][1]]>=aC){break}}aO=aK[aS][0];aN=aK[aS][1];if(aN=="year"){aQ=Math.pow(10,Math.floor(Math.log(aT/aJ.year)/Math.LN10));aI=(aT/aJ.year)/aQ;if(aI<1.5){aO=1}else{if(aI<3){aO=2}else{if(aI<7.5){aO=5}else{aO=10}}}aO*=aQ}aG.tickSize=aM.tickSize||[aO,aN];aB=function(aX){var a2=[],a0=aX.tickSize[0],a3=aX.tickSize[1],a1=new Date(aX.min);var aW=a0*aJ[a3];if(a3=="second"){a1.setUTCSeconds(a(a1.getUTCSeconds(),a0))}if(a3=="minute"){a1.setUTCMinutes(a(a1.getUTCMinutes(),a0))}if(a3=="hour"){a1.setUTCHours(a(a1.getUTCHours(),a0))}if(a3=="month"){a1.setUTCMonth(a(a1.getUTCMonth(),a0))}if(a3=="year"){a1.setUTCFullYear(a(a1.getUTCFullYear(),a0))}a1.setUTCMilliseconds(0);if(aW>=aJ.minute){a1.setUTCSeconds(0)}if(aW>=aJ.hour){a1.setUTCMinutes(0)}if(aW>=aJ.day){a1.setUTCHours(0)}if(aW>=aJ.day*4){a1.setUTCDate(1)}if(aW>=aJ.year){a1.setUTCMonth(0)}var a5=0,a4=Number.NaN,aY;do{aY=a4;a4=a1.getTime();a2.push(a4);if(a3=="month"){if(a0<1){a1.setUTCDate(1);var aV=a1.getTime();a1.setUTCMonth(a1.getUTCMonth()+1);var aZ=a1.getTime();a1.setTime(a4+a5*aJ.hour+(aZ-aV)*a0);a5=a1.getUTCHours();a1.setUTCHours(0)}else{a1.setUTCMonth(a1.getUTCMonth()+a0)}}else{if(a3=="year"){a1.setUTCFullYear(a1.getUTCFullYear()+a0)}else{a1.setTime(a4+aW)}}}while(a4<aX.max&&a4!=aY);return a2};aR=function(aV,aY){var a0=new Date(aV);if(aM.timeformat!=null){return c.plot.formatDate(a0,aM.timeformat,aM.monthNames)}var aW=aY.tickSize[0]*aJ[aY.tickSize[1]];var aX=aY.max-aY.min;var aZ=(aM.twelveHourClock)?" %p":"";if(aW<aJ.minute){fmt="%h:%M:%S"+aZ}else{if(aW<aJ.day){if(aX<2*aJ.day){fmt="%h:%M"+aZ}else{fmt="%b %d %h:%M"+aZ}}else{if(aW<aJ.month){fmt="%b %d"}else{if(aW<aJ.year){if(aX<aJ.year){fmt="%b"}else{fmt="%b %y"}}else{fmt="%y"}}}}return c.plot.formatDate(a0,fmt,aM.monthNames)}}else{var aU=aM.tickDecimals;var aP=-Math.floor(Math.log(aT)/Math.LN10);if(aU!=null&&aP>aU){aP=aU}aQ=Math.pow(10,-aP);aI=aT/aQ;if(aI<1.5){aO=1}else{if(aI<3){aO=2;if(aI>2.25&&(aU==null||aP+1<=aU)){aO=2.5;++aP}}else{if(aI<7.5){aO=5}else{aO=10}}}aO*=aQ;if(aM.minTickSize!=null&&aO<aM.minTickSize){aO=aM.minTickSize}aG.tickDecimals=Math.max(0,aU!=null?aU:aP);aG.tickSize=aM.tickSize||aO;aB=function(aX){var aZ=[];var a0=a(aX.min,aX.tickSize),aW=0,aV=Number.NaN,aY;do{aY=aV;aV=a0+aW*aX.tickSize;aZ.push(aV);++aW}while(aV<aX.max&&aV!=aY);return aZ};aR=function(aV,aW){return aV.toFixed(aW.tickDecimals)}}if(aM.alignTicksWithAxis!=null){var aF=(aG.direction=="x"?p:aw)[aM.alignTicksWithAxis-1];if(aF&&aF.used&&aF!=aG){var aL=aB(aG);if(aL.length>0){if(aM.min==null){aG.min=Math.min(aG.min,aL[0])}if(aM.max==null&&aL.length>1){aG.max=Math.max(aG.max,aL[aL.length-1])}}aB=function(aX){var aY=[],aV,aW;for(aW=0;aW<aF.ticks.length;++aW){aV=(aF.ticks[aW].v-aF.min)/(aF.max-aF.min);aV=aX.min+aV*(aX.max-aX.min);aY.push(aV)}return aY};if(aG.mode!="time"&&aM.tickDecimals==null){var aE=Math.max(0,-Math.floor(Math.log(aT)/Math.LN10)+1),aD=aB(aG);if(!(aD.length>1&&/\..*0$/.test((aD[1]-aD[0]).toFixed(aE)))){aG.tickDecimals=aE}}}}aG.tickGenerator=aB;if(c.isFunction(aM.tickFormatter)){aG.tickFormatter=function(aV,aW){return""+aM.tickFormatter(aV,aW)}}else{aG.tickFormatter=aR}}function P(aF){var aH=aF.options.ticks,aG=[];if(aH==null||(typeof aH=="number"&&aH>0)){aG=aF.tickGenerator(aF)}else{if(aH){if(c.isFunction(aH)){aG=aH({min:aF.min,max:aF.max})}else{aG=aH}}}var aE,aB;aF.ticks=[];for(aE=0;aE<aG.length;++aE){var aC=null;var aD=aG[aE];if(typeof aD=="object"){aB=+aD[0];if(aD.length>1){aC=aD[1]}}else{aB=+aD}if(aC==null){aC=aF.tickFormatter(aB,aF)}if(!isNaN(aB)){aF.ticks.push({v:aB,label:aC})}}}function ap(aB,aC){if(aB.options.autoscaleMargin&&aC.length>0){if(aB.options.min==null){aB.min=Math.min(aB.min,aC[0].v)}if(aB.options.max==null&&aC.length>1){aB.max=Math.max(aB.max,aC[aC.length-1].v)}}}function W(){H.clearRect(0,0,G,I);var aC=O.grid;if(aC.show&&aC.backgroundColor){N()}if(aC.show&&!aC.aboveData){ac()}for(var aB=0;aB<Q.length;++aB){an(ak.drawSeries,[H,Q[aB]]);d(Q[aB])}an(ak.draw,[H]);if(aC.show&&aC.aboveData){ac()}}function D(aB,aI){var aE,aH,aG,aD,aF=m();for(i=0;i<aF.length;++i){aE=aF[i];if(aE.direction==aI){aD=aI+aE.n+"axis";if(!aB[aD]&&aE.n==1){aD=aI+"axis"}if(aB[aD]){aH=aB[aD].from;aG=aB[aD].to;break}}}if(!aB[aD]){aE=aI=="x"?p[0]:aw[0];aH=aB[aI+"1"];aG=aB[aI+"2"]}if(aH!=null&&aG!=null&&aH>aG){var aC=aH;aH=aG;aG=aC}return{from:aH,to:aG,axis:aE}}function N(){H.save();H.translate(q.left,q.top);H.fillStyle=am(O.grid.backgroundColor,w,0,"rgba(255, 255, 255, 0)");H.fillRect(0,0,h,w);H.restore()}function ac(){var aF;H.save();H.translate(q.left,q.top);var aH=O.grid.markings;if(aH){if(c.isFunction(aH)){var aK=aq.getAxes();aK.xmin=aK.xaxis.min;aK.xmax=aK.xaxis.max;aK.ymin=aK.yaxis.min;aK.ymax=aK.yaxis.max;aH=aH(aK)}for(aF=0;aF<aH.length;++aF){var aD=aH[aF],aC=D(aD,"x"),aI=D(aD,"y");if(aC.from==null){aC.from=aC.axis.min}if(aC.to==null){aC.to=aC.axis.max}if(aI.from==null){aI.from=aI.axis.min}if(aI.to==null){aI.to=aI.axis.max}if(aC.to<aC.axis.min||aC.from>aC.axis.max||aI.to<aI.axis.min||aI.from>aI.axis.max){continue}aC.from=Math.max(aC.from,aC.axis.min);aC.to=Math.min(aC.to,aC.axis.max);aI.from=Math.max(aI.from,aI.axis.min);aI.to=Math.min(aI.to,aI.axis.max);if(aC.from==aC.to&&aI.from==aI.to){continue}aC.from=aC.axis.p2c(aC.from);aC.to=aC.axis.p2c(aC.to);aI.from=aI.axis.p2c(aI.from);aI.to=aI.axis.p2c(aI.to);if(aC.from==aC.to||aI.from==aI.to){H.beginPath();H.strokeStyle=aD.color||O.grid.markingsColor;H.lineWidth=aD.lineWidth||O.grid.markingsLineWidth;H.moveTo(aC.from,aI.from);H.lineTo(aC.to,aI.to);H.stroke()}else{H.fillStyle=aD.color||O.grid.markingsColor;H.fillRect(aC.from,aI.to,aC.to-aC.from,aI.from-aI.to)}}}var aK=m(),aM=O.grid.borderWidth;for(var aE=0;aE<aK.length;++aE){var aB=aK[aE],aG=aB.box,aQ=aB.tickLength,aN,aL,aP,aJ;if(!aB.show||aB.ticks.length==0){continue}H.strokeStyle=aB.options.tickColor||c.color.parse(aB.options.color).scale("a",0.22).toString();H.lineWidth=1;if(aB.direction=="x"){aN=0;if(aQ=="full"){aL=(aB.position=="top"?0:w)}else{aL=aG.top-q.top+(aB.position=="top"?aG.height:0)}}else{aL=0;if(aQ=="full"){aN=(aB.position=="left"?0:h)}else{aN=aG.left-q.left+(aB.position=="left"?aG.width:0)}}if(!aB.innermost){H.beginPath();aP=aJ=0;if(aB.direction=="x"){aP=h}else{aJ=w}if(H.lineWidth==1){aN=Math.floor(aN)+0.5;aL=Math.floor(aL)+0.5}H.moveTo(aN,aL);H.lineTo(aN+aP,aL+aJ);H.stroke()}H.beginPath();for(aF=0;aF<aB.ticks.length;++aF){var aO=aB.ticks[aF].v;aP=aJ=0;if(aO<aB.min||aO>aB.max||(aQ=="full"&&aM>0&&(aO==aB.min||aO==aB.max))){continue}if(aB.direction=="x"){aN=aB.p2c(aO);aJ=aQ=="full"?-w:aQ;if(aB.position=="top"){aJ=-aJ}}else{aL=aB.p2c(aO);aP=aQ=="full"?-h:aQ;if(aB.position=="left"){aP=-aP}}if(H.lineWidth==1){if(aB.direction=="x"){aN=Math.floor(aN)+0.5}else{aL=Math.floor(aL)+0.5}}H.moveTo(aN,aL);H.lineTo(aN+aP,aL+aJ)}H.stroke()}if(aM){H.lineWidth=aM;H.strokeStyle=O.grid.borderColor;H.strokeRect(-aM/2,-aM/2,h+aM,w+aM)}H.restore()}function k(){av.find(".tickLabels").remove();var aG=['<div class="tickLabels" style="font-size:smaller">'];var aJ=m();for(var aD=0;aD<aJ.length;++aD){var aC=aJ[aD],aF=aC.box;if(!aC.show){continue}aG.push('<div class="'+aC.direction+"Axis "+aC.direction+aC.n+'Axis" style="color:'+aC.options.color+'">');for(var aE=0;aE<aC.ticks.length;++aE){var aH=aC.ticks[aE];if(!aH.label||aH.v<aC.min||aH.v>aC.max){continue}var aK={},aI;if(aC.direction=="x"){aI="center";aK.left=Math.round(q.left+aC.p2c(aH.v)-aC.labelWidth/2);if(aC.position=="bottom"){aK.top=aF.top+aF.padding}else{aK.bottom=I-(aF.top+aF.height-aF.padding)}}else{aK.top=Math.round(q.top+aC.p2c(aH.v)-aC.labelHeight/2);if(aC.position=="left"){aK.right=G-(aF.left+aF.width-aF.padding);aI="right"}else{aK.left=aF.left+aF.padding;aI="left"}}aK.width=aC.labelWidth;var aB=["position:absolute","text-align:"+aI];for(var aL in aK){aB.push(aL+":"+aK[aL]+"px")}aG.push('<div class="tickLabel" style="'+aB.join(";")+'">'+aH.label+"</div>")}aG.push("</div>")}aG.push("</div>");av.append(aG.join(""))}function d(aB){if(aB.lines.show){at(aB)}if(aB.bars.show){e(aB)}if(aB.points.show){ao(aB)}}function at(aE){function aD(aP,aQ,aI,aU,aT){var aV=aP.points,aJ=aP.pointsize,aN=null,aM=null;H.beginPath();for(var aO=aJ;aO<aV.length;aO+=aJ){var aL=aV[aO-aJ],aS=aV[aO-aJ+1],aK=aV[aO],aR=aV[aO+1];if(aL==null||aK==null){continue}if(aS<=aR&&aS<aT.min){if(aR<aT.min){continue}aL=(aT.min-aS)/(aR-aS)*(aK-aL)+aL;aS=aT.min}else{if(aR<=aS&&aR<aT.min){if(aS<aT.min){continue}aK=(aT.min-aS)/(aR-aS)*(aK-aL)+aL;aR=aT.min}}if(aS>=aR&&aS>aT.max){if(aR>aT.max){continue}aL=(aT.max-aS)/(aR-aS)*(aK-aL)+aL;aS=aT.max}else{if(aR>=aS&&aR>aT.max){if(aS>aT.max){continue}aK=(aT.max-aS)/(aR-aS)*(aK-aL)+aL;aR=aT.max}}if(aL<=aK&&aL<aU.min){if(aK<aU.min){continue}aS=(aU.min-aL)/(aK-aL)*(aR-aS)+aS;aL=aU.min}else{if(aK<=aL&&aK<aU.min){if(aL<aU.min){continue}aR=(aU.min-aL)/(aK-aL)*(aR-aS)+aS;aK=aU.min}}if(aL>=aK&&aL>aU.max){if(aK>aU.max){continue}aS=(aU.max-aL)/(aK-aL)*(aR-aS)+aS;aL=aU.max}else{if(aK>=aL&&aK>aU.max){if(aL>aU.max){continue}aR=(aU.max-aL)/(aK-aL)*(aR-aS)+aS;aK=aU.max}}if(aL!=aN||aS!=aM){H.moveTo(aU.p2c(aL)+aQ,aT.p2c(aS)+aI)}aN=aK;aM=aR;H.lineTo(aU.p2c(aK)+aQ,aT.p2c(aR)+aI)}H.stroke()}function aF(aI,aQ,aP){var aW=aI.points,aV=aI.pointsize,aN=Math.min(Math.max(0,aP.min),aP.max),aX=0,aU,aT=false,aM=1,aL=0,aR=0;while(true){if(aV>0&&aX>aW.length+aV){break}aX+=aV;var aZ=aW[aX-aV],aK=aW[aX-aV+aM],aY=aW[aX],aJ=aW[aX+aM];if(aT){if(aV>0&&aZ!=null&&aY==null){aR=aX;aV=-aV;aM=2;continue}if(aV<0&&aX==aL+aV){H.fill();aT=false;aV=-aV;aM=1;aX=aL=aR+aV;continue}}if(aZ==null||aY==null){continue}if(aZ<=aY&&aZ<aQ.min){if(aY<aQ.min){continue}aK=(aQ.min-aZ)/(aY-aZ)*(aJ-aK)+aK;aZ=aQ.min}else{if(aY<=aZ&&aY<aQ.min){if(aZ<aQ.min){continue}aJ=(aQ.min-aZ)/(aY-aZ)*(aJ-aK)+aK;aY=aQ.min}}if(aZ>=aY&&aZ>aQ.max){if(aY>aQ.max){continue}aK=(aQ.max-aZ)/(aY-aZ)*(aJ-aK)+aK;aZ=aQ.max}else{if(aY>=aZ&&aY>aQ.max){if(aZ>aQ.max){continue}aJ=(aQ.max-aZ)/(aY-aZ)*(aJ-aK)+aK;aY=aQ.max}}if(!aT){H.beginPath();H.moveTo(aQ.p2c(aZ),aP.p2c(aN));aT=true}if(aK>=aP.max&&aJ>=aP.max){H.lineTo(aQ.p2c(aZ),aP.p2c(aP.max));H.lineTo(aQ.p2c(aY),aP.p2c(aP.max));continue}else{if(aK<=aP.min&&aJ<=aP.min){H.lineTo(aQ.p2c(aZ),aP.p2c(aP.min));H.lineTo(aQ.p2c(aY),aP.p2c(aP.min));continue}}var aO=aZ,aS=aY;if(aK<=aJ&&aK<aP.min&&aJ>=aP.min){aZ=(aP.min-aK)/(aJ-aK)*(aY-aZ)+aZ;aK=aP.min}else{if(aJ<=aK&&aJ<aP.min&&aK>=aP.min){aY=(aP.min-aK)/(aJ-aK)*(aY-aZ)+aZ;aJ=aP.min}}if(aK>=aJ&&aK>aP.max&&aJ<=aP.max){aZ=(aP.max-aK)/(aJ-aK)*(aY-aZ)+aZ;aK=aP.max}else{if(aJ>=aK&&aJ>aP.max&&aK<=aP.max){aY=(aP.max-aK)/(aJ-aK)*(aY-aZ)+aZ;aJ=aP.max}}if(aZ!=aO){H.lineTo(aQ.p2c(aO),aP.p2c(aK))}H.lineTo(aQ.p2c(aZ),aP.p2c(aK));H.lineTo(aQ.p2c(aY),aP.p2c(aJ));if(aY!=aS){H.lineTo(aQ.p2c(aY),aP.p2c(aJ));H.lineTo(aQ.p2c(aS),aP.p2c(aJ))}}}H.save();H.translate(q.left,q.top);H.lineJoin="round";var aG=aE.lines.lineWidth,aB=aE.shadowSize;if(aG>0&&aB>0){H.lineWidth=aB;H.strokeStyle="rgba(0,0,0,0.1)";var aH=Math.PI/18;aD(aE.datapoints,Math.sin(aH)*(aG/2+aB/2),Math.cos(aH)*(aG/2+aB/2),aE.xaxis,aE.yaxis);H.lineWidth=aB/2;aD(aE.datapoints,Math.sin(aH)*(aG/2+aB/4),Math.cos(aH)*(aG/2+aB/4),aE.xaxis,aE.yaxis)}H.lineWidth=aG;H.strokeStyle=aE.color;var aC=ae(aE.lines,aE.color,0,w);if(aC){H.fillStyle=aC;aF(aE.datapoints,aE.xaxis,aE.yaxis)}if(aG>0){aD(aE.datapoints,0,0,aE.xaxis,aE.yaxis)}H.restore()}function ao(aE){function aH(aN,aM,aU,aK,aS,aT,aQ,aJ){var aR=aN.points,aI=aN.pointsize;for(var aL=0;aL<aR.length;aL+=aI){var aP=aR[aL],aO=aR[aL+1];if(aP==null||aP<aT.min||aP>aT.max||aO<aQ.min||aO>aQ.max){continue}H.beginPath();aP=aT.p2c(aP);aO=aQ.p2c(aO)+aK;if(aJ=="circle"){H.arc(aP,aO,aM,0,aS?Math.PI:Math.PI*2,false)}else{aJ(H,aP,aO,aM,aS)}H.closePath();if(aU){H.fillStyle=aU;H.fill()}H.stroke()}}H.save();H.translate(q.left,q.top);var aG=aE.points.lineWidth,aC=aE.shadowSize,aB=aE.points.radius,aF=aE.points.symbol;if(aG>0&&aC>0){var aD=aC/2;H.lineWidth=aD;H.strokeStyle="rgba(0,0,0,0.1)";aH(aE.datapoints,aB,null,aD+aD/2,true,aE.xaxis,aE.yaxis,aF);H.strokeStyle="rgba(0,0,0,0.2)";aH(aE.datapoints,aB,null,aD/2,true,aE.xaxis,aE.yaxis,aF)}H.lineWidth=aG;H.strokeStyle=aE.color;aH(aE.datapoints,aB,ae(aE.points,aE.color),0,false,aE.xaxis,aE.yaxis,aF);H.restore()}function E(aN,aM,aV,aI,aQ,aF,aD,aL,aK,aU,aR,aC){var aE,aT,aJ,aP,aG,aB,aO,aH,aS;if(aR){aH=aB=aO=true;aG=false;aE=aV;aT=aN;aP=aM+aI;aJ=aM+aQ;if(aT<aE){aS=aT;aT=aE;aE=aS;aG=true;aB=false}}else{aG=aB=aO=true;aH=false;aE=aN+aI;aT=aN+aQ;aJ=aV;aP=aM;if(aP<aJ){aS=aP;aP=aJ;aJ=aS;aH=true;aO=false}}if(aT<aL.min||aE>aL.max||aP<aK.min||aJ>aK.max){return}if(aE<aL.min){aE=aL.min;aG=false}if(aT>aL.max){aT=aL.max;aB=false}if(aJ<aK.min){aJ=aK.min;aH=false}if(aP>aK.max){aP=aK.max;aO=false}aE=aL.p2c(aE);aJ=aK.p2c(aJ);aT=aL.p2c(aT);aP=aK.p2c(aP);if(aD){aU.beginPath();aU.moveTo(aE,aJ);aU.lineTo(aE,aP);aU.lineTo(aT,aP);aU.lineTo(aT,aJ);aU.fillStyle=aD(aJ,aP);aU.fill()}if(aC>0&&(aG||aB||aO||aH)){aU.beginPath();aU.moveTo(aE,aJ+aF);if(aG){aU.lineTo(aE,aP+aF)}else{aU.moveTo(aE,aP+aF)}if(aO){aU.lineTo(aT,aP+aF)}else{aU.moveTo(aT,aP+aF)}if(aB){aU.lineTo(aT,aJ+aF)}else{aU.moveTo(aT,aJ+aF)}if(aH){aU.lineTo(aE,aJ+aF)}else{aU.moveTo(aE,aJ+aF)}aU.stroke()}}function e(aD){function aC(aJ,aI,aL,aG,aK,aN,aM){var aO=aJ.points,aF=aJ.pointsize;for(var aH=0;aH<aO.length;aH+=aF){if(aO[aH]==null){continue}E(aO[aH],aO[aH+1],aO[aH+2],aI,aL,aG,aK,aN,aM,H,aD.bars.horizontal,aD.bars.lineWidth)}}H.save();H.translate(q.left,q.top);H.lineWidth=aD.bars.lineWidth;H.strokeStyle=aD.color;var aB=aD.bars.align=="left"?0:-aD.bars.barWidth/2;var aE=aD.bars.fill?function(aF,aG){return ae(aD.bars,aD.color,aF,aG)}:null;aC(aD.datapoints,aB,aB+aD.bars.barWidth,0,aE,aD.xaxis,aD.yaxis);H.restore()}function ae(aD,aB,aC,aF){var aE=aD.fill;if(!aE){return null}if(aD.fillColor){return am(aD.fillColor,aC,aF,aB)}var aG=c.color.parse(aB);aG.a=typeof aE=="number"?aE:0.4;aG.normalize();return aG.toString()}function o(){av.find(".legend").remove();if(!O.legend.show){return}var aH=[],aF=false,aN=O.legend.labelFormatter,aM,aJ;for(var aE=0;aE<Q.length;++aE){aM=Q[aE];aJ=aM.label;if(!aJ){continue}if(aE%O.legend.noColumns==0){if(aF){aH.push("</tr>")}aH.push("<tr>");aF=true}if(aN){aJ=aN(aJ,aM)}aH.push('<td class="legendColorBox"><div style="border:1px solid '+O.legend.labelBoxBorderColor+';padding:1px"><div style="width:4px;height:0;border:5px solid '+aM.color+';overflow:hidden"></div></div></td><td class="legendLabel">'+aJ+"</td>")}if(aF){aH.push("</tr>")}if(aH.length==0){return}var aL='<table style="font-size:smaller;color:'+O.grid.color+'">'+aH.join("")+"</table>";if(O.legend.container!=null){c(O.legend.container).html(aL)}else{var aI="",aC=O.legend.position,aD=O.legend.margin;if(aD[0]==null){aD=[aD,aD]}if(aC.charAt(0)=="n"){aI+="top:"+(aD[1]+q.top)+"px;"}else{if(aC.charAt(0)=="s"){aI+="bottom:"+(aD[1]+q.bottom)+"px;"}}if(aC.charAt(1)=="e"){aI+="right:"+(aD[0]+q.right)+"px;"}else{if(aC.charAt(1)=="w"){aI+="left:"+(aD[0]+q.left)+"px;"}}var aK=c('<div class="legend">'+aL.replace('style="','style="position:absolute;'+aI+";")+"</div>").appendTo(av);if(O.legend.backgroundOpacity!=0){var aG=O.legend.backgroundColor;if(aG==null){aG=O.grid.backgroundColor;if(aG&&typeof aG=="string"){aG=c.color.parse(aG)}else{aG=c.color.extract(aK,"background-color")}aG.a=1;aG=aG.toString()}var aB=aK.children();c('<div style="position:absolute;width:'+aB.width()+"px;height:"+aB.height()+"px;"+aI+"background-color:"+aG+';"> </div>').prependTo(aK).css("opacity",O.legend.backgroundOpacity)}}}var ab=[],M=null;function K(aI,aG,aD){var aO=O.grid.mouseActiveRadius,a0=aO*aO+1,aY=null,aR=false,aW,aU;for(aW=Q.length-1;aW>=0;--aW){if(!aD(Q[aW])){continue}var aP=Q[aW],aH=aP.xaxis,aF=aP.yaxis,aV=aP.datapoints.points,aT=aP.datapoints.pointsize,aQ=aH.c2p(aI),aN=aF.c2p(aG),aC=aO/aH.scale,aB=aO/aF.scale;if(aH.options.inverseTransform){aC=Number.MAX_VALUE}if(aF.options.inverseTransform){aB=Number.MAX_VALUE}if(aP.lines.show||aP.points.show){for(aU=0;aU<aV.length;aU+=aT){var aK=aV[aU],aJ=aV[aU+1];if(aK==null){continue}if(aK-aQ>aC||aK-aQ<-aC||aJ-aN>aB||aJ-aN<-aB){continue}var aM=Math.abs(aH.p2c(aK)-aI),aL=Math.abs(aF.p2c(aJ)-aG),aS=aM*aM+aL*aL;if(aS<a0){a0=aS;aY=[aW,aU/aT]}}}if(aP.bars.show&&!aY){var aE=aP.bars.align=="left"?0:-aP.bars.barWidth/2,aX=aE+aP.bars.barWidth;for(aU=0;aU<aV.length;aU+=aT){var aK=aV[aU],aJ=aV[aU+1],aZ=aV[aU+2];if(aK==null){continue}if(Q[aW].bars.horizontal?(aQ<=Math.max(aZ,aK)&&aQ>=Math.min(aZ,aK)&&aN>=aJ+aE&&aN<=aJ+aX):(aQ>=aK+aE&&aQ<=aK+aX&&aN>=Math.min(aZ,aJ)&&aN<=Math.max(aZ,aJ))){aY=[aW,aU/aT]}}}}if(aY){aW=aY[0];aU=aY[1];aT=Q[aW].datapoints.pointsize;return{datapoint:Q[aW].datapoints.points.slice(aU*aT,(aU+1)*aT),dataIndex:aU,series:Q[aW],seriesIndex:aW}}return null}function aa(aB){if(O.grid.hoverable){u("plothover",aB,function(aC){return aC.hoverable!=false})}}function l(aB){if(O.grid.hoverable){u("plothover",aB,function(aC){return false})}}function R(aB){u("plotclick",aB,function(aC){return aC.clickable!=false})}function u(aC,aB,aD){var aE=y.offset(),aH=aB.pageX-aE.left-q.left,aF=aB.pageY-aE.top-q.top,aJ=C({left:aH,top:aF});aJ.pageX=aB.pageX;aJ.pageY=aB.pageY;var aK=K(aH,aF,aD);if(aK){aK.pageX=parseInt(aK.series.xaxis.p2c(aK.datapoint[0])+aE.left+q.left);aK.pageY=parseInt(aK.series.yaxis.p2c(aK.datapoint[1])+aE.top+q.top)}if(O.grid.autoHighlight){for(var aG=0;aG<ab.length;++aG){var aI=ab[aG];if(aI.auto==aC&&!(aK&&aI.series==aK.series&&aI.point[0]==aK.datapoint[0]&&aI.point[1]==aK.datapoint[1])){T(aI.series,aI.point)}}if(aK){x(aK.series,aK.datapoint,aC)}}av.trigger(aC,[aJ,aK])}function f(){if(!M){M=setTimeout(s,30)}}function s(){M=null;A.save();A.clearRect(0,0,G,I);A.translate(q.left,q.top);var aC,aB;for(aC=0;aC<ab.length;++aC){aB=ab[aC];if(aB.series.bars.show){v(aB.series,aB.point)}else{ay(aB.series,aB.point)}}A.restore();an(ak.drawOverlay,[A])}function x(aD,aB,aF){if(typeof aD=="number"){aD=Q[aD]}if(typeof aB=="number"){var aE=aD.datapoints.pointsize;aB=aD.datapoints.points.slice(aE*aB,aE*(aB+1))}var aC=al(aD,aB);if(aC==-1){ab.push({series:aD,point:aB,auto:aF});f()}else{if(!aF){ab[aC].auto=false}}}function T(aD,aB){if(aD==null&&aB==null){ab=[];f()}if(typeof aD=="number"){aD=Q[aD]}if(typeof aB=="number"){aB=aD.data[aB]}var aC=al(aD,aB);if(aC!=-1){ab.splice(aC,1);f()}}function al(aD,aE){for(var aB=0;aB<ab.length;++aB){var aC=ab[aB];if(aC.series==aD&&aC.point[0]==aE[0]&&aC.point[1]==aE[1]){return aB}}return -1}function ay(aE,aD){var aC=aD[0],aI=aD[1],aH=aE.xaxis,aG=aE.yaxis;if(aC<aH.min||aC>aH.max||aI<aG.min||aI>aG.max){return}var aF=aE.points.radius+aE.points.lineWidth/2;A.lineWidth=aF;A.strokeStyle=c.color.parse(aE.color).scale("a",0.5).toString();var aB=1.5*aF,aC=aH.p2c(aC),aI=aG.p2c(aI);A.beginPath();if(aE.points.symbol=="circle"){A.arc(aC,aI,aB,0,2*Math.PI,false)}else{aE.points.symbol(A,aC,aI,aB,false)}A.closePath();A.stroke()}function v(aE,aB){A.lineWidth=aE.bars.lineWidth;A.strokeStyle=c.color.parse(aE.color).scale("a",0.5).toString();var aD=c.color.parse(aE.color).scale("a",0.5).toString();var aC=aE.bars.align=="left"?0:-aE.bars.barWidth/2;E(aB[0],aB[1],aB[2]||0,aC,aC+aE.bars.barWidth,0,function(){return aD},aE.xaxis,aE.yaxis,A,aE.bars.horizontal,aE.bars.lineWidth)}function am(aJ,aB,aH,aC){if(typeof aJ=="string"){return aJ}else{var aI=H.createLinearGradient(0,aH,0,aB);for(var aE=0,aD=aJ.colors.length;aE<aD;++aE){var aF=aJ.colors[aE];if(typeof aF!="string"){var aG=c.color.parse(aC);if(aF.brightness!=null){aG=aG.scale("rgb",aF.brightness)}if(aF.opacity!=null){aG.a*=aF.opacity}aF=aG.toString()}aI.addColorStop(aE/(aD-1),aF)}return aI}}}c.plot=function(g,e,d){var f=new b(c(g),e,d,c.plot.plugins);return f};c.plot.version="0.7";c.plot.plugins=[];c.plot.formatDate=function(l,f,h){var o=function(d){d=""+d;return d.length==1?"0"+d:d};var e=[];var p=false,j=false;var n=l.getUTCHours();var k=n<12;if(h==null){h=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]}if(f.search(/%p|%P/)!=-1){if(n>12){n=n-12}else{if(n==0){n=12}}}for(var g=0;g<f.length;++g){var m=f.charAt(g);if(p){switch(m){case"h":m=""+n;break;case"H":m=o(n);break;case"M":m=o(l.getUTCMinutes());break;case"S":m=o(l.getUTCSeconds());break;case"d":m=""+l.getUTCDate();break;case"m":m=""+(l.getUTCMonth()+1);break;case"y":m=""+l.getUTCFullYear();break;case"b":m=""+h[l.getUTCMonth()];break;case"p":m=(k)?("am"):("pm");break;case"P":m=(k)?("AM"):("PM");break;case"0":m="";j=true;break}if(m&&j){m=o(m);j=false}e.push(m);if(!j){p=false}}else{if(m=="%"){p=true}else{e.push(m)}}}return e.join("")};function a(e,d){return d*Math.floor(e/d)}})(jQuery); \ No newline at end of file Added: trunk/server/app/assets/javascripts/jquery.flot.pie.min.js =================================================================== --- trunk/server/app/assets/javascripts/jquery.flot.pie.min.js (rev 0) +++ trunk/server/app/assets/javascripts/jquery.flot.pie.min.js 2012-04-21 04:22:22 UTC (rev 315) @@ -0,0 +1 @@ +(function(b){function c(D){var h=null;var L=null;var n=null;var B=null;var p=null;var M=0;var F=true;var o=10;var w=0.95;var A=0;var d=false;var z=false;var j=[];D.hooks.processOptions.push(g);D.hooks.bindEvents.push(e);function g(O,N){if(N.series.pie.show){N.grid.show=false;if(N.series.pie.label.show=="auto"){if(N.legend.show){N.series.pie.label.show=false}else{N.series.pie.label.show=true}}if(N.series.pie.radius=="auto"){if(N.series.pie.label.show){N.series.pie.radius=3/4}else{N.series.pie.radius=1}}if(N.series.pie.tilt>1){N.series.pie.tilt=1}if(N.series.pie.tilt<0){N.series.pie.tilt=0}O.hooks.processDatapoints.push(E);O.hooks.drawOverlay.push(H);O.hooks.draw.push(r)}}function e(P,N){var O=P.getOptions();if(O.series.pie.show&&O.grid.hoverable){N.unbind("mousemove").mousemove(t)}if(O.series.pie.show&&O.grid.clickable){N.unbind("click").click(l)}}function G(O){var P="";function N(S,T){if(!T){T=0}for(var R=0;R<S.length;++R){for(var Q=0;Q<T;Q++){P+="\t"}if(typeof S[R]=="object"){P+=""+R+":\n";N(S[R],T+1)}else{P+=""+R+": "+S[R]+"\n"}}}N(O);alert(P)}function q(P){for(var N=0;N<P.length;++N){var O=parseFloat(P[N].data[0][1]);if(O){M+=O}}}function E(Q,N,O,P){if(!d){d=true;h=Q.getCanvas();L=b(h).parent();a=Q.getOptions();Q.setData(K(Q.getData()))}}function I(){A=L.children().filter(".legend").children().width();n=Math.min(h.width,(h.height/a.series.pie.tilt))/2;p=(h.height/2)+a.series.pie.offset.top;B=(h.width/2);if(a.series.pie.offset.left=="auto"){if(a.legend.position.match("w")){B+=A/2}else{B-=A/2}}else{B+=a.series.pie.offset.left}if(B<n){B=n}else{if(B>h.width-n){B=h.width-n}}}function v(O){for(var N=0;N<O.length;++N){if(typeof(O[N].data)=="number"){O[N].data=[[1,O[N].data]]}else{if(typeof(O[N].data)=="undefined"||typeof(O[N].data[0])=="undefined"){if(typeof(O[N].data)!="undefined"&&typeof(O[N].data.label)!="undefined"){O[N].label=O[N].data.label}O[N].data=[[1,0]]}}}return O}function K(Q){Q=v(Q);q(Q);var P=0;var S=0;var N=a.series.pie.combine.color;var R=[];for(var O=0;O<Q.length;++O){Q[O].data[0][1]=parseFloat(Q[O].data[0][1]);if(!Q[O].data[0][1]){Q[O].data[0][1]=0}if(Q[O].data[0][1]/M<=a.series.pie.combine.threshold){P+=Q[O].data[0][1];S++;if(!N){N=Q[O].color}}else{R.push({data:[[1,Q[O].data[0][1]]],color:Q[O].color,label:Q[O].label,angle:(Q[O].data[0][1]*(Math.PI*2))/M,percent:(Q[O].data[0][1]/M*100)})}}if(S>0){R.push({data:[[1,P]],color:N,label:a.series.pie.combine.label,angle:(P*(Math.PI*2))/M,percent:(P/M*100)})}return R}function r(S,Q){if(!L){return}ctx=Q;I();var T=S.getData();var P=0;while(F&&P<o){F=false;if(P>0){n*=w}P+=1;N();if(a.series.pie.tilt<=0.8){O()}R()}if(P>=o){N();L.prepend('<div class="error">Could not draw pie with labels contained inside canvas</div>')}if(S.setSeries&&S.insertLegend){S.setSeries(T);S.insertLegend()}function N(){ctx.clearRect(0,0,h.width,h.height);L.children().filter(".pieLabel, .pieLabelBackground").remove()}function O(){var Z=5;var Y=15;var W=10;var X=0.02;if(a.series.pie.radius>1){var U=a.series.pie.radius}else{var U=n*a.series.pie.radius}if(U>=(h.width/2)-Z||U*a.series.pie.tilt>=(h.height/2)-Y||U<=W){return}ctx.save();ctx.translate(Z,Y);ctx.globalAlpha=X;ctx.fillStyle="#000";ctx.translate(B,p);ctx.scale(1,a.series.pie.tilt);for(var V=1;V<=W;V++){ctx.beginPath();ctx.arc(0,0,U,0,Math.PI*2,false);ctx.fill();U-=V}ctx.restore()}function R(){startAngle=Math.PI*a.series.pie.startAngle;if(a.series.pie.radius>1){var U=a.series.pie.radius}else{var U=n*a.series.pie.radius}ctx.save();ctx.translate(B,p);ctx.scale(1,a.series.pie.tilt);ctx.save();var Y=startAngle;for(var W=0;W<T.length;++W){T[W].startAngle=Y;X(T[W].angle,T[W].color,true)}ctx.restore();ctx.save();ctx.lineWidth=a.series.pie.stroke.width;Y=startAngle;for(var W=0;W<T.length;++W){X(T[W].angle,a.series.pie.stroke.color,false)}ctx.restore();J(ctx);if(a.series.pie.label.show){V()}ctx.restore();function X(ab,Z,aa){if(ab<=0){return}if(aa){ctx.fillStyle=Z}else{ctx.strokeStyle=Z;ctx.lineJoin="round"}ctx.beginPath();if(Math.abs(ab-Math.PI*2)>1e-9){ctx.moveTo(0,0)}else{if(b.browser.msie){ab-=0.0001}}ctx.arc(0,0,U,Y,Y+ab,false);ctx.closePath();Y+=ab;if(aa){ctx.fill()}else{ctx.stroke()}}function V(){var ac=startAngle;if(a.series.pie.label.radius>1){var Z=a.series.pie.label.radius}else{var Z=n*a.series.pie.label.radius}for(var ab=0;ab<T.length;++ab){if(T[ab].percent>=a.series.pie.label.threshold*100){aa(T[ab],ac,ab)}ac+=T[ab].angle}function aa(ap,ai,ag){if(ap.data[0][1]==0){return}var ar=a.legend.labelFormatter,aq,ae=a.series.pie.label.formatter;if(ar){aq=ar(ap.label,ap)}else{aq=ap.label}if(ae){aq=ae(aq,ap)}var aj=((ai+ap.angle)+ai)/2;var ao=B+Math.round(Math.cos(aj)*Z);var am=p+Math.round(Math.sin(aj)*Z)*a.series.pie.tilt;var af='<span class="pieLabel" id="pieLabel'+ag+'" style="position:absolute;top:'+am+"px;left:"+ao+'px;">'+aq+"</span>";L.append(af);var an=L.children("#pieLabel"+ag);var ad=(am-an.height()/2);var ah=(ao-an.width()/2);an.css("top",ad);an.css("left",ah);if(0-ad>0||0-ah>0||h.height-(ad+an.height())<0||h.width-(ah+an.width())<0){F=true}if(a.series.pie.label.background.opacity!=0){var ak=a.series.pie.label.background.color;if(ak==null){ak=ap.color}var al="top:"+ad+"px;left:"+ah+"px;";b('<div class="pieLabelBackground" style="position:absolute;width:'+an.width()+"px;height:"+an.height()+"px;"+al+"background-color:"+ak+';"> </div>').insertBefore(an).css("opacity",a.series.pie.label.background.opacity)}}}}}function J(N){if(a.series.pie.innerRadius>0){N.save();innerRadius=a.series.pie.innerRadius>1?a.series.pie.innerRadius:n*a.series.pie.innerRadius;N.globalCompositeOperation="destination-out";N.beginPath();N.fillStyle=a.series.pie.stroke.color;N.arc(0,0,innerRadius,0,Math.PI*2,false);N.fill();N.closePath();N.restore();N.save();N.beginPath();N.strokeStyle=a.series.pie.stroke.color;N.arc(0,0,innerRadius,0,Math.PI*2,false);N.stroke();N.closePath();N.restore()}}function s(Q,R){for(var S=false,P=-1,N=Q.length,O=N-1;++P<N;O=P){((Q[P][1]<=R[1]&&R[1]<Q[O][1])||(Q[O][1]<=R[1]&&R[1]<Q[P][1]))&&(R[0]<(Q[O][0]-Q[P][0])*(R[1]-Q[P][1])/(Q[O][1]-Q[P][1])+Q[P][0])&&(S=!S)}return S}function u(R,P){var T=D.getData(),O=D.getOptions(),N=O.series.pie.radius>1?O.series.pie.radius:n*O.series.pie.radius;for(var Q=0;Q<T.length;++Q){var S=T[Q];if(S.pie.show){ctx.save();ctx.beginPath();ctx.moveTo(0,0);ctx.arc(0,0,N,S.startAngle,S.startAngle+S.angle,false);ctx.closePath();x=R-B;y=P-p;if(ctx.isPointInPath){if(ctx.isPointInPath(R-B,P-p)){ctx.restore();return{datapoint:[S.percent,S.data],dataIndex:0,series:S,seriesIndex:Q}}}else{p1X=(N*Math.cos(S.startAngle));p1Y=(N*Math.sin(S.startAngle));p2X=(N*Math.cos(S.startAngle+(S.angle/4)));p2Y=(N*Math.sin(S.startAngle+(S.angle/4)));p3X=(N*Math.cos(S.startAngle+(S.angle/2)));p3Y=(N*Math.sin(S.startAngle+(S.angle/2)));p4X=(N*Math.cos(S.startAngle+(S.angle/1.5)));p4Y=(N*Math.sin(S.startAngle+(S.angle/1.5)));p5X=(N*Math.cos(S.startAngle+S.angle));p5Y=(N*Math.sin(S.startAngle+S.angle));arrPoly=[[0,0],[p1X,p1Y],[p2X,p2Y],[p3X,p3Y],[p4X,p4Y],[p5X,p5Y]];arrPoint=[x,y];if(s(arrPoly,arrPoint)){ctx.restore();return{datapoint:[S.percent,S.data],dataIndex:0,series:S,seriesIndex:Q}}}ctx.restore()}}return null}function t(N){m("plothover",N)}function l(N){m("plotclick",N)}function m(N,T){var O=D.offset(),R=parseInt(T.pageX-O.left),P=parseInt(T.pageY-O.top),V=u(R,P);if(a.grid.autoHighlight){for(var Q=0;Q<j.length;++Q){var S=j[Q];if(S.auto==N&&!(V&&S.series==V.series)){f(S.series)}}}if(V){k(V.series,N)}var U={pageX:T.pageX,pageY:T.pageY};L.trigger(N,[U,V])}function k(O,P){if(typeof O=="number"){O=series[O]}var N=C(O);if(N==-1){j.push({series:O,auto:P});D.triggerRedrawOverlay()}else{if(!P){j[N].auto=false}}}function f(O){if(O==null){j=[];D.triggerRedrawOverlay()}if(typeof O=="number"){O=series[O]}var N=C(O);if(N!=-1){j.splice(N,1);D.triggerRedrawOverlay()}}function C(P){for(var N=0;N<j.length;++N){var O=j[N];if(O.series==P){return N}}return -1}function H(Q,R){var P=Q.getOptions();var N=P.series.pie.radius>1?P.series.pie.radius:n*P.series.pie.radius;R.save();R.translate(B,p);R.scale(1,P.series.pie.tilt);for(i=0;i<j.length;++i){O(j[i].series)}J(R);R.restore();function O(S){if(S.angle<0){return}R.fillStyle="rgba(255, 255, 255, "+P.series.pie.highlight.opacity+")";R.beginPath();if(Math.abs(S.angle-Math.PI*2)>1e-9){R.moveTo(0,0)}R.arc(0,0,N,S.startAngle,S.startAngle+S.angle,false);R.closePath();R.fill()}}}var a={series:{pie:{show:false,radius:"auto",innerRadius:0,startAngle:3/2,tilt:1,offset:{top:0,left:"auto"},stroke:{color:"#FFF",width:1},label:{show:"auto",formatter:function(d,e){return'<div style="font-size:x-small;text-align:center;padding:2px;color:'+e.color+';">'+d+"<br/>"+Math.round(e.percent)+"%</div>"},radius:1,background:{color:null,opacity:0},threshold:0},combine:{threshold:-1,color:null,label:"Other"},highlight:{opacity:0.5}}}};b.plot.plugins.push({init:c,options:a,name:"pie",version:"1.0"})})(jQuery); \ No newline at end of file Deleted: trunk/server/app/assets/javascripts/swfobject.js =================================================================== --- trunk/server/app/assets/javascripts/swfobject.js 2012-04-20 23:22:38 UTC (rev 314) +++ trunk/server/app/assets/javascripts/swfobject.js 2012-04-21 04:22:22 UTC (rev 315) @@ -1,5 +0,0 @@ -/* SWFObject v2.0 <http://code.google.com/p/swfobject/> - Copyright (c) 2007 Geoff Stearns, Michael Williams, and Bobby van der Sluis - This software is released under the MIT License <http://www.opensource.org/licenses/mit-license.php> -*/ -var swfobject=function(){var Z="undefined",P="object",B="Shockwave Flash",h="ShockwaveFlash.ShockwaveFlash",W="application/x-shockwave-flash",K="SWFObjectExprInst",G=window,g=document,N=navigator,f=[],H=[],Q=null,L=null,T=null,S=false,C=false;var a=function(){var l=typeof g.getElementById!=Z&&typeof g.getElementsByTagName!=Z&&typeof g.createElement!=Z&&typeof g.appendChild!=Z&&typeof g.replaceChild!=Z&&typeof g.removeChild!=Z&&typeof g.cloneNode!=Z,t=[0,0,0],n=null;if(typeof N.plugins!=Z&&typeof N.plugins[B]==P){n=N.plugins[B].description;if(n){n=n.replace(/^.*\s+(\S+\s+\S+$)/,"$1");t[0]=parseInt(n.replace(/^(.*)\..*$/,"$1"),10);t[1]=parseInt(n.replace(/^.*\.(.*)\s.*$/,"$1"),10);t[2]=/r/.test(n)?parseInt(n.replace(/^.*r(.*)$/,"$1"),10):0}}else{if(typeof G.ActiveXObject!=Z){var o=null,s=false;try{o=new ActiveXObject(h+".7")}catch(k){try{o=new ActiveXObject(h+".6");t=[6,0,21];o.AllowScriptAccess="always"}catch(k){if(t[0]==6){s=true}}if(!s){try{o=new ActiveXObject(h)}catch(k){}}}if(!s&&o){try{n=o.GetVariable("$version");if(n){n=n.split(" ")[1].split(",");t=[parseInt(n[0],10),parseInt(n[1],10),parseInt(n[2],10)]}}catch(k){}}}}var v=N.userAgent.toLowerCase(),j=N.platform.toLowerCase(),r=/webkit/.test(v)?parseFloat(v.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,i=false,q=j?/win/.test(j):/win/.test(v),m=j?/mac/.test(j):/mac/.test(v);/*@cc_on i=true;@if(@_win32)q=true;@elif(@_mac)m=true;@end@*/return{w3cdom:l,pv:t,webkit:r,ie:i,win:q,mac:m}}();var e=function(){if(!a.w3cdom){return }J(I);if(a.ie&&a.win){try{g.write("<script id=__ie_ondomload defer=true src=//:><\/script>");var i=c("__ie_ondomload");if(i){i.onreadystatechange=function(){if(this.readyState=="complete"){this.parentNode.removeChild(this);V()}}}}catch(j){}}if(a.webkit&&typeof g.readyState!=Z){Q=setInterval(function(){if(/loaded|complete/.test(g.readyState)){V()}},10)}if(typeof g.addEventListener!=Z){g.addEventListener("DOMContentLoaded",V,null)}M(V)}();function V(){if(S){return }if(a.ie&&a.win){var m=Y("span");try{var l=g.getElementsByTagName("body")[0].appendChild(m);l.parentNode.removeChild(l)}catch(n){return }}S=true;if(Q){clearInterval(Q);Q=null}var j=f.length;for(var k=0;k<j;k++){f[k]()}}function J(i){if(S){i()}else{f[f.length]=i}}function M(j){if(typeof G.addEventListener!=Z){G.addEventListener("load",j,false)}else{if(typeof g.addEventListener!=Z){g.addEventListener("load",j,false)}else{if(typeof G.attachEvent!=Z){G.attachEvent("onload",j)}else{if(typeof G.onload=="function"){var i=G.onload;G.onload=function(){i();j()}}else{G.onload=j}}}}}function I(){var l=H.length;for(var j=0;j<l;j++){var m=H[j].id;if(a.pv[0]>0){var k=c(m);if(k){H[j].width=k.getAttribute("width")?k.getAttribute("width"):"0";H[j].height=k.getAttribute("height")?k.getAttribute("height"):"0";if(O(H[j].swfVersion)){if(a.webkit&&a.webkit<312){U(k)}X(m,true)}else{if(H[j].expressInstall&&!C&&O("6.0.65")&&(a.win||a.mac)){D(H[j])}else{d(k)}}}}else{X(m,true)}}}function U(m){var k=m.getElementsByTagName(P)[0];if(k){var p=Y("embed"),r=k.attributes;if(r){var o=r.length;for(var n=0;n<o;n++){if(r[n].nodeName.toLowerCase()=="data"){p.setAttribute("src",r[n].nodeValue)}else{p.setAttribute(r[n].nodeName,r[n].nodeValue)}}}var q=k.childNodes;if(q){var s=q.length;for(var l=0;l<s;l++){if(q[l].nodeType==1&&q[l].nodeName.toLowerCase()=="param"){p.setAttribute(q[l].getAttribute("name"),q[l].getAttribute("value"))}}}m.parentNode.replaceChild(p,m)}}function F(i){if(a.ie&&a.win&&O("8.0.0")){G.attachEvent("onunload",function(){var k=c(i);if(k){for(var j in k){if(typeof k[j]=="function"){k[j]=function(){}}}k.parentNode.removeChild(k)}})}}function D(j){C=true;var o=c(j.id);if(o){if(j.altContentId){var l=c(j.altContentId);if(l){L=l;T=j.altContentId}}else{L=b(o)}if(!(/%$/.test(j.width))&&parseInt(j.width,10)<310){j.width="310"}if(!(/%$/.test(j.height))&&parseInt(j.height,10)<137){j.height="137"}g.title=g.title.slice(0,47)+" - Flash Player Installation";var n=a.ie&&a.win?"ActiveX":"PlugIn",k=g.title,m="MMredirectURL="+G.location+"&MMplayerType="+n+"&MMdoctitle="+k,p=j.id;if(a.ie&&a.win&&o.readyState!=4){var i=Y("div");p+="SWFObjectNew";i.setAttribute("id",p);o.parentNode.insertBefore(i,o);o.style.display="none";G.attachEvent("onload",function(){o.parentNode.removeChild(o)})}R({data:j.expressInstall,id:K,width:j.width,height:j.height},{flashvars:m},p)}}function d(j){if(a.ie&&a.win&&j.readyState!=4){var i=Y("div");j.parentNode.insertBefore(i,j);i.parentNode.replaceChild(b(j),i);j.style.display="none";G.attachEvent("onload",function(){j.parentNode.removeChild(j)})}else{j.parentNode.replaceChild(b(j),j)}}function b(n){var m=Y("div");if(a.win&&a.ie){m.innerHTML=n.innerHTML}else{var k=n.getElementsByTagName(P)[0];if(k){var o=k.childNodes;if(o){var j=o.length;for(var l=0;l<j;l++){if(!(o[l].nodeType==1&&o[l].nodeName.toLowerCase()=="param")&&!(o[l].nodeType==8)){m.appendChild(o[l].cloneNode(true))}}}}}return m}function R(AE,AC,q){var p,t=c(q);if(typeof AE.id==Z){AE.id=q}if(a.ie&&a.win){var AD="";for(var z in AE){if(AE[z]!=Object.prototype[z]){if(z=="data"){AC.movie=AE[z]}else{if(z.toLowerCase()=="styleclass"){AD+=' class="'+AE[z]+'"'}else{if(z!="classid"){AD+=" "+z+'="'+AE[z]+'"'}}}}}var AB="";for(var y in AC){if(AC[y]!=Object.prototype[y]){AB+='<param name="'+y+'" value="'+AC[y]+'" />'}}t.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+AD+">"+AB+"</object>";F(AE.id);p=c(AE.id)}else{if(a.webkit&&a.webkit<312){var AA=Y("embed");AA.setAttribute("type",W);for(var x in AE){if(AE[x]!=Object.prototype[x]){if(x=="data"){AA.setAttribute("src",AE[x])}else{if(x.toLowerCase()=="styleclass"){AA.setAttribute("class",AE[x])}else{if(x!="classid"){AA.setAttribute(x,AE[x])}}}}}for(var w in AC){if(AC[w]!=Object.prototype[w]){if(w!="movie"){AA.setAttribute(w,AC[w])}}}t.parentNode.replaceChild(AA,t);p=AA}else{var s=Y(P);s.setAttribute("type",W);for(var v in AE){if(AE[v]!=Object.prototype[v]){if(v.toLowerCase()=="styleclass"){s.setAttribute("class",AE[v])}else{if(v!="classid"){s.setAttribute(v,AE[v])}}}}for(var u in AC){if(AC[u]!=Object.prototype[u]&&u!="movie"){E(s,u,AC[u])}}t.parentNode.replaceChild(s,t);p=s}}return p}function E(k,i,j){var l=Y("param");l.setAttribute("name",i);l.setAttribute("value",j);k.appendChild(l)}function c(i){return g.getElementById(i)}function Y(i){return g.createElement(i)}function O(k){var j=a.pv,i=k.split(".");i[0]=parseInt(i[0],10);i[1]=parseInt(i[1],10);i[2]=parseInt(i[2],10);return(j[0]>i[0]||(j[0]==i[0]&&j[1]>i[1])||(j[0]==i[0]&&j[1]==i[1]&&j[2]>=i[2]))?true:false}function A(m,j){if(a.ie&&a.mac){return }var l=g.getElementsByTagName("head")[0],k=Y("style");k.setAttribute("type","text/css");k.setAttribute("media","screen");if(!(a.ie&&a.win)&&typeof g.createTextNode!=Z){k.appendChild(g.createTextNode(m+" {"+j+"}"))}l.appendChild(k);if(a.ie&&a.win&&typeof g.styleSheets!=Z&&g.styleSheets.length>0){var i=g.styleSheets[g.styleSheets.length-1];if(typeof i.addRule==P){i.addRule(m,j)}}}function X(k,i){var j=i?"visible":"hidden";if(S){c(k).style.visibility=j}else{A("#"+k,"visibility:"+j)}}return{registerObject:function(l,i,k){if(!a.w3cdom||!l||!i){return }var j={};j.id=l;j.swfVersion=i;j.expressInstall=k?k:false;H[H.length]=j;X(l,false)},getObjectById:function(l){var i=null;if(a.w3cdom&&S){var j=c(l);if(j){var k=j.getElementsByTagName(P)[0];if(!k||(k&&typeof j.SetVariable!=Z)){i=j}else{if(typeof k.SetVariable!=Z){i=k}}}}return i},embedSWF:function(n,u,r,t,j,m,k,p,s){if(!a.w3cdom||!n||!u||!r||!t||!j){return }r+="";t+="";if(O(j)){X(u,false);var q=(typeof s==P)?s:{};q.data=n;q.width=r;q.height=t;var o=(typeof p==P)?p:{};if(typeof k==P){for(var l in k){if(k[l]!=Object.prototype[l]){if(typeof o.flashvars!=Z){o.flashvars+="&"+l+"="+k[l]}else{o.flashvars=l+"="+k[l]}}}}J(function(){R(q,o,u);if(q.id==u){X(u,true)}})}else{if(m&&!C&&O("6.0.65")&&(a.win||a.mac)){X(u,false);J(function(){var i={};i.id=i.altContentId=u;i.width=r;i.height=t;i.expressInstall=m;D(i)})}}},getFlashPlayerVersion:function(){return{major:a.pv[0],minor:a.pv[1],release:a.pv[2]}},hasFlashPlayerVersion:O,createSWF:function(k,j,i){if(a.w3cdom&&S){return R(k,j,i)}else{return undefined}},createCSS:function(j,i){if(a.w3cdom){A(j,i)}},addDomLoadEvent:J,addLoadEvent:M,getQueryParamValue:function(m){var l=g.location.search||g.location.hash;if(m==null){return l}if(l){var k=l.substring(1).split("&");for(var j=0;j<k.length;j++){if(k[j].substring(0,k[j].indexOf("="))==m){return k[j].substring((k[j].indexOf("=")+1))}}}return""},expressInstallCallback:function(){if(C&&L){var i=c(K);if(i){i.parentNode.replaceChild(L,i);if(T){X(T,true);if(a.ie&&a.win){L.style.display="block"}}L=null;T=null;C=false}}}}}(); \ No newline at end of file Added: trunk/server/app/assets/stylesheets/dashboard.css.scss =================================================================== --- trunk/server/app/assets/stylesheets/dashboard.css.scss (rev 0) +++ trunk/server/app/assets/stylesheets/dashboard.css.scss 2012-04-21 04:22:22 UTC (rev 315) @@ -0,0 +1,9 @@ +#status_chart { + width:300px; + height:300px; +} +#client_chart { + width:500px; + height:300px; +} + Modified: trunk/server/app/assets/stylesheets/design.css =================================================================== --- trunk/server/app/assets/stylesheets/design.css 2012-04-20 23:22:38 UTC (rev 314) +++ trunk/server/app/assets/stylesheets/design.css 2012-04-21 04:22:22 UTC (rev 315) @@ -295,6 +295,7 @@ border-color: #036; border-width: 1px; border-style: solid; + margin-left: 40px; margin-bottom: 1em; } table.network_summary td @@ -330,20 +331,5 @@ #loginbox p { text-align: right; } -#status_chart -{ - /* Center this chart */ - margin-left: auto; - margin-right: auto; - /* The chart is... [truncated message content] |
From: <jh...@us...> - 2012-04-20 23:22:48
|
Revision: 314 http://etch.svn.sourceforge.net/etch/?rev=314&view=rev Author: jheiss Date: 2012-04-20 23:22:38 +0000 (Fri, 20 Apr 2012) Log Message: ----------- First pass at updating server to Rails 3. There are still a few unit test errors, but it mostly works. Modified Paths: -------------- trunk/server/Rakefile trunk/server/app/controllers/application_controller.rb trunk/server/app/controllers/clients_controller.rb trunk/server/app/controllers/dashboard_controller.rb trunk/server/app/controllers/etch_configs_controller.rb trunk/server/app/controllers/facts_controller.rb trunk/server/app/controllers/originals_controller.rb trunk/server/app/controllers/results_controller.rb trunk/server/app/helpers/application_helper.rb trunk/server/app/models/client.rb trunk/server/app/models/etch_config.rb trunk/server/app/models/fact.rb trunk/server/app/models/original.rb trunk/server/app/models/result.rb trunk/server/app/views/clients/index.html.erb trunk/server/app/views/clients/show.html.erb trunk/server/app/views/dashboard/_client_chart.html.erb trunk/server/app/views/dashboard/_status_chart.html.erb trunk/server/app/views/etch_configs/index.html.erb trunk/server/app/views/facts/index.html.erb trunk/server/app/views/layouts/application.html.erb trunk/server/app/views/originals/index.html.erb trunk/server/app/views/results/index.html.erb trunk/server/app/views/results/show.html.erb trunk/server/config/boot.rb trunk/server/config/database.yml trunk/server/config/dbclean trunk/server/config/environment.rb trunk/server/config/environments/development.rb trunk/server/config/environments/production.rb trunk/server/config/environments/test.rb trunk/server/config/initializers/inflections.rb trunk/server/config/routes.rb trunk/server/config/unicorn.rb trunk/server/lib/etch/server.rb trunk/server/lib/etch.rb trunk/server/public/404.html trunk/server/public/422.html trunk/server/public/500.html trunk/server/test/test_helper.rb Added Paths: ----------- trunk/server/Gemfile trunk/server/Gemfile.lock trunk/server/README.rdoc trunk/server/app/assets/ trunk/server/app/assets/images/ trunk/server/app/assets/images/rails.png trunk/server/app/assets/javascripts/ trunk/server/app/assets/javascripts/application.js trunk/server/app/assets/javascripts/swfobject.js trunk/server/app/assets/stylesheets/ trunk/server/app/assets/stylesheets/application.css trunk/server/app/assets/stylesheets/design.css trunk/server/app/assets/stylesheets/forms.css trunk/server/app/mailers/ trunk/server/config/application.rb trunk/server/config/initializers/backtrace_silencers.rb trunk/server/config/initializers/secret_token.rb trunk/server/config/initializers/session_store.rb trunk/server/config/initializers/wrap_parameters.rb trunk/server/config/locales/ trunk/server/config/locales/en.yml trunk/server/config.ru trunk/server/db/schema.rb trunk/server/db/seeds.rb trunk/server/lib/assets/ trunk/server/script/rails trunk/server/test/performance/ trunk/server/test/performance/browsing_test.rb trunk/server/vendor/assets/ trunk/server/vendor/assets/javascripts/ trunk/server/vendor/assets/stylesheets/ Removed Paths: ------------- trunk/server/README trunk/server/app/helpers/clients_helper.rb trunk/server/app/helpers/dashboard_helper.rb trunk/server/app/helpers/etch_configs_helper.rb trunk/server/app/helpers/facts_helper.rb trunk/server/app/helpers/files_helper.rb trunk/server/app/helpers/originals_helper.rb trunk/server/app/helpers/results_helper.rb trunk/server/public/dispatch.cgi trunk/server/public/dispatch.fcgi trunk/server/public/dispatch.rb trunk/server/public/images/ trunk/server/public/javascripts/ trunk/server/public/stylesheets/ trunk/server/script/about trunk/server/script/console trunk/server/script/dbconsole trunk/server/script/destroy trunk/server/script/generate trunk/server/script/performance/ trunk/server/script/plugin trunk/server/script/process/ trunk/server/script/runner trunk/server/script/server trunk/server/vendor/plugins/exception_notification/ Property Changed: ---------------- trunk/server/ trunk/server/db/ trunk/server/tmp/cache/ trunk/server/tmp/pids/ trunk/server/tmp/sessions/ trunk/server/tmp/sockets/ Property changes on: trunk/server ___________________________________________________________________ Added: svn:ignore + .bundle Added: trunk/server/Gemfile =================================================================== --- trunk/server/Gemfile (rev 0) +++ trunk/server/Gemfile 2012-04-20 23:22:38 UTC (rev 314) @@ -0,0 +1,44 @@ +source 'https://rubygems.org' + +gem 'rails', '3.2.3' + +# Bundle edge Rails instead: +# gem 'rails', :git => 'git://github.com/rails/rails.git' + +gem 'sqlite3' + + +# Gems used only for assets and not required +# in production environments by default. +group :assets do + gem 'sass-rails', '~> 3.2.3' + gem 'coffee-rails', '~> 3.2.1' + + # See https://github.com/sstephenson/execjs#readme for more supported runtimes + gem 'therubyracer', :platform => :ruby + + gem 'uglifier', '>= 1.0.3' +end + +gem 'jquery-rails' + +# To use ActiveModel has_secure_password +# gem 'bcrypt-ruby', '~> 3.0.0' + +# To use Jbuilder templates for JSON +# gem 'jbuilder' + +# Use unicorn as the app server +# gem 'unicorn' + +# Deploy with Capistrano +# gem 'capistrano' + +# To use debugger +# gem 'ruby-debug19', :require => 'ruby-debug' + +gem 'will_paginate', '~> 3.0.0' +gem 'ransack', '~> 0.6.0' +gem 'exception_notification', '~> 2.6.0' +gem 'nokogiri' + Added: trunk/server/Gemfile.lock =================================================================== --- trunk/server/Gemfile.lock (rev 0) +++ trunk/server/Gemfile.lock 2012-04-20 23:22:38 UTC (rev 314) @@ -0,0 +1,129 @@ +GEM + remote: https://rubygems.org/ + specs: + actionmailer (3.2.3) + actionpack (= 3.2.3) + mail (~> 2.4.4) + actionpack (3.2.3) + activemodel (= 3.2.3) + activesupport (= 3.2.3) + builder (~> 3.0.0) + erubis (~> 2.7.0) + journey (~> 1.0.1) + rack (~> 1.4.0) + rack-cache (~> 1.2) + rack-test (~> 0.6.1) + sprockets (~> 2.1.2) + activemodel (3.2.3) + activesupport (= 3.2.3) + builder (~> 3.0.0) + activerecord (3.2.3) + activemodel (= 3.2.3) + activesupport (= 3.2.3) + arel (~> 3.0.2) + tzinfo (~> 0.3.29) + activeresource (3.2.3) + activemodel (= 3.2.3) + activesupport (= 3.2.3) + activesupport (3.2.3) + i18n (~> 0.6) + multi_json (~> 1.0) + arel (3.0.2) + builder (3.0.0) + coffee-rails (3.2.2) + coffee-script (>= 2.2.0) + railties (~> 3.2.0) + coffee-script (2.2.0) + coffee-script-source + execjs + coffee-script-source (1.3.1) + erubis (2.7.0) + exception_notification (2.6.0) + actionmailer (>= 3.0.4) + execjs (1.3.0) + multi_json (~> 1.0) + hike (1.2.1) + i18n (0.6.0) + journey (1.0.3) + jquery-rails (2.0.2) + railties (>= 3.2.0, < 5.0) + thor (~> 0.14) + json (1.6.6) + libv8 (3.3.10.4) + mail (2.4.4) + i18n (>= 0.4.0) + mime-types (~> 1.16) + treetop (~> 1.4.8) + mime-types (1.18) + multi_json (1.2.0) + nokogiri (1.5.0) + polyamorous (0.5.0) + activerecord (~> 3.0) + polyglot (0.3.3) + rack (1.4.1) + rack-cache (1.2) + rack (>= 0.4) + rack-ssl (1.3.2) + rack + rack-test (0.6.1) + rack (>= 1.0) + rails (3.2.3) + actionmailer (= 3.2.3) + actionpack (= 3.2.3) + activerecord (= 3.2.3) + activeresource (= 3.2.3) + activesupport (= 3.2.3) + bundler (~> 1.0) + railties (= 3.2.3) + railties (3.2.3) + actionpack (= 3.2.3) + activesupport (= 3.2.3) + rack-ssl (~> 1.3.2) + rake (>= 0.8.7) + rdoc (~> 3.4) + thor (~> 0.14.6) + rake (0.9.2.2) + ransack (0.6.0) + actionpack (~> 3.0) + activerecord (~> 3.0) + polyamorous (~> 0.5.0) + rdoc (3.12) + json (~> 1.4) + sass (3.1.15) + sass-rails (3.2.5) + railties (~> 3.2.0) + sass (>= 3.1.10) + tilt (~> 1.3) + sprockets (2.1.2) + hike (~> 1.2) + rack (~> 1.0) + tilt (~> 1.1, != 1.3.0) + sqlite3 (1.3.5) + therubyracer (0.10.1) + libv8 (~> 3.3.10) + thor (0.14.6) + tilt (1.3.3) + treetop (1.4.10) + polyglot + polyglot (>= 0.3.1) + tzinfo (0.3.33) + uglifier (1.2.4) + execjs (>= 0.3.0) + multi_json (>= 1.0.2) + will_paginate (3.0.3) + +PLATFORMS + ruby + +DEPENDENCIES + coffee-rails (~> 3.2.1) + exception_notification (~> 2.6.0) + jquery-rails + nokogiri + rails (= 3.2.3) + ransack (~> 0.6.0) + sass-rails (~> 3.2.3) + sqlite3 + therubyracer + uglifier (>= 1.0.3) + will_paginate (~> 3.0.0) Deleted: trunk/server/README =================================================================== --- trunk/server/README 2012-03-21 23:30:16 UTC (rev 313) +++ trunk/server/README 2012-04-20 23:22:38 UTC (rev 314) @@ -1,256 +0,0 @@ -== Welcome to Rails - -Rails is a web-application framework that includes everything needed to create -database-backed web applications according to the Model-View-Control pattern. - -This pattern splits the view (also called the presentation) into "dumb" templates -that are primarily responsible for inserting pre-built data in between HTML tags. -The model contains the "smart" domain objects (such as Account, Product, Person, -Post) that holds all the business logic and knows how to persist themselves to -a database. The controller handles the incoming requests (such as Save New Account, -Update Product, Show Post) by manipulating the model and directing data to the view. - -In Rails, the model is handled by what's called an object-relational mapping -layer entitled Active Record. This layer allows you to present the data from -database rows as objects and embellish these data objects with business logic -methods. You can read more about Active Record in -link:files/vendor/rails/activerecord/README.html. - -The controller and view are handled by the Action Pack, which handles both -layers by its two parts: Action View and Action Controller. These two layers -are bundled in a single package due to their heavy interdependence. This is -unlike the relationship between the Active Record and Action Pack that is much -more separate. Each of these packages can be used independently outside of -Rails. You can read more about Action Pack in -link:files/vendor/rails/actionpack/README.html. - - -== Getting Started - -1. At the command prompt, start a new Rails application using the <tt>rails</tt> command - and your application name. Ex: rails myapp -2. Change directory into myapp and start the web server: <tt>script/server</tt> (run with --help for options) -3. Go to http://localhost:3000/ and get "Welcome aboard: You're riding the Rails!" -4. Follow the guidelines to start developing your application - - -== Web Servers - -By default, Rails will try to use Mongrel and lighttpd if they are installed, otherwise -Rails will use WEBrick, the webserver that ships with Ruby. When you run script/server, -Rails will check if Mongrel exists, then lighttpd and finally fall back to WEBrick. This ensures -that you can always get up and running quickly. - -Mongrel is a Ruby-based webserver with a C component (which requires compilation) that is -suitable for development and deployment of Rails applications. If you have Ruby Gems installed, -getting up and running with mongrel is as easy as: <tt>gem install mongrel</tt>. -More info at: http://mongrel.rubyforge.org - -If Mongrel is not installed, Rails will look for lighttpd. It's considerably faster than -Mongrel and WEBrick and also suited for production use, but requires additional -installation and currently only works well on OS X/Unix (Windows users are encouraged -to start with Mongrel). We recommend version 1.4.11 and higher. You can download it from -http://www.lighttpd.net. - -And finally, if neither Mongrel or lighttpd are installed, Rails will use the built-in Ruby -web server, WEBrick. WEBrick is a small Ruby web server suitable for development, but not -for production. - -But of course its also possible to run Rails on any platform that supports FCGI. -Apache, LiteSpeed, IIS are just a few. For more information on FCGI, -please visit: http://wiki.rubyonrails.com/rails/pages/FastCGI - - -== Apache .htaccess example - -# General Apache options -AddHandler fastcgi-script .fcgi -AddHandler cgi-script .cgi -Options +FollowSymLinks +ExecCGI - -# If you don't want Rails to look in certain directories, -# use the following rewrite rules so that Apache won't rewrite certain requests -# -# Example: -# RewriteCond %{REQUEST_URI} ^/notrails.* -# RewriteRule .* - [L] - -# Redirect all requests not available on the filesystem to Rails -# By default the cgi dispatcher is used which is very slow -# -# For better performance replace the dispatcher with the fastcgi one -# -# Example: -# RewriteRule ^(.*)$ dispatch.fcgi [QSA,L] -RewriteEngine On - -# If your Rails application is accessed via an Alias directive, -# then you MUST also set the RewriteBase in this htaccess file. -# -# Example: -# Alias /myrailsapp /path/to/myrailsapp/public -# RewriteBase /myrailsapp - -RewriteRule ^$ index.html [QSA] -RewriteRule ^([^.]+)$ $1.html [QSA] -RewriteCond %{REQUEST_FILENAME} !-f -RewriteRule ^(.*)$ dispatch.cgi [QSA,L] - -# In case Rails experiences terminal errors -# Instead of displaying this message you can supply a file here which will be rendered instead -# -# Example: -# ErrorDocument 500 /500.html - -ErrorDocument 500 "<h2>Application error</h2>Rails application failed to start properly" - - -== Debugging Rails - -Sometimes your application goes wrong. Fortunately there are a lot of tools that -will help you debug it and get it back on the rails. - -First area to check is the application log files. Have "tail -f" commands running -on the server.log and development.log. Rails will automatically display debugging -and runtime information to these files. Debugging info will also be shown in the -browser on requests from 127.0.0.1. - -You can also log your own messages directly into the log file from your code using -the Ruby logger class from inside your controllers. Example: - - class WeblogController < ActionController::Base - def destroy - @weblog = Weblog.find(params[:id]) - @weblog.destroy - logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!") - end - end - -The result will be a message in your log file along the lines of: - - Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1 - -More information on how to use the logger is at http://www.ruby-doc.org/core/ - -Also, Ruby documentation can be found at http://www.ruby-lang.org/ including: - -* The Learning Ruby (Pickaxe) Book: http://www.ruby-doc.org/docs/ProgrammingRuby/ -* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide) - -These two online (and free) books will bring you up to speed on the Ruby language -and also on programming in general. - - -== Debugger - -Debugger support is available through the debugger command when you start your Mongrel or -Webrick server with --debugger. This means that you can break out of execution at any point -in the code, investigate and change the model, AND then resume execution! -You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug' -Example: - - class WeblogController < ActionController::Base - def index - @posts = Post.find(:all) - debugger - end - end - -So the controller will accept the action, run the first line, then present you -with a IRB prompt in the server window. Here you can do things like: - - >> @posts.inspect - => "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>, - #<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]" - >> @posts.first.title = "hello from a debugger" - => "hello from a debugger" - -...and even better is that you can examine how your runtime objects actually work: - - >> f = @posts.first - => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}> - >> f. - Display all 152 possibilities? (y or n) - -Finally, when you're ready to resume execution, you enter "cont" - - -== Console - -You can interact with the domain model by starting the console through <tt>script/console</tt>. -Here you'll have all parts of the application configured, just like it is when the -application is running. You can inspect domain models, change values, and save to the -database. Starting the script without arguments will launch it in the development environment. -Passing an argument will specify a different environment, like <tt>script/console production</tt>. - -To reload your controllers and models after launching the console run <tt>reload!</tt> - -== dbconsole - -You can go to the command line of your database directly through <tt>script/dbconsole</tt>. -You would be connected to the database with the credentials defined in database.yml. -Starting the script without arguments will connect you to the development database. Passing an -argument will connect you to a different database, like <tt>script/dbconsole production</tt>. -Currently works for mysql, postgresql and sqlite. - -== Description of Contents - -app - Holds all the code that's specific to this particular application. - -app/controllers - Holds controllers that should be named like weblogs_controller.rb for - automated URL mapping. All controllers should descend from ApplicationController - which itself descends from ActionController::Base. - -app/models - Holds models that should be named like post.rb. - Most models will descend from ActiveRecord::Base. - -app/views - Holds the template files for the view that should be named like - weblogs/index.html.erb for the WeblogsController#index action. All views use eRuby - syntax. - -app/views/layouts - Holds the template files for layouts to be used with views. This models the common - header/footer method of wrapping views. In your views, define a layout using the - <tt>layout :default</tt> and create a file named default.html.erb. Inside default.html.erb, - call <% yield %> to render the view using this layout. - -app/helpers - Holds view helpers that should be named like weblogs_helper.rb. These are generated - for you automatically when using script/generate for controllers. Helpers can be used to - wrap functionality for your views into methods. - -config - Configuration files for the Rails environment, the routing map, the database, and other dependencies. - -db - Contains the database schema in schema.rb. db/migrate contains all - the sequence of Migrations for your schema. - -doc - This directory is where your application documentation will be stored when generated - using <tt>rake doc:app</tt> - -lib - Application specific libraries. Basically, any kind of custom code that doesn't - belong under controllers, models, or helpers. This directory is in the load path. - -public - The directory available for the web server. Contains subdirectories for images, stylesheets, - and javascripts. Also contains the dispatchers and the default HTML files. This should be - set as the DOCUMENT_ROOT of your web server. - -script - Helper scripts for automation and generation. - -test - Unit and functional tests along with fixtures. When using the script/generate scripts, template - test files will be generated for you and placed in this directory. - -vendor - External libraries that the application depends on. Also includes the plugins subdirectory. - If the app has frozen rails, those gems also go here, under vendor/rails/. - This directory is in the load path. Added: trunk/server/README.rdoc =================================================================== --- trunk/server/README.rdoc (rev 0) +++ trunk/server/README.rdoc 2012-04-20 23:22:38 UTC (rev 314) @@ -0,0 +1,261 @@ +== Welcome to Rails + +Rails is a web-application framework that includes everything needed to create +database-backed web applications according to the Model-View-Control pattern. + +This pattern splits the view (also called the presentation) into "dumb" +templates that are primarily responsible for inserting pre-built data in between +HTML tags. The model contains the "smart" domain objects (such as Account, +Product, Person, Post) that holds all the business logic and knows how to +persist themselves to a database. The controller handles the incoming requests +(such as Save New Account, Update Product, Show Post) by manipulating the model +and directing data to the view. + +In Rails, the model is handled by what's called an object-relational mapping +layer entitled Active Record. This layer allows you to present the data from +database rows as objects and embellish these data objects with business logic +methods. You can read more about Active Record in +link:files/vendor/rails/activerecord/README.html. + +The controller and view are handled by the Action Pack, which handles both +layers by its two parts: Action View and Action Controller. These two layers +are bundled in a single package due to their heavy interdependence. This is +unlike the relationship between the Active Record and Action Pack that is much +more separate. Each of these packages can be used independently outside of +Rails. You can read more about Action Pack in +link:files/vendor/rails/actionpack/README.html. + + +== Getting Started + +1. At the command prompt, create a new Rails application: + <tt>rails new myapp</tt> (where <tt>myapp</tt> is the application name) + +2. Change directory to <tt>myapp</tt> and start the web server: + <tt>cd myapp; rails server</tt> (run with --help for options) + +3. Go to http://localhost:3000/ and you'll see: + "Welcome aboard: You're riding Ruby on Rails!" + +4. Follow the guidelines to start developing your application. You can find +the following resources handy: + +* The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html +* Ruby on Rails Tutorial Book: http://www.railstutorial.org/ + + +== Debugging Rails + +Sometimes your application goes wrong. Fortunately there are a lot of tools that +will help you debug it and get it back on the rails. + +First area to check is the application log files. Have "tail -f" commands +running on the server.log and development.log. Rails will automatically display +debugging and runtime information to these files. Debugging info will also be +shown in the browser on requests from 127.0.0.1. + +You can also log your own messages directly into the log file from your code +using the Ruby logger class from inside your controllers. Example: + + class WeblogController < ActionController::Base + def destroy + @weblog = Weblog.find(params[:id]) + @weblog.destroy + logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!") + end + end + +The result will be a message in your log file along the lines of: + + Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1! + +More information on how to use the logger is at http://www.ruby-doc.org/core/ + +Also, Ruby documentation can be found at http://www.ruby-lang.org/. There are +several books available online as well: + +* Programming Ruby: http://www.ruby-doc.org/docs/ProgrammingRuby/ (Pickaxe) +* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide) + +These two books will bring you up to speed on the Ruby language and also on +programming in general. + + +== Debugger + +Debugger support is available through the debugger command when you start your +Mongrel or WEBrick server with --debugger. This means that you can break out of +execution at any point in the code, investigate and change the model, and then, +resume execution! You need to install ruby-debug to run the server in debugging +mode. With gems, use <tt>sudo gem install ruby-debug</tt>. Example: + + class WeblogController < ActionController::Base + def index + @posts = Post.all + debugger + end + end + +So the controller will accept the action, run the first line, then present you +with a IRB prompt in the server window. Here you can do things like: + + >> @posts.inspect + => "[#<Post:0x14a6be8 + @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>, + #<Post:0x14a6620 + @attributes={"title"=>"Rails", "body"=>"Only ten..", "id"=>"2"}>]" + >> @posts.first.title = "hello from a debugger" + => "hello from a debugger" + +...and even better, you can examine how your runtime objects actually work: + + >> f = @posts.first + => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}> + >> f. + Display all 152 possibilities? (y or n) + +Finally, when you're ready to resume execution, you can enter "cont". + + +== Console + +The console is a Ruby shell, which allows you to interact with your +application's domain model. Here you'll have all parts of the application +configured, just like it is when the application is running. You can inspect +domain models, change values, and save to the database. Starting the script +without arguments will launch it in the development environment. + +To start the console, run <tt>rails console</tt> from the application +directory. + +Options: + +* Passing the <tt>-s, --sandbox</tt> argument will rollback any modifications + made to the database. +* Passing an environment name as an argument will load the corresponding + environment. Example: <tt>rails console production</tt>. + +To reload your controllers and models after launching the console run +<tt>reload!</tt> + +More information about irb can be found at: +link:http://www.rubycentral.org/pickaxe/irb.html + + +== dbconsole + +You can go to the command line of your database directly through <tt>rails +dbconsole</tt>. You would be connected to the database with the credentials +defined in database.yml. Starting the script without arguments will connect you +to the development database. Passing an argument will connect you to a different +database, like <tt>rails dbconsole production</tt>. Currently works for MySQL, +PostgreSQL and SQLite 3. + +== Description of Contents + +The default directory structure of a generated Ruby on Rails application: + + |-- app + | |-- assets + | |-- images + | |-- javascripts + | `-- stylesheets + | |-- controllers + | |-- helpers + | |-- mailers + | |-- models + | `-- views + | `-- layouts + |-- config + | |-- environments + | |-- initializers + | `-- locales + |-- db + |-- doc + |-- lib + | `-- tasks + |-- log + |-- public + |-- script + |-- test + | |-- fixtures + | |-- functional + | |-- integration + | |-- performance + | `-- unit + |-- tmp + | |-- cache + | |-- pids + | |-- sessions + | `-- sockets + `-- vendor + |-- assets + `-- stylesheets + `-- plugins + +app + Holds all the code that's specific to this particular application. + +app/assets + Contains subdirectories for images, stylesheets, and JavaScript files. + +app/controllers + Holds controllers that should be named like weblogs_controller.rb for + automated URL mapping. All controllers should descend from + ApplicationController which itself descends from ActionController::Base. + +app/models + Holds models that should be named like post.rb. Models descend from + ActiveRecord::Base by default. + +app/views + Holds the template files for the view that should be named like + weblogs/index.html.erb for the WeblogsController#index action. All views use + eRuby syntax by default. + +app/views/layouts + Holds the template files for layouts to be used with views. This models the + common header/footer method of wrapping views. In your views, define a layout + using the <tt>layout :default</tt> and create a file named default.html.erb. + Inside default.html.erb, call <% yield %> to render the view using this + layout. + +app/helpers + Holds view helpers that should be named like weblogs_helper.rb. These are + generated for you automatically when using generators for controllers. + Helpers can be used to wrap functionality for your views into methods. + +config + Configuration files for the Rails environment, the routing map, the database, + and other dependencies. + +db + Contains the database schema in schema.rb. db/migrate contains all the + sequence of Migrations for your schema. + +doc + This directory is where your application documentation will be stored when + generated using <tt>rake doc:app</tt> + +lib + Application specific libraries. Basically, any kind of custom code that + doesn't belong under controllers, models, or helpers. This directory is in + the load path. + +public + The directory available for the web server. Also contains the dispatchers and the + default HTML files. This should be set as the DOCUMENT_ROOT of your web + server. + +script + Helper scripts for automation and generation. + +test + Unit and functional tests along with fixtures. When using the rails generate + command, template test files will be generated for you and placed in this + directory. + +vendor + External libraries that the application depends on. Also includes the plugins + subdirectory. If the app has frozen rails, those gems also go here, under + vendor/rails/. This directory is in the load path. Modified: trunk/server/Rakefile =================================================================== --- trunk/server/Rakefile 2012-03-21 23:30:16 UTC (rev 313) +++ trunk/server/Rakefile 2012-04-20 23:22:38 UTC (rev 314) @@ -1,10 +1,7 @@ +#!/usr/bin/env rake # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. -require(File.join(File.dirname(__FILE__), 'config', 'boot')) +require File.expand_path('../config/application', __FILE__) -require 'rake' -require 'rake/testtask' -require 'rake/rdoctask' - -require 'tasks/rails' +Server::Application.load_tasks Added: trunk/server/app/assets/images/rails.png =================================================================== (Binary files differ) Property changes on: trunk/server/app/assets/images/rails.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Added: trunk/server/app/assets/javascripts/application.js =================================================================== --- trunk/server/app/assets/javascripts/application.js (rev 0) +++ trunk/server/app/assets/javascripts/application.js 2012-04-20 23:22:38 UTC (rev 314) @@ -0,0 +1,15 @@ +// This is a manifest file that'll be compiled into application.js, which will include all the files +// listed below. +// +// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, +// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. +// +// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the +// the compiled file. +// +// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD +// GO AFTER THE REQUIRES BELOW. +// +//= require jquery +//= require jquery_ujs +//= require_tree . Copied: trunk/server/app/assets/javascripts/swfobject.js (from rev 313, trunk/server/public/javascripts/swfobject.js) =================================================================== --- trunk/server/app/assets/javascripts/swfobject.js (rev 0) +++ trunk/server/app/assets/javascripts/swfobject.js 2012-04-20 23:22:38 UTC (rev 314) @@ -0,0 +1,5 @@ +/* SWFObject v2.0 <http://code.google.com/p/swfobject/> + Copyright (c) 2007 Geoff Stearns, Michael Williams, and Bobby van der Sluis + This software is released under the MIT License <http://www.opensource.org/licenses/mit-license.php> +*/ +var swfobject=function(){var Z="undefined",P="object",B="Shockwave Flash",h="ShockwaveFlash.ShockwaveFlash",W="application/x-shockwave-flash",K="SWFObjectExprInst",G=window,g=document,N=navigator,f=[],H=[],Q=null,L=null,T=null,S=false,C=false;var a=function(){var l=typeof g.getElementById!=Z&&typeof g.getElementsByTagName!=Z&&typeof g.createElement!=Z&&typeof g.appendChild!=Z&&typeof g.replaceChild!=Z&&typeof g.removeChild!=Z&&typeof g.cloneNode!=Z,t=[0,0,0],n=null;if(typeof N.plugins!=Z&&typeof N.plugins[B]==P){n=N.plugins[B].description;if(n){n=n.replace(/^.*\s+(\S+\s+\S+$)/,"$1");t[0]=parseInt(n.replace(/^(.*)\..*$/,"$1"),10);t[1]=parseInt(n.replace(/^.*\.(.*)\s.*$/,"$1"),10);t[2]=/r/.test(n)?parseInt(n.replace(/^.*r(.*)$/,"$1"),10):0}}else{if(typeof G.ActiveXObject!=Z){var o=null,s=false;try{o=new ActiveXObject(h+".7")}catch(k){try{o=new ActiveXObject(h+".6");t=[6,0,21];o.AllowScriptAccess="always"}catch(k){if(t[0]==6){s=true}}if(!s){try{o=new ActiveXObject(h)}catch(k){}}}if(!s&&o){try{n=o.GetVariable("$version");if(n){n=n.split(" ")[1].split(",");t=[parseInt(n[0],10),parseInt(n[1],10),parseInt(n[2],10)]}}catch(k){}}}}var v=N.userAgent.toLowerCase(),j=N.platform.toLowerCase(),r=/webkit/.test(v)?parseFloat(v.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,i=false,q=j?/win/.test(j):/win/.test(v),m=j?/mac/.test(j):/mac/.test(v);/*@cc_on i=true;@if(@_win32)q=true;@elif(@_mac)m=true;@end@*/return{w3cdom:l,pv:t,webkit:r,ie:i,win:q,mac:m}}();var e=function(){if(!a.w3cdom){return }J(I);if(a.ie&&a.win){try{g.write("<script id=__ie_ondomload defer=true src=//:><\/script>");var i=c("__ie_ondomload");if(i){i.onreadystatechange=function(){if(this.readyState=="complete"){this.parentNode.removeChild(this);V()}}}}catch(j){}}if(a.webkit&&typeof g.readyState!=Z){Q=setInterval(function(){if(/loaded|complete/.test(g.readyState)){V()}},10)}if(typeof g.addEventListener!=Z){g.addEventListener("DOMContentLoaded",V,null)}M(V)}();function V(){if(S){return }if(a.ie&&a.win){var m=Y("span");try{var l=g.getElementsByTagName("body")[0].appendChild(m);l.parentNode.removeChild(l)}catch(n){return }}S=true;if(Q){clearInterval(Q);Q=null}var j=f.length;for(var k=0;k<j;k++){f[k]()}}function J(i){if(S){i()}else{f[f.length]=i}}function M(j){if(typeof G.addEventListener!=Z){G.addEventListener("load",j,false)}else{if(typeof g.addEventListener!=Z){g.addEventListener("load",j,false)}else{if(typeof G.attachEvent!=Z){G.attachEvent("onload",j)}else{if(typeof G.onload=="function"){var i=G.onload;G.onload=function(){i();j()}}else{G.onload=j}}}}}function I(){var l=H.length;for(var j=0;j<l;j++){var m=H[j].id;if(a.pv[0]>0){var k=c(m);if(k){H[j].width=k.getAttribute("width")?k.getAttribute("width"):"0";H[j].height=k.getAttribute("height")?k.getAttribute("height"):"0";if(O(H[j].swfVersion)){if(a.webkit&&a.webkit<312){U(k)}X(m,true)}else{if(H[j].expressInstall&&!C&&O("6.0.65")&&(a.win||a.mac)){D(H[j])}else{d(k)}}}}else{X(m,true)}}}function U(m){var k=m.getElementsByTagName(P)[0];if(k){var p=Y("embed"),r=k.attributes;if(r){var o=r.length;for(var n=0;n<o;n++){if(r[n].nodeName.toLowerCase()=="data"){p.setAttribute("src",r[n].nodeValue)}else{p.setAttribute(r[n].nodeName,r[n].nodeValue)}}}var q=k.childNodes;if(q){var s=q.length;for(var l=0;l<s;l++){if(q[l].nodeType==1&&q[l].nodeName.toLowerCase()=="param"){p.setAttribute(q[l].getAttribute("name"),q[l].getAttribute("value"))}}}m.parentNode.replaceChild(p,m)}}function F(i){if(a.ie&&a.win&&O("8.0.0")){G.attachEvent("onunload",function(){var k=c(i);if(k){for(var j in k){if(typeof k[j]=="function"){k[j]=function(){}}}k.parentNode.removeChild(k)}})}}function D(j){C=true;var o=c(j.id);if(o){if(j.altContentId){var l=c(j.altContentId);if(l){L=l;T=j.altContentId}}else{L=b(o)}if(!(/%$/.test(j.width))&&parseInt(j.width,10)<310){j.width="310"}if(!(/%$/.test(j.height))&&parseInt(j.height,10)<137){j.height="137"}g.title=g.title.slice(0,47)+" - Flash Player Installation";var n=a.ie&&a.win?"ActiveX":"PlugIn",k=g.title,m="MMredirectURL="+G.location+"&MMplayerType="+n+"&MMdoctitle="+k,p=j.id;if(a.ie&&a.win&&o.readyState!=4){var i=Y("div");p+="SWFObjectNew";i.setAttribute("id",p);o.parentNode.insertBefore(i,o);o.style.display="none";G.attachEvent("onload",function(){o.parentNode.removeChild(o)})}R({data:j.expressInstall,id:K,width:j.width,height:j.height},{flashvars:m},p)}}function d(j){if(a.ie&&a.win&&j.readyState!=4){var i=Y("div");j.parentNode.insertBefore(i,j);i.parentNode.replaceChild(b(j),i);j.style.display="none";G.attachEvent("onload",function(){j.parentNode.removeChild(j)})}else{j.parentNode.replaceChild(b(j),j)}}function b(n){var m=Y("div");if(a.win&&a.ie){m.innerHTML=n.innerHTML}else{var k=n.getElementsByTagName(P)[0];if(k){var o=k.childNodes;if(o){var j=o.length;for(var l=0;l<j;l++){if(!(o[l].nodeType==1&&o[l].nodeName.toLowerCase()=="param")&&!(o[l].nodeType==8)){m.appendChild(o[l].cloneNode(true))}}}}}return m}function R(AE,AC,q){var p,t=c(q);if(typeof AE.id==Z){AE.id=q}if(a.ie&&a.win){var AD="";for(var z in AE){if(AE[z]!=Object.prototype[z]){if(z=="data"){AC.movie=AE[z]}else{if(z.toLowerCase()=="styleclass"){AD+=' class="'+AE[z]+'"'}else{if(z!="classid"){AD+=" "+z+'="'+AE[z]+'"'}}}}}var AB="";for(var y in AC){if(AC[y]!=Object.prototype[y]){AB+='<param name="'+y+'" value="'+AC[y]+'" />'}}t.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+AD+">"+AB+"</object>";F(AE.id);p=c(AE.id)}else{if(a.webkit&&a.webkit<312){var AA=Y("embed");AA.setAttribute("type",W);for(var x in AE){if(AE[x]!=Object.prototype[x]){if(x=="data"){AA.setAttribute("src",AE[x])}else{if(x.toLowerCase()=="styleclass"){AA.setAttribute("class",AE[x])}else{if(x!="classid"){AA.setAttribute(x,AE[x])}}}}}for(var w in AC){if(AC[w]!=Object.prototype[w]){if(w!="movie"){AA.setAttribute(w,AC[w])}}}t.parentNode.replaceChild(AA,t);p=AA}else{var s=Y(P);s.setAttribute("type",W);for(var v in AE){if(AE[v]!=Object.prototype[v]){if(v.toLowerCase()=="styleclass"){s.setAttribute("class",AE[v])}else{if(v!="classid"){s.setAttribute(v,AE[v])}}}}for(var u in AC){if(AC[u]!=Object.prototype[u]&&u!="movie"){E(s,u,AC[u])}}t.parentNode.replaceChild(s,t);p=s}}return p}function E(k,i,j){var l=Y("param");l.setAttribute("name",i);l.setAttribute("value",j);k.appendChild(l)}function c(i){return g.getElementById(i)}function Y(i){return g.createElement(i)}function O(k){var j=a.pv,i=k.split(".");i[0]=parseInt(i[0],10);i[1]=parseInt(i[1],10);i[2]=parseInt(i[2],10);return(j[0]>i[0]||(j[0]==i[0]&&j[1]>i[1])||(j[0]==i[0]&&j[1]==i[1]&&j[2]>=i[2]))?true:false}function A(m,j){if(a.ie&&a.mac){return }var l=g.getElementsByTagName("head")[0],k=Y("style");k.setAttribute("type","text/css");k.setAttribute("media","screen");if(!(a.ie&&a.win)&&typeof g.createTextNode!=Z){k.appendChild(g.createTextNode(m+" {"+j+"}"))}l.appendChild(k);if(a.ie&&a.win&&typeof g.styleSheets!=Z&&g.styleSheets.length>0){var i=g.styleSheets[g.styleSheets.length-1];if(typeof i.addRule==P){i.addRule(m,j)}}}function X(k,i){var j=i?"visible":"hidden";if(S){c(k).style.visibility=j}else{A("#"+k,"visibility:"+j)}}return{registerObject:function(l,i,k){if(!a.w3cdom||!l||!i){return }var j={};j.id=l;j.swfVersion=i;j.expressInstall=k?k:false;H[H.length]=j;X(l,false)},getObjectById:function(l){var i=null;if(a.w3cdom&&S){var j=c(l);if(j){var k=j.getElementsByTagName(P)[0];if(!k||(k&&typeof j.SetVariable!=Z)){i=j}else{if(typeof k.SetVariable!=Z){i=k}}}}return i},embedSWF:function(n,u,r,t,j,m,k,p,s){if(!a.w3cdom||!n||!u||!r||!t||!j){return }r+="";t+="";if(O(j)){X(u,false);var q=(typeof s==P)?s:{};q.data=n;q.width=r;q.height=t;var o=(typeof p==P)?p:{};if(typeof k==P){for(var l in k){if(k[l]!=Object.prototype[l]){if(typeof o.flashvars!=Z){o.flashvars+="&"+l+"="+k[l]}else{o.flashvars=l+"="+k[l]}}}}J(function(){R(q,o,u);if(q.id==u){X(u,true)}})}else{if(m&&!C&&O("6.0.65")&&(a.win||a.mac)){X(u,false);J(function(){var i={};i.id=i.altContentId=u;i.width=r;i.height=t;i.expressInstall=m;D(i)})}}},getFlashPlayerVersion:function(){return{major:a.pv[0],minor:a.pv[1],release:a.pv[2]}},hasFlashPlayerVersion:O,createSWF:function(k,j,i){if(a.w3cdom&&S){return R(k,j,i)}else{return undefined}},createCSS:function(j,i){if(a.w3cdom){A(j,i)}},addDomLoadEvent:J,addLoadEvent:M,getQueryParamValue:function(m){var l=g.location.search||g.location.hash;if(m==null){return l}if(l){var k=l.substring(1).split("&");for(var j=0;j<k.length;j++){if(k[j].substring(0,k[j].indexOf("="))==m){return k[j].substring((k[j].indexOf("=")+1))}}}return""},expressInstallCallback:function(){if(C&&L){var i=c(K);if(i){i.parentNode.replaceChild(L,i);if(T){X(T,true);if(a.ie&&a.win){L.style.display="block"}}L=null;T=null;C=false}}}}}(); \ No newline at end of file Added: trunk/server/app/assets/stylesheets/application.css =================================================================== --- trunk/server/app/assets/stylesheets/application.css (rev 0) +++ trunk/server/app/assets/stylesheets/application.css 2012-04-20 23:22:38 UTC (rev 314) @@ -0,0 +1,13 @@ +/* + * This is a manifest file that'll be compiled into application.css, which will include all the files + * listed below. + * + * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, + * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. + * + * You're free to add application-wide styles to this file and they'll appear at the top of the + * compiled file, but it's generally better to create a new file per style scope. + * + *= require_self + *= require_tree . +*/ Copied: trunk/server/app/assets/stylesheets/design.css (from rev 313, trunk/server/public/stylesheets/design.css) =================================================================== --- trunk/server/app/assets/stylesheets/design.css (rev 0) +++ trunk/server/app/assets/stylesheets/design.css 2012-04-20 23:22:38 UTC (rev 314) @@ -0,0 +1,349 @@ +body +{ + font-family: Arial, Helvetica, sans-serif; + font-size: 90%; + margin: 0; + padding: 0; +} + +#header +{ + color: #fff; + height: 30px; + background-color: #036; +} + +#header a +{ + color: #fff; +} + +#branding +{ + margin: 0; + padding: 10px 0 0 10px; + font-size: 125%; + line-height: 10px; + text-shadow: black 2px 2px 3px; +} + +#branding a { text-decoration: none; } + +#account_links +{ + float: right; + text-shadow: black 2px 2px 3px; + margin: 0 10px 0 0; + padding: 0; + line-height: 30px; +} + +#sidepanel +{ + width: 15em; + position: absolute; + top: 30px; + left: 0; + padding: .5em 1em; +} + +#sidepanel h3, +#dashboard_menu h3 +{ + color: #000; + margin: 0; + padding: 0 0 .5em 0; +} + +#sidepanel p, +#dashboard_menu p +{ + margin: 0; + padding: 1em 0; +} + +#sidepanel ul, +#dashboard_menu ul +{ + list-style: none; + margin: 0 0 1em 0; + padding: 0 0 0 .5em; +} + +#sidepanel ul li, +#dashboard_menu ul li +{ + margin: 0 0 .2em 0; +} + +#sidepanel ul li ul, +#dashboard_menu ul li ul +{ + margin: 0; +} + +#content +{ + margin: 0 0 0 17em; + padding: 1em; +} + +#content h1, +#content h2, +#content h3, +#content h4, +#content p { margin-top: 0; } + +table.styled +{ + border-collapse: collapse; + width: 100%; + border-color: #666; + border-width: 1px; + border-style: solid; + margin-bottom: 1em; +} + +table.styled th, +table.styled td { padding: 0.3em 1em; } + +table.styled caption +{ + font-size: 1.3em; + font-weight: bold; + text-align: left; +} + +table.styled thead +{ + background-color: #999; + color: #fff; + text-align: left; + +} + +table.styled thead a { color: #fff; } +{ + color: #fff; + background-color: #666; +} + + +table.styled .even +{ + background-color: #eee; +} + +table.styled .odd +{ + background-color: #fff; +} + + +table.styled tbody tr:hover, +table.styled tbody tr:hover a +{ + background-color: #369; + color: #fff; +} + + + +table.arversions +{ + border-collapse: collapse; + width: 100%; + border-color: #666; + border-width: 1px; + border-style: solid; + margin-bottom: 1em; +} + +table.arversions th, +table.arversions td { padding: 0.3em 1em; } + +table.arversions caption +{ + font-size: 1.3em; + font-weight: bold; + text-align: left; +} + +table.arversions thead +{ + background-color: #999; + color: #fff; + text-align: left; + +} + +table.arversions .even +{ + background-color: #eee; +} + +table.arversions del +{ + color: red; +} + +table.arversions ins +{ + color: green; + text-decoration: none; +} + + +table.arattributes th { text-align: right; } + +.arversion_date { color: #999; } + + +.record_view +{ + background-color: #eee; + border-color: #ccc; + border-width: 1px 0; + border-style: solid; + padding: 1em 1em 0 1em; + margin-bottom: 1em; +} + +.record_view p { line-height: 130%; } + +.record_view .note +{ + color: grey; + font-weight: normal; +} + +.edit_record_form em +{ + color: red; + font-style: normal; +} + +.relationship +{ + background-color: #FFF4E6; + border-color: #FF8A00; + border-width: 1px 0; + border-style: solid; + padding: 1em 1em 0 1em; + margin-bottom: 1em; +} + +.smartrelationship +{ + background-color: #FFE; + border-color: #FF0; + border-width: 1px 0 1px 0; + border-style: solid; + padding: 1em 1em 0 1em; + margin-bottom: 1em; +} + +/* Visualization of the racks */ + +.v_rack +{ + margin: 0; + padding: .5em; + font-size: 12px; + font-family: Verdana, Arial, Helvetica, sans-serif; +} + +.v_rack_name +{ + font-size: 18px; + font-weight: bold; +} + +.v_rack_container +{ + background-color: #D3EEFF; + padding: 5px; + border-color: #036; + border-width: 1px 0 1px 0; + border-style: solid; +} + +ul.v_rack_node +{ + margin: 0; + padding: 0; + list-style: none; +} + +ul.v_rack_node li a +{ + border-color: #000; + border-width: 1px; + border-style: solid; + margin-top: 3px; + padding: 4px 5px; + display: block; + text-decoration: none; + color: black; + overflow: hidden; +} + +table.network_summary +{ + width: 100%; + background-color: #D3EEFF; + border-color: #036; + border-width: 1px; + border-style: solid; + margin-bottom: 1em; +} +table.network_summary td +{ + width: 50%; +} + +table.network_summary caption +{ + font-size: 1.3em; + font-weight: bold; + text-align: left; +} + +#dashboard_body { margin-right: 25em; } + +#dashboard_menu +{ + width: 23em; + float: right; +} + +#loginbox +{ + background-color: #eee; + border-color: #ccc; + border-width: 1px 0; + border-style: solid; + padding: 1em 1em 0 1em; + margin: 1em auto 0 auto; + width: 300px; +} + +#loginbox p { text-align: right; } + +#status_chart +{ + /* Center this chart */ + margin-left: auto; + margin-right: auto; + /* The chart is defined as 300px wide when created in the dashboard controller */ + width: 300px; +} +#client_chart +{ + margin-left: auto; + margin-right: auto; + width: 500px; +} + +/* Hide all HRs, they are only meant for print, or non CSS browsers */ +hr { display: none; } \ No newline at end of file Copied: trunk/server/app/assets/stylesheets/forms.css (from rev 313, trunk/server/public/stylesheets/forms.css) =================================================================== --- trunk/server/app/assets/stylesheets/forms.css (rev 0) +++ trunk/server/app/assets/stylesheets/forms.css 2012-04-20 23:22:38 UTC (rev 314) @@ -0,0 +1,60 @@ +form +{ + margin: 0; + padding: 0; +} + +#errorExplanation +{ + border-color: #c00; + border-width: 1px; + border-style: solid; + width: 90%; + margin: 1em auto; + font-size: 14px; + background-color: #eee; +} + +#errorExplanation p { margin: 1em; } + +#errorExplanation h2 +{ + margin: 0; + background-color: #c00; + color: #fff; + font-size: 14px; + letter-spacing: 1px; + padding: 5px 10px; +} + +.fieldWithErrors +{ + margin: 0; + display: inline; + border-color: #c00; + border-width: 0 3px; + border-style: solid; + padding: 2px 4px; +} + +#notice +{ + background-color: #cfc; + border-color: #090; + border-width: 1px 0; + border-style: solid; + padding: 5px 10px; + font-size: 14px; + margin: 1em 0; +} + +#error +{ + background-color: #FCC; + border-color: #c00; + border-width: 1px 0; + border-style: solid; + padding: 5px 10px; + font-size: 14px; + margin: 1em 0; +} \ No newline at end of file Modified: trunk/server/app/controllers/application_controller.rb =================================================================== --- trunk/server/app/controllers/application_controller.rb 2012-03-21 23:30:16 UTC (rev 313) +++ trunk/server/app/controllers/application_controller.rb 2012-04-20 23:22:38 UTC (rev 314) @@ -4,17 +4,6 @@ # Likewise, all the methods added will be available for all controllers. class ApplicationController < ActionController::Base - helper :all # include all helpers, all the time - - # See ActionController::Base for details - # Uncomment this to filter the contents of submitted sensitive data parameters - # from your application log (in this case, all fields with names like "password"). - # filter_parameter_logging :password - - # Turn on the exception_notification plugin - # See environment.rb for the email address(s) to which exceptions are mailed - include ExceptionNotifiable - # Verify that any changes are signed if the administrator has # enabled authentication before_filter :authenticate, :only => [:create, :update, :destroy] @@ -46,21 +35,4 @@ end end end - - # find and to_xml take their :include options in different formats - # find wants: - # :include => { :rack => { :datacenter_rack_assignment => :datacenter } } - # or this (which is what we use because it is easier to generate recursively) - # :include => { :rack => { :datacenter_rack_assignment => { :datacenter => {} } } } - # to_xml wants: - # :include => { :rack => { :include => { :datacenter_rack_assignment => { :include => { :datacenter => {} } } } } } - # This method takes the find format and returns the to_xml format - def convert_includes(includes) - includes.each do |key, value| - unless (value.nil? || value.blank?) - includes[key] = { :include => convert_includes(value) } - end - end - includes - end end Modified: trunk/server/app/controllers/clients_controller.rb =================================================================== --- trunk/server/app/controllers/clients_controller.rb 2012-03-21 23:30:16 UTC (rev 313) +++ trunk/server/app/controllers/clients_controller.rb 2012-04-20 23:22:38 UTC (rev 314) @@ -3,79 +3,37 @@ class ClientsController < ApplicationController # GET /clients def index - includes = {} - - sort = case params[:sort] - when 'client' then 'clients.name' - when 'client_reverse' then 'clients.name DESC' - when 'status' then 'clients.status' - when 'status_reverse' then 'clients.status DESC' - when 'updated_at' then 'clients.updated_at' - when 'updated_at_reverse' then 'clients.updated_at DESC' - end - # If a sort was not defined we'll make one default - if sort.nil? - params[:sort] = 'client' - sort = 'clients.name' + # The dashboard has some custom search links for various health + # categories. If the user selected one then use the appropriate scope as + # the starting point for further filtering rather than all clients. + scope = nil + case params['health'] + when 'healthy' + scope = Client.healthy + when 'broken' + scope = Client.broken + when 'disabled' + scope = Client.disabled + when 'stale' + scope = Client.stale + else + scope = Client end - # Parse all other params as search query args - allowed_queries = ['name', 'status', 'updated_at'] - conditions_query = [] - conditions_values = [] - params.each_pair do |key, value| - next if key == 'action' - next if key == 'controller' - next if key == 'format' - next if key == 'page' - next if key == 'sort' - - if key == 'health' - if value == 'healthy' - conditions_query << "status = 0 AND updated_at > ?" - conditions_values << 24.hours.ago - elsif value == 'broken' - conditions_query << "status != 0 AND status != 200 AND updated_at > ?" - conditions_values << 24.hours.ago - elsif value == 'disabled' - conditions_query << "status = 200 AND updated_at > ?" - conditions_values << 24.hours.ago - elsif value == 'stale' - conditions_query << "updated_at <= ?" - conditions_values << 24.hours.ago - end - elsif key == 'name_substring' - conditions_query << "name LIKE ?" - conditions_values << '%' + value + '%' - elsif key == 'updated_since' - conditions_query << "updated_at >= ?" - conditions_values << value.to_i.hours.ago - elsif key == 'not_updated_since' - conditions_query << "updated_at < ?" - conditions_values << value.to_i.hours.ago - elsif allowed_queries.include?(key) - conditions_query << "#{key} = ?" - conditions_values << value - end + # Clients requesting XML get no pagination (all entries) + per_page = Client.per_page # will_paginate's default value + respond_to do |format| + format.html {} + format.xml { per_page = Integer::MAX } end - conditions_string = conditions_query.join(' AND ') - per_page = Client.per_page # will_paginate's default value - # Client's requesting XML get all entries - respond_to { |format| format.html {}; format.xml { per_page = Integer::MAX } } + @q = scope.search(params[:q]) + @clients = @q.result.paginate(:page => params[:page], :per_page => per_page) - @clients = Client.paginate(:all, - :include => includes, - :conditions => [ conditions_string, *conditions_values ], - :order => sort, - :page => params[:page], - :per_page => per_page) - respond_to do |format| format.html # index.html.erb format.xml do - render :xml => @clients.to_xml(:include => convert_includes(includes), - :dasherize => false) + render :xml => @clients.to_xml(:dasherize => false) end end end @@ -90,8 +48,7 @@ @client = Client.find(params[:id]) respond_to do |format| format.html # show.html.erb - format.xml { render :xml => @client.to_xml(:include => convert_includes(includes), - :dasherize => false) } + format.xml { render :xml => @client.to_xml(:dasherize => false) } end end Modified: trunk/server/app/controllers/dashboard_controller.rb =================================================================== --- trunk/server/app/controllers/dashboard_controller.rb 2012-03-21 23:30:16 UTC (rev 313) +++ trunk/server/app/controllers/dashboard_controller.rb 2012-04-20 23:22:38 UTC (rev 314) @@ -3,14 +3,14 @@ class DashboardController < ApplicationController def set_counts @total_count = Client.count - @healthy_count = Client.count(:conditions => ["status = 0 AND updated_at > ?", 24.hours.ago]) - @broken_count = Client.count(:conditions => ["status != 0 AND status != 200 AND updated_at > ?", 24.hours.ago]) - @disabled_count = Client.count(:conditions => ["status = 200 AND updated_at > ?", 24.hours.ago]) - @stale_count = Client.count(:conditions => ["updated_at <= ?", 24.hours.ago]) + @healthy_count = Client.healthy.count + @broken_count = Client.broken.count + @disabled_count = Client.disabled.count + @stale_count = Client.stale.count end def set_charts - @status_chart = open_flash_chart_object(300, 300, url_for( :action => 'chart', :chart => 'status', :format => :json )) - @client_chart = open_flash_chart_object(500, 300, url_for( :action => 'chart', :chart => 'client', :format => :json )) + @status_chart = open_flash_chart_object(300, 300, url_for( :action => 'chart', :chart => 'status', :format => :json )).html_safe + @client_chart = open_flash_chart_object(500, 300, url_for( :action => 'chart', :chart => 'client', :format => :json )).html_safe end def index @@ -55,8 +55,8 @@ chart.x_axis = nil - render :text => chart, :layout => false - return + debug chart.render + render :text => chart.render and return when 'client' clients = [] months = [] @@ -104,8 +104,7 @@ chart.add_element(line_dot) - render :text => chart.to_s - return + render :text => chart.render and return end } end Modified: trunk/server/app/controllers/etch_configs_controller.rb =================================================================== --- trunk/server/app/controllers/etch_configs_controller.rb 2012-03-21 23:30:16 UTC (rev 313) +++ trunk/server/app/controllers/etch_configs_controller.rb 2012-04-20 23:22:38 UTC (rev 314) @@ -10,8 +10,8 @@ format.xml { per_page = Integer::MAX } end - @search = EtchConfig.search(params[:search]) - @etch_configs = @search.paginate(:page => params[:page], :per_page => per_page) + @q = EtchConfig.search(params[:q]) + @etch_configs = @q.result.paginate(:page => params[:page], :per_page => per_page) respond_to do |format| format.html # index.html.erb Modified: trunk/server/app/controllers/facts_controller.rb =================================================================== --- trunk/server/app/controllers/facts_controller.rb 2012-03-21 23:30:16 UTC (rev 313) +++ trunk/server/app/controllers/facts_controller.rb 2012-04-20 23:22:38 UTC (rev 314) @@ -10,8 +10,8 @@ format.xml { per_page = Integer::MAX } end - @search = Fact.search(params[:search]) - @facts = @search.paginate(:page => params[:page], :per_page => per_page) + @q = Fact.search(params[:q]) + @facts = @q.result.paginate(:page => params[:page], :per_page => per_page) respond_to do |format| format.html # index.html.erb Modified: trunk/server/app/controllers/originals_controller.rb =================================================================== --- trunk/server/app/controllers/originals_controller.rb 2012-03-21 23:30:16 UTC (rev 313) +++ trunk/server/app/controllers/originals_controller.rb 2012-04-20 23:22:38 UTC (rev 314) @@ -10,8 +10,8 @@ format.xml { per_page = Integer::MAX } end - @search = Original.search(params[:search]) - @originals = @search.paginate(:page => params[:page], :per_page => per_page) + @q = Original.search(params[:q]) + @originals = @q.result.paginate(:page => params[:page], :per_page => per_page) respond_to do |format| format.html # index.html.erb Modified: trunk/server/app/controllers/results_controller.rb =================================================================== --- trunk/server/app/controllers/results_controller.rb 2012-03-21 23:30:16 UTC (rev 313) +++ trunk/server/app/controllers/results_controller.rb 2012-04-20 23:22:38 UTC (rev 314) @@ -3,83 +3,27 @@ class ResultsController < ApplicationController # GET /results def index - includes = {} + @combined = params[:combined] + @query_string = request.query_string - # The index page uses clients.name, so always include it in the includes. - # Otherwise there's a SQL lookup for each row - includes[:client] = {} - - sort = case params[:sort] - when 'client' then includes[:client] = {}; 'clients.name' - when 'client_reverse' then includes[:client] = {}; 'clients.name DESC' - when 'file' then 'results.file' - when 'file_reverse' then 'results.file DESC' - when 'created_at' then 'results.created_at' - when 'created_at_reverse' then 'results.created_at DESC' - when 'success' then 'results.success' - wh... [truncated message content] |
From: <jh...@us...> - 2012-03-21 23:30:22
|
Revision: 313 http://etch.svn.sourceforge.net/etch/?rev=313&view=rev Author: jheiss Date: 2012-03-21 23:30:16 +0000 (Wed, 21 Mar 2012) Log Message: ----------- Update with 3.20.1 version Modified Paths: -------------- trunk/client/packages/macports/Portfile Modified: trunk/client/packages/macports/Portfile =================================================================== --- trunk/client/packages/macports/Portfile 2012-03-21 23:23:46 UTC (rev 312) +++ trunk/client/packages/macports/Portfile 2012-03-21 23:30:16 UTC (rev 313) @@ -5,7 +5,7 @@ PortGroup ruby 1.0 name etch -version 3.20.0 +version 3.20.1 categories sysutils maintainers aput.net:jheiss openmaintainer supported_archs noarch @@ -27,8 +27,8 @@ master_sites sourceforge:project/etch/etch/${version} -checksums rmd160 7f6525673bc636f3128268bf9ed6420c7098ff15 \ - sha256 3245e1187bd635e112daf954f0b30945ff522f16c4084290005ae962da932c1b +checksums rmd160 c93fdb584928b25433c99b1fde430eef2b6f8deb \ + sha256 38a39c27edeaef03aa2f72417a481717030b34e7990d723ea1299a7bc6eac540 depends_build port:rb-rake depends_run port:facter This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2012-03-21 23:23:52
|
Revision: 312 http://etch.svn.sourceforge.net/etch/?rev=312&view=rev Author: jheiss Date: 2012-03-21 23:23:46 +0000 (Wed, 21 Mar 2012) Log Message: ----------- Tag 3.20.1 release Modified Paths: -------------- Rakefile tags/release-3.20.1/VERSION Added Paths: ----------- tags/release-3.20.1/ Modified: Rakefile =================================================================== --- Rakefile 2012-03-21 21:12:32 UTC (rev 311) +++ Rakefile 2012-03-21 23:23:46 UTC (rev 312) @@ -1,4 +1,4 @@ -ETCHVER = '3.20.0' +ETCHVER = '3.20.1' TAGNAME = "release-#{ETCHVER}" TAGDIR = "tags/#{TAGNAME}" DIST = "etch-#{ETCHVER}" Modified: tags/release-3.20.1/VERSION =================================================================== --- trunk/VERSION 2012-03-21 21:12:32 UTC (rev 311) +++ tags/release-3.20.1/VERSION 2012-03-21 23:23:46 UTC (rev 312) @@ -1 +1 @@ -trunk +3.20.1 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sal...@us...> - 2012-03-21 21:12:38
|
Revision: 311 http://etch.svn.sourceforge.net/etch/?rev=311&view=rev Author: saltmanm Date: 2012-03-21 21:12:32 +0000 (Wed, 21 Mar 2012) Log Message: ----------- Show the ArgumentError messages only when in debug mode. Modified Paths: -------------- trunk/client/lib/etch/client.rb Modified: trunk/client/lib/etch/client.rb =================================================================== --- trunk/client/lib/etch/client.rb 2012-03-19 14:39:16 UTC (rev 310) +++ trunk/client/lib/etch/client.rb 2012-03-21 21:12:32 UTC (rev 311) @@ -2250,7 +2250,7 @@ pw = Etc.getpwnam(user) uid = pw.uid rescue ArgumentError - puts "config.xml requests user #{user}, but that user can't be found. Using UID 0." + puts "config.xml requests user #{user}, but that user can't be found. Using UID 0." if @debug uid = 0 end end @@ -2270,7 +2270,7 @@ gr = Etc.getgrnam(group) gid = gr.gid rescue ArgumentError - puts "config.xml requests group #{group}, but that group can't be found. Using GID 0." + puts "config.xml requests group #{group}, but that group can't be found. Using GID 0." if @debug gid = 0 end end This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2012-03-19 14:39:26
|
Revision: 310 http://etch.svn.sourceforge.net/etch/?rev=310&view=rev Author: jheiss Date: 2012-03-19 14:39:16 +0000 (Mon, 19 Mar 2012) Log Message: ----------- Update from 3.20.0 release Modified Paths: -------------- trunk/client/packages/macports/Portfile Modified: trunk/client/packages/macports/Portfile =================================================================== --- trunk/client/packages/macports/Portfile 2012-03-19 14:38:56 UTC (rev 309) +++ trunk/client/packages/macports/Portfile 2012-03-19 14:39:16 UTC (rev 310) @@ -5,9 +5,11 @@ PortGroup ruby 1.0 name etch -version 3.17.0 +version 3.20.0 categories sysutils maintainers aput.net:jheiss openmaintainer +supported_archs noarch +license MIT description Etch is a system configuration management tool. @@ -23,17 +25,15 @@ homepage http://etch.sourceforge.net/ platforms darwin -master_sites sourceforge +master_sites sourceforge:project/etch/etch/${version} -checksums md5 9b5216f62d4add225f50984cc07f630b \ - sha1 a4bc1c61f349464ca793d858abeca08760bde6e5 \ - rmd160 f827b360c69cceab1a864b11c7cf434b7c7a4a39 +checksums rmd160 7f6525673bc636f3128268bf9ed6420c7098ff15 \ + sha256 3245e1187bd635e112daf954f0b30945ff522f16c4084290005ae962da932c1b depends_build port:rb-rake depends_run port:facter worksrcdir ${worksrcdir}/client -supported_archs noarch use_configure no build {} destroot.cmd ${prefix}/bin/rake This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2012-03-19 14:39:06
|
Revision: 309 http://etch.svn.sourceforge.net/etch/?rev=309&view=rev Author: jheiss Date: 2012-03-19 14:38:56 +0000 (Mon, 19 Mar 2012) Log Message: ----------- Update macports template to latest macports standards. Fix a bug in the Rakefile related to client directory structure changes. Modified Paths: -------------- trunk/client/Rakefile trunk/client/packages/macports/Portfile.template Modified: trunk/client/Rakefile =================================================================== --- trunk/client/Rakefile 2012-03-19 11:58:44 UTC (rev 308) +++ trunk/client/Rakefile 2012-03-19 14:38:56 UTC (rev 309) @@ -53,7 +53,7 @@ # Substitute ETCHVER into etch/client.rb # Substitute proper path into CONFIGDIR in etch/client.rb if appropriate File.open(File.join(libdir, 'etch', 'client.rb'), 'w') do |newfile| - IO.foreach(File.join('etch', 'client.rb')) do |line| + IO.foreach(File.join('lib', 'etch', 'client.rb')) do |line| if line =~ /^\s*VERSION/ line.sub!(/=.*/, "= '#{ETCHVER}'") end @@ -390,6 +390,7 @@ md5 = `openssl md5 #{TARBALL}`.chomp.split.last sha1 = `openssl sha1 #{TARBALL}`.chomp.split.last rmd160 = `openssl rmd160 #{TARBALL}`.chomp.split.last + sha256 = `openssl sha256 #{TARBALL}`.chomp.split.last portfile = File.join(Dir.tmpdir, 'Portfile') rm_f(portfile) @@ -399,6 +400,7 @@ line.sub!('%MD5%', md5) line.sub!('%SHA1%', sha1) line.sub!('%RMD160%', rmd160) + line.sub!('%SHA256%', sha256) newfile.puts(line) end end Modified: trunk/client/packages/macports/Portfile.template =================================================================== --- trunk/client/packages/macports/Portfile.template 2012-03-19 11:58:44 UTC (rev 308) +++ trunk/client/packages/macports/Portfile.template 2012-03-19 14:38:56 UTC (rev 309) @@ -9,6 +9,7 @@ categories sysutils maintainers aput.net:jheiss openmaintainer supported_archs noarch +license MIT description Etch is a system configuration management tool. @@ -24,17 +25,15 @@ homepage http://etch.sourceforge.net/ platforms darwin -master_sites sourceforge +master_sites sourceforge:project/etch/etch/${version} -checksums md5 %MD5% \ - sha1 %SHA1% \ - rmd160 %RMD160% +checksums rmd160 %RMD160% \ + sha256 %SHA256% depends_build port:rb-rake depends_run port:facter worksrcdir ${worksrcdir}/client -supported_archs noarch use_configure no build {} destroot.cmd ${prefix}/bin/rake This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2012-03-19 11:58:56
|
Revision: 308 http://etch.svn.sourceforge.net/etch/?rev=308&view=rev Author: jheiss Date: 2012-03-19 11:58:44 +0000 (Mon, 19 Mar 2012) Log Message: ----------- Tag 3.20.0 release Modified Paths: -------------- Rakefile tags/release-3.20.0/VERSION Added Paths: ----------- tags/release-3.20.0/ tags/release-3.20.0/client/lib/etch/client.rb Removed Paths: ------------- tags/release-3.20.0/client/lib/etch/client.rb Modified: Rakefile =================================================================== --- Rakefile 2012-03-18 15:28:44 UTC (rev 307) +++ Rakefile 2012-03-19 11:58:44 UTC (rev 308) @@ -1,4 +1,4 @@ -ETCHVER = '3.19.0' +ETCHVER = '3.20.0' TAGNAME = "release-#{ETCHVER}" TAGDIR = "tags/#{TAGNAME}" DIST = "etch-#{ETCHVER}" Modified: tags/release-3.20.0/VERSION =================================================================== --- trunk/VERSION 2012-03-03 16:21:43 UTC (rev 306) +++ tags/release-3.20.0/VERSION 2012-03-19 11:58:44 UTC (rev 308) @@ -1 +1 @@ -trunk +3.20.0 Deleted: tags/release-3.20.0/client/lib/etch/client.rb =================================================================== --- trunk/client/lib/etch/client.rb 2012-03-03 16:21:43 UTC (rev 306) +++ tags/release-3.20.0/client/lib/etch/client.rb 2012-03-19 11:58:44 UTC (rev 308) @@ -1,2575 +0,0 @@ -############################################################################## -# Etch configuration file management tool library -############################################################################## - -# Ensure we can find etch.rb if run within the development directory structure -# This is roughly equivalent to "../../../server/lib" -serverlibdir = File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'server', 'lib') -if File.exist?(serverlibdir) - $:.unshift(serverlibdir) -end - -# Exclude standard libraries and gems from the warnings induced by -# running ruby with the -w flag. Several of these have warnings under -# ruby 1.9 and there's nothing we can do to fix that. -require 'silently' -Silently.silently do - begin - # Try loading facter w/o gems first so that we don't introduce a - # dependency on gems if it is not needed. - require 'facter' # Facter - rescue LoadError - require 'rubygems' - require 'facter' - end - require 'find' - require 'digest/sha1' # hexdigest - require 'openssl' # OpenSSL - require 'base64' # decode64, encode64 - require 'uri' - require 'net/http' - require 'net/https' - require 'rexml/document' - require 'fileutils' # copy, mkpath, rmtree - require 'fcntl' # Fcntl::O_* - require 'etc' # getpwnam, getgrnam - require 'tempfile' # Tempfile - require 'find' # Find.find - require 'cgi' - require 'timeout' - require 'logger' -end -require 'etch' - -class Etch::Client - VERSION = 'unset' - - CONFIRM_PROCEED = 1 - CONFIRM_SKIP = 2 - CONFIRM_QUIT = 3 - PRIVATE_KEY_PATHS = ["/etc/ssh/ssh_host_rsa_key", "/etc/ssh_host_rsa_key"] - DEFAULT_CONFIGDIR = '/etc' - DEFAULT_VARDIR = '/var/etch' - DEFAULT_DETAILED_RESULTS = ['SERVER'] - - # We need these in relation to the output capturing - ORIG_STDOUT = STDOUT.dup - ORIG_STDERR = STDERR.dup - - attr_reader :exec_once_per_run - - def initialize(options) - @server = options[:server] ? options[:server] : 'https://etch' - @configdir = options[:configdir] ? options[:configdir] : DEFAULT_CONFIGDIR - @vardir = options[:vardir] ? options[:vardir] : DEFAULT_VARDIR - @tag = options[:tag] - @local = options[:local] ? File.expand_path(options[:local]) : nil - @debug = options[:debug] - @dryrun = options[:dryrun] - @listfiles = options[:listfiles] - @interactive = options[:interactive] - @filenameonly = options[:filenameonly] - @fullfile = options[:fullfile] - @key = options[:key] ? options[:key] : get_private_key_path - @disableforce = options[:disableforce] - @lockforce = options[:lockforce] - - @last_response = "" - - @file_system_root = '/' # Not sure if this needs to be more portable - # This option is only intended for use by the test suite - if options[:file_system_root] - @file_system_root = options[:file_system_root] - @vardir = File.join(@file_system_root, @vardir) - @configdir = File.join(@file_system_root, @configdir) - end - - @configfile = File.join(@configdir, 'etch.conf') - @detailed_results = [] - - if File.exist?(@configfile) - IO.foreach(@configfile) do |line| - line.chomp! - next if (line =~ /^\s*$/); # Skip blank lines - next if (line =~ /^\s*#/); # Skip comments - line.strip! # Remove leading/trailing whitespace - key, value = line.split(/\s*=\s*/, 2) - if key == 'server' - # A setting for the server to use which comes from upstream - # (generally from a command line option) takes precedence - # over the config file - if !options[:server] - @server = value - # Warn the user, as this could potentially be confusing - # if they don't realize there's a config file lying - # around - warn "Using server #{@server} from #{@configfile}" if @debug - else - # "command line override" isn't necessarily accurate, we don't - # know why the caller passed us an option to override the config - # file, but most of the time it will be due to a command line - # option and I want the message to be easily understood by users. - # If someone can come up with some better wording without turning - # the message into something as long as this comment that would be - # welcome. - warn "Ignoring 'server' option in #{@configfile} due to command line override" if @debug - end - elsif key == 'local' - if !options[:local] && !options[:server] - @local = value - warn "Using local directory #{@local} from #{@configfile}" if @debug - else - warn "Ignoring 'local' option in #{@configfile} due to command line override" if @debug - end - elsif key == 'key' - if !options[:key] - @key = value - warn "Using key #{@key} from #{@configfile}" if @debug - else - warn "Ignoring 'key' option in #{@configfile} due to command line override" if @debug - end - elsif key == 'path' - ENV['PATH'] = value - elsif key == 'detailed_results' - warn "Adding detailed results destination '#{value}'" if @debug - @detailed_results << value - end - end - end - - if @key && !File.readable?(@key) - @key = nil - end - if !@key - warn "No readable private key found, messages to server will not be signed and may be rejected depending on server configuration" - end - - if @detailed_results.empty? - @detailed_results = DEFAULT_DETAILED_RESULTS - end - - @origbase = File.join(@vardir, 'orig') - @historybase = File.join(@vardir, 'history') - @lockbase = File.join(@vardir, 'locks') - @requestbase = File.join(@vardir, 'requests') - - @facts = Facter.to_hash - if @facts['operatingsystemrelease'] - # Some versions of Facter have a bug that leaves extraneous - # whitespace on this fact. Work around that with strip. I.e. on - # CentOS you'll get '5 ' or '5.2 '. - @facts['operatingsystemrelease'].strip! - end - - if @local - logger = Logger.new(STDOUT) - dlogger = Logger.new(STDOUT) - if @debug - dlogger.level = Logger::DEBUG - else - dlogger.level = Logger::INFO - end - blankrequest = {} - @facts.each_pair { |key, value| blankrequest[key] = value.to_s } - blankrequest['fqdn'] = @facts['fqdn'] - @facts = blankrequest - @etch = Etch.new(logger, dlogger) - else - # Make sure the server URL ends in a / so that we can append paths - # to it using URI.join - if @server !~ %r{/$} - @server << '/' - end - @filesuri = URI.join(@server, 'files') - @resultsuri = URI.join(@server, 'results') - - @blankrequest = {} - # If the user specified a non-standard key then override the - # sshrsakey fact so that authentication works - if @key - @facts['sshrsakey'] = IO.read(@key+'.pub').chomp.split[1] - end - @facts.each_pair { |key, value| @blankrequest["facts[#{key}]"] = value.to_s } - @blankrequest['fqdn'] = @facts['fqdn'] - if @debug - @blankrequest['debug'] = '1' - end - if @tag - @blankrequest['tag'] = @tag - end - end - - @locked_files = {} - @first_update = {} - @already_processed = {} - @exec_already_processed = {} - @exec_once_per_run = {} - @results = [] - # See start/stop_output_capture for these - @output_pipes = [] - - @lchown_supported = nil - @lchmod_supported = nil - end - - def process_until_done(files, commands) - # Our overall status. Will be reported to the server and used as the - # return value for this method. Command-line clients should use it as - # their exit value. Zero indicates no errors. - status = 0 - message = '' - - # A variable to collect filenames if operating in @listfiles mode - files_to_list = {} - - # Prep http instance - http = nil - if !@local - puts "Connecting to #{@filesuri}" if (@debug) - http = Net::HTTP.new(@filesuri.host, @filesuri.port) - if @filesuri.scheme == "https" - # Eliminate the OpenSSL "using default DH parameters" warning - if File.exist?(File.join(@configdir, 'etch', 'dhparams')) - dh = OpenSSL::PKey::DH.new(IO.read(File.join(@configdir, 'etch', 'dhparams'))) - Net::HTTP.ssl_context_accessor(:tmp_dh_callback) - http.tmp_dh_callback = proc { dh } - end - http.use_ssl = true - if File.exist?(File.join(@configdir, 'etch', 'ca.pem')) - http.ca_file = File.join(@configdir, 'etch', 'ca.pem') - http.verify_mode = OpenSSL::SSL::VERIFY_PEER - elsif File.directory?(File.join(@configdir, 'etch', 'ca')) - http.ca_path = File.join(@configdir, 'etch', 'ca') - http.verify_mode = OpenSSL::SSL::VERIFY_PEER - end - end - http.start - end - - # catch/throw for expected/non-error events that end processing - # begin/raise for error events that end processing - catch :stop_processing do - begin - enabled, message = check_for_disable_etch_file - if !enabled - # 200 is the arbitrarily picked exit value indicating - # that etch is disabled - status = 200 - throw :stop_processing - end - remove_stale_lock_files - - # Assemble the initial request - request = nil - if @local - request = {} - if files && !files.empty? - request[:files] = {} - files.each do |file| - request[:files][file] = {:orig => save_orig(file)} - local_requests = get_local_requests(file) - if local_requests - request[:files][file][:local_requests] = local_requests - end - end - end - if commands && !commands.empty? - request[:commands] = {} - commands.each do |command| - request[:commands][command] = {} - end - end - else - request = get_blank_request - if (files && !files.empty?) || (commands && !commands.empty?) - if files - files.each do |file| - request["files[#{CGI.escape(file)}][sha1sum]"] = - get_orig_sum(file) - local_requests = get_local_requests(file) - if local_requests - request["files[#{CGI.escape(file)}][local_requests]"] = - local_requests - end - end - end - if commands - commands.each do |command| - request["commands[#{CGI.escape(command)}]"] = '1' - end - end - else - request['files[GENERATEALL]'] = '1' - end - end - - # - # Loop back and forth with the server sending requests for files and - # responding to the server's requests for original contents or sums - # it needs - # - - Signal.trap('EXIT') do - STDOUT.reopen(ORIG_STDOUT) - STDERR.reopen(ORIG_STDERR) - unlock_all_files - end - - # It usually takes a few back and forth exchanges with the server to - # exchange all needed data and get a complete set of configuration. - # The number of iterations is capped at 10 to prevent any unplanned - # infinite loops. The limit of 10 was chosen somewhat arbitrarily but - # seems fine in practice. - 10.times do - # - # Send request to server - # - - responsedata = {} - if @local - results = @etch.generate(@local, @facts, request) - # FIXME: Etch#generate returns parsed XML using whatever XML - # library it happens to use. In order to avoid re-parsing - # the XML we'd have to use the XML abstraction code from Etch - # everwhere here. - # Until then re-parse the XML using REXML. - #responsedata[:configs] = results[:configs] - responsedata[:configs] = {} - results[:configs].each {|f,c| responsedata[:configs][f] = REXML::Document.new(c.to_s) } - responsedata[:need_sums] = {} - responsedata[:need_origs] = results[:need_orig] - #responsedata[:allcommands] = results[:allcommands] - responsedata[:allcommands] = {} - results[:allcommands].each {|cn,c| responsedata[:allcommands][cn] = REXML::Document.new(c.to_s) } - responsedata[:retrycommands] = results[:retrycommands] - else - puts "Sending request to server #{@filesuri}: #{request.inspect}" if (@debug) - post = Net::HTTP::Post.new(@filesuri.path) - post.set_form_data(request) - sign_post!(post, @key) - response = http.request(post) - if !response.kind_of?(Net::HTTPSuccess) - $stderr.puts response.body - # error! raises an exception - response.error! - end - puts "Response from server:\n'#{response.body}'" if (@debug) - if !response.body.nil? && !response.body.empty? - response_xml = REXML::Document.new(response.body) - responsedata[:configs] = {} - response_xml.elements.each('/files/configs/config') do |config| - file = config.attributes['filename'] - # We have to make a new document so that XPath paths are - # referenced relative to the configuration for this - # specific file. - #responsedata[:configs][file] = REXML::Document.new(response_xml.elements["/files/configs/config[@filename='#{file}']"].to_s) - responsedata[:configs][file] = REXML::Document.new(config.to_s) - end - responsedata[:need_sums] = {} - response_xml.elements.each('/files/need_sums/need_sum') do |ns| - responsedata[:need_sums][ns.text] = true - end - responsedata[:need_origs] = {} - response_xml.elements.each('/files/need_origs/need_orig') do |no| - responsedata[:need_origs][no.text] = true - end - responsedata[:allcommands] = {} - response_xml.elements.each('/files/allcommands/commands') do |command| - commandname = command.attributes['commandname'] - # We have to make a new document so that XPath paths are - # referenced relative to the configuration for this - # specific file. - #responsedata[:allcommands][commandname] = REXML::Document.new(response_xml.root.elements["/files/allcommands/commands[@commandname='#{commandname}']"].to_s) - responsedata[:allcommands][commandname] = REXML::Document.new(command.to_s) - end - responsedata[:retrycommands] = {} - response_xml.elements.each('/files/retrycommands/retrycommand') do |rc| - responsedata[:retrycommands][rc.text] = true - end - else - puts " Response is empty" if (@debug) - break - end - end - - # - # Process the response from the server - # - - # Prep a clean request hash - if @local - request = {} - if !responsedata[:need_origs].empty? - request[:files] = {} - end - if !responsedata[:retrycommands].empty? - request[:commands] = {} - end - else - request = get_blank_request - end - - # With generateall we expect to make at least two round trips - # to the server. - # 1) Send GENERATEALL request, get back a list of need_sums - # 2) Send sums, possibly get back some need_origs - # 3) Send origs, get back generated files - need_to_loop = false - reset_already_processed - # Process configs first, as they may contain setup entries that are - # needed to create the original files. - responsedata[:configs].each_key do |file| - puts "Processing config for #{file}" if (@debug) - if !@listfiles - continue_processing = process_file(file, responsedata) - if !continue_processing - throw :stop_processing - end - else - files_to_list[file] = true - end - end - responsedata[:need_sums].each_key do |need_sum| - puts "Processing request for sum of #{need_sum}" if (@debug) - if @local - # If this happens we screwed something up, the local mode - # code never requests sums. - raise "No support for sums in local mode" - else - request["files[#{CGI.escape(need_sum)}][sha1sum]"] = - get_orig_sum(need_sum) - end - local_requests = get_local_requests(need_sum) - if local_requests - if @local - request[:files][need_sum][:local_requests] = local_requests - else - request["files[#{CGI.escape(need_sum)}][local_requests]"] = - local_requests - end - end - need_to_loop = true - end - responsedata[:need_origs].each_key do |need_orig| - puts "Processing request for contents of #{need_orig}" if (@debug) - if @local - request[:files][need_orig] = {:orig => save_orig(need_orig)} - else - request["files[#{CGI.escape(need_orig)}][contents]"] = - Base64.encode64(get_orig_contents(need_orig)) - request["files[#{CGI.escape(need_orig)}][sha1sum]"] = - get_orig_sum(need_orig) - end - local_requests = get_local_requests(need_orig) - if local_requests - if @local - request[:files][need_orig][:local_requests] = local_requests - else - request["files[#{CGI.escape(need_orig)}][local_requests]"] = - local_requests - end - end - need_to_loop = true - end - responsedata[:allcommands].each_key do |commandname| - puts "Processing commands #{commandname}" if (@debug) - continue_processing = process_commands(commandname, responsedata) - if !continue_processing - throw :stop_processing - end - end - responsedata[:retrycommands].each_key do |commandname| - puts "Processing request to retry command #{commandname}" if (@debug) - if @local - request[:commands][commandname] = true - else - request["commands[#{CGI.escape(commandname)}]"] = '1' - end - need_to_loop = true - end - - if !need_to_loop - break - end - end - - puts "Processing 'exec once per run' commands" if (!exec_once_per_run.empty?) - exec_once_per_run.keys.each do |exec| - process_exec('post', exec) - end - rescue Exception => e - status = 1 - $stderr.puts e.message - message << e.message - $stderr.puts e.backtrace.join("\n") if @debug - message << e.backtrace.join("\n") if @debug - end # begin/rescue - end # catch - - if @listfiles - puts "Files under management:" - files_to_list.keys.sort.each {|file| puts file} - end - - # Send results to server - if !@dryrun && !@local - rails_results = [] - # A few of the fields here are numbers or booleans and need a - # to_s to make them compatible with CGI.escape, which expects a - # string. - rails_results << "fqdn=#{CGI.escape(@facts['fqdn'])}" - rails_results << "status=#{CGI.escape(status.to_s)}" - rails_results << "message=#{CGI.escape(message)}" - if @detailed_results.include?('SERVER') - @results.each do |result| - # Strangely enough this works. Even though the key is not unique to - # each result the Rails parameter parsing code keeps track of keys it - # has seen, and if it sees a duplicate it starts a new hash. - rails_results << "results[][file]=#{CGI.escape(result['file'])}" - rails_results << "results[][success]=#{CGI.escape(result['success'].to_s)}" - rails_results << "results[][message]=#{CGI.escape(result['message'])}" - end - end - puts "Sending results to server #{@resultsuri}" if (@debug) - resultspost = Net::HTTP::Post.new(@resultsuri.path) - # We have to bypass Net::HTTP's set_form_data method in this case - # because it expects a hash and we can't provide the results in the - # format we want in a hash because we'd have duplicate keys (see above). - results_as_string = rails_results.join('&') - resultspost.body = results_as_string - resultspost.content_type = 'application/x-www-form-urlencoded' - sign_post!(resultspost, @key) - response = http.request(resultspost) - case response - when Net::HTTPSuccess - puts "Response from server:\n'#{response.body}'" if (@debug) - else - $stderr.puts "Error submitting results:" - $stderr.puts response.body - end - end - - if !@dryrun - @detailed_results.each do |detail_dest| - # If any of the destinations look like a file (start with a /) then we - # log to that file - if detail_dest =~ %r{^/} - FileUtils.mkpath(File.dirname(detail_dest)) - File.open(detail_dest, 'a') do |file| - # Add a header for the overall status of the run - file.puts "Etch run at #{Time.now}" - file.puts "Status: #{status}" - if !message.empty? - file.puts "Message:\n#{message}\n" - end - # Then the detailed results - @results.each do |result| - file.puts "File #{result['file']}, result #{result['success']}:\n" - file.puts result['message'] - end - end - end - end - end - - status - end - - def check_for_disable_etch_file - disable_etch = File.join(@vardir, 'disable_etch') - message = '' - if File.exist?(disable_etch) - if !@disableforce - message = "Etch disabled:\n" - message << IO.read(disable_etch) - puts message - return false, message - else - puts "Ignoring disable_etch file" - end - end - return true, message - end - - def get_blank_request - @blankrequest.dup - end - - # Raises an exception if any fatal error is encountered - # Returns a boolean, true unless the user indicated in interactive mode - # that further processing should be halted - def process_file(file, responsedata) - continue_processing = true - save_results = true - exception = nil - - # We may not have configuration for this file, if it does not apply - # to this host. The server takes care of detecting any errors that - # might involve, so here we can just silently return. - config = responsedata[:configs][file] - if !config - puts "No configuration for #{file}, skipping" if (@debug) - return continue_processing - end - - # Skip files we've already processed in response to <depend> - # statements. - if @already_processed.has_key?(file) - puts "Skipping already processed #{file}" if (@debug) - return continue_processing - end - - # Prep the results capturing for this file - result = {} - result['file'] = file - result['success'] = true - result['message'] = '' - - # catch/throw for expected/non-error events that end processing - # begin/raise for error events that end processing - # Within this block you should throw :process_done if you've reached - # a natural stopping point and nothing further needs to be done. You - # should raise an exception if you encounter an error condition. - # Do not 'return' or 'abort'. - catch :process_done do - begin - start_output_capture - - puts "Processing #{file}" if (@debug) - - # The %locked_files hash provides a convenient way to - # detect circular dependancies. It doesn't give us an ordered - # list of dependencies, which might be handy to help the user - # debug the problem, but I don't think it's worth maintaining a - # seperate array just for that purpose. - if @locked_files.has_key?(file) - raise "Circular dependancy detected. " + - "Dependancy list (unsorted) contains:\n " + - @locked_files.keys.join(', ') - end - - # This needs to be after the circular dependency check - lock_file(file) - - # Process any other files that this file depends on - config.elements.each('/config/depend') do |depend| - puts "Processing dependency #{depend.text}" if (@debug) - process_file(depend.text, responsedata) - end - - # Process any commands that this file depends on - config.elements.each('/config/dependcommand') do |dependcommand| - puts "Processing command dependency #{dependcommand.text}" if (@debug) - process_commands(dependcommand.text, responsedata) - end - - # See what type of action the user has requested - - # Check to see if the user has requested that we revert back to the - # original file. - if config.elements['/config/revert'] - origpathbase = File.join(@origbase, file) - origpath = nil - - # Restore the original file if it is around - revert_occurred = false - if File.exist?("#{origpathbase}.ORIG") - origpath = "#{origpathbase}.ORIG" - origdir = File.dirname(origpath) - origbase = File.basename(origpath) - filedir = File.dirname(file) - - # Remove anything we might have written out for this file - remove_file(file) if (!@dryrun) - - puts "Restoring #{origpath} to #{file}" - recursive_copy_and_rename(origdir, origbase, file) if (!@dryrun) - revert_occurred = true - elsif File.exist?("#{origpathbase}.TAR") - origpath = "#{origpathbase}.TAR" - filedir = File.dirname(file) - - # Remove anything we might have written out for this file - remove_file(file) if (!@dryrun) - - puts "Restoring #{file} from #{origpath}" - system("cd #{filedir} && tar xf #{origpath}") if (!@dryrun) - revert_occurred = true - elsif File.exist?("#{origpathbase}.NOORIG") - origpath = "#{origpathbase}.NOORIG" - puts "Original #{file} didn't exist, restoring that state" - - # Remove anything we might have written out for this file - remove_file(file) if (!@dryrun) - revert_occurred = true - end - - # Update the history log - if revert_occurred - save_history(file) - end - - # Now remove the backed-up original so that future runs - # don't do anything - if origpath - remove_file(origpath) if (!@dryrun) - end - - throw :process_done - end - - # Perform any setup commands that the user has requested. - # These are occasionally needed to install software that is - # required to generate the file (think m4 for sendmail.cf) or to - # install a package containing a sample config file which we - # then edit with a script, and thus doing the install in <pre> - # is too late. - if config.elements['/config/setup'] - process_setup(file, config) - end - - if config.elements['/config/file'] # Regular file - newcontents = nil - if config.elements['/config/file/contents'] - newcontents = Base64.decode64(config.elements['/config/file/contents'].text) - end - - permstring = config.elements['/config/file/perms'].text - perms = permstring.oct - owner = config.elements['/config/file/owner'].text - group = config.elements['/config/file/group'].text - uid = lookup_uid(owner) - gid = lookup_gid(group) - - set_file_contents = false - if newcontents - set_file_contents = !compare_file_contents(file, newcontents) - end - set_permissions = nil - set_ownership = nil - # If the file is currently something other than a plain file then - # always set the flags to set the permissions and ownership. - # Checking the permissions/ownership of whatever is there currently - # is useless. - if set_file_contents && (!File.file?(file) || File.symlink?(file)) - set_permissions = true - set_ownership = true - else - set_permissions = !compare_permissions(file, perms) - set_ownership = !compare_ownership(file, uid, gid) - end - - # Proceed if: - # - The new contents are different from the current file - # - The permissions or ownership requested don't match the - # current permissions or ownership - if !set_file_contents && - !set_permissions && - !set_ownership - puts "No change to #{file} necessary" if (@debug) - throw :process_done - else - # Tell the user what we're going to do - if set_file_contents - # If the new contents are different from the current file - # show that to the user in the format they've requested. - # If the requested permissions are not world-readable then - # use the filenameonly format so that we don't disclose - # non-public data, unless we're in interactive mode - if @filenameonly || (permstring.to_i(8) & 0004 == 0 && !@interactive) - puts "Will write out new #{file}" - elsif @fullfile - # Grab the first 8k of the contents - first8k = newcontents.slice(0, 8192) - # Then check it for null characters. If it has any it's - # likely a binary file. - hasnulls = true if (first8k =~ /\0/) - - if !hasnulls - puts "Generated contents for #{file}:" - puts "=============================================" - puts newcontents - puts "=============================================" - else - puts "Will write out new #{file}, but " + - "generated contents are not plain text so " + - "they will not be displayed" - end - else - # Default is to show a diff of the current file and the - # newly generated file. - puts "Will make the following changes to #{file}, diff -c:" - tempfile = Tempfile.new(File.basename(file)) - tempfile.write(newcontents) - tempfile.close - puts "=============================================" - if File.file?(file) && !File.symlink?(file) - system("diff -c #{file} #{tempfile.path}") - else - # Either the file doesn't currently exist, - # or is something other than a normal file - # that we'll be replacing with a file. In - # either case diffing against /dev/null will - # produce the most logical output. - system("diff -c /dev/null #{tempfile.path}") - end - puts "=============================================" - tempfile.delete - end - end - if set_permissions - puts "Will set permissions on #{file} to #{permstring}" - end - if set_ownership - puts "Will set ownership of #{file} to #{uid}:#{gid}" - end - - # If the user requested interactive mode ask them for - # confirmation to proceed. - if @interactive - case get_user_confirmation() - when CONFIRM_PROCEED - # No need to do anything - when CONFIRM_SKIP - save_results = false - throw :process_done - when CONFIRM_QUIT - unlock_all_files - continue_processing = false - save_results = false - throw :process_done - else - raise "Unexpected result from get_user_confirmation()" - end - end - - # Perform any pre-action commands that the user has requested - if config.elements['/config/pre'] - process_pre(file, config) - end - - # If the original "file" is a directory and the user hasn't - # specifically told us we can overwrite it then raise an exception. - # - # The test is here, rather than a bit earlier where you might - # expect it, because the pre section may be used to address - # originals which are directories. So we don't check until - # after any pre commands are run. - if File.directory?(file) && !File.symlink?(file) && - !config.elements['/config/file/overwrite_directory'] - raise "Can't proceed, original of #{file} is a directory,\n" + - " consider the overwrite_directory flag if appropriate." - end - - # Give save_orig a definitive answer on whether or not to save the - # contents of an original directory. - origpath = save_orig(file, true) - # Update the history log - save_history(file) - - # Make sure the directory tree for this file exists - filedir = File.dirname(file) - if !File.directory?(filedir) - puts "Making directory tree #{filedir}" - FileUtils.mkpath(filedir) if (!@dryrun) - end - - # Make a backup in case we need to roll back. We have no use - # for a backup if there are no test commands defined (since we - # only use the backup to roll back if the test fails), so don't - # bother to create a backup unless there is a test command defined. - backup = nil - if config.elements['/config/test_before_post'] || - config.elements['/config/test'] - backup = make_backup(file) - puts "Created backup #{backup}" - end - - # If the new contents are different from the current file, - # replace the file. - if set_file_contents - if !@dryrun - # Write out the new contents into a temporary file - filebase = File.basename(file) - filedir = File.dirname(file) - newfile = Tempfile.new(filebase, filedir) - - # Set the proper permissions on the file before putting - # data into it. - newfile.chmod(perms) - begin - newfile.chown(uid, gid) - rescue Errno::EPERM - raise if Process.euid == 0 - end - - puts "Writing new contents of #{file} to #{newfile.path}" if (@debug) - newfile.write(newcontents) - newfile.close - - # If the current file is not a plain file, remove it. - # Plain files are left alone so that the replacement is - # atomic. - if File.symlink?(file) || (File.exist?(file) && ! File.file?(file)) - puts "Current #{file} is not a plain file, removing it" if (@debug) - remove_file(file) - end - - # Move the new file into place - File.rename(newfile.path, file) - - # Check the permissions and ownership now to ensure they - # end up set properly - set_permissions = !compare_permissions(file, perms) - set_ownership = !compare_ownership(file, uid, gid) - end - end - - # Ensure the permissions are set properly - if set_permissions - File.chmod(perms, file) if (!@dryrun) - end - - # Ensure the ownership is set properly - if set_ownership - begin - File.chown(uid, gid, file) if (!@dryrun) - rescue Errno::EPERM - raise if Process.euid == 0 - end - end - - # Perform any test_before_post commands that the user has requested - if config.elements['/config/test_before_post'] - if !process_test_before_post(file, config) - restore_backup(file, backup) - raise "test_before_post failed" - end - end - - # Perform any post-action commands that the user has requested - if config.elements['/config/post'] - process_post(file, config) - end - - # Perform any test commands that the user has requested - if config.elements['/config/test'] - if !process_test(file, config) - restore_backup(file, backup) - - # Re-run any post commands - if config.elements['/config/post'] - process_post(file, config) - end - end - end - - # Clean up the backup, we don't need it anymore - if config.elements['/config/test_before_post'] || - config.elements['/config/test'] - puts "Removing backup #{backup}" - remove_file(backup) if (!@dryrun) - end - - # Update the history log again - save_history(file) - - throw :process_done - end - end - - if config.elements['/config/link'] # Symbolic link - - dest = config.elements['/config/link/dest'].text - - set_link_destination = !compare_link_destination(file, dest) - absdest = File.expand_path(dest, File.dirname(file)) - - permstring = config.elements['/config/link/perms'].text - perms = permstring.oct - owner = config.elements['/config/link/owner'].text - group = config.elements['/config/link/group'].text - uid = lookup_uid(owner) - gid = lookup_gid(group) - - # lchown and lchmod are not supported on many platforms. The server - # always includes ownership and permissions settings with any link - # (pulling them from defaults.xml if the user didn't specify them in - # the config.xml file.) As such link management would always fail - # on systems which don't support lchown/lchmod, which seems like bad - # behavior. So instead we check to see if they are implemented, and - # if not just ignore ownership/permissions settings. I suppose the - # ideal would be for the server to tell the client whether the - # ownership/permissions were specifically requested (in config.xml) - # rather than just defaults, and then for the client to always try to - # manage ownership/permissions if the settings are not defaults (and - # fail in the event that they aren't implemented.) - if @lchown_supported.nil? - lchowntestlink = Tempfile.new('etchlchowntest').path - lchowntestfile = Tempfile.new('etchlchowntest').path - File.delete(lchowntestlink) - File.symlink(lchowntestfile, lchowntestlink) - begin - File.lchown(0, 0, lchowntestfile) - @lchown_supported = true - rescue NotImplementedError - @lchown_supported = false - rescue Errno::EPERM - raise if Process.euid == 0 - end - File.delete(lchowntestlink) - end - if @lchmod_supported.nil? - lchmodtestlink = Tempfile.new('etchlchmodtest').path - lchmodtestfile = Tempfile.new('etchlchmodtest').path - File.delete(lchmodtestlink) - File.symlink(lchmodtestfile, lchmodtestlink) - begin - File.lchmod(0644, lchmodtestfile) - @lchmod_supported = true - rescue NotImplementedError - @lchmod_supported = false - end - File.delete(lchmodtestlink) - end - - set_permissions = false - if @lchmod_supported - # If the file is currently something other than a link then - # always set the flags to set the permissions and ownership. - # Checking the permissions/ownership of whatever is there currently - # is useless. - if set_link_destination && !File.symlink?(file) - set_permissions = true - else - set_permissions = !compare_permissions(file, perms) - end - end - set_ownership = false - if @lchown_supported - if set_link_destination && !File.symlink?(file) - set_ownership = true - else - set_ownership = !compare_ownership(file, uid, gid) - end - end - - # Proceed if: - # - The new link destination differs from the current one - # - The permissions or ownership requested don't match the - # current permissions or ownership - if !set_link_destination && - !set_permissions && - !set_ownership - puts "No change to #{file} necessary" if (@debug) - throw :process_done - # Check that the link destination exists, and refuse to create - # the link unless it does exist or the user told us to go ahead - # anyway. - # - # Note that the destination may be a relative path, and the - # target directory may not exist yet, so we have to convert the - # destination to an absolute path and test that for existence. - # expand_path should handle paths that are already absolute - # properly. - elsif ! File.exist?(absdest) && ! File.symlink?(absdest) && - ! config.elements['/config/link/allow_nonexistent_dest'] - puts "Destination #{dest} for link #{file} does not exist," + - " consider the allow_nonexistent_dest flag if appropriate." - throw :process_done - else - # Tell the user what we're going to do - if set_link_destination - puts "Linking #{file} -> #{dest}" - end - if set_permissions - puts "Will set permissions on #{file} to #{permstring}" - end - if set_ownership - puts "Will set ownership of #{file} to #{uid}:#{gid}" - end - - # If the user requested interactive mode ask them for - # confirmation to proceed. - if @interactive - case get_user_confirmation() - when CONFIRM_PROCEED - # No need to do anything - when CONFIRM_SKIP - save_results = false - throw :process_done - when CONFIRM_QUIT - unlock_all_files - continue_processing = false - save_results = false - throw :process_done - else - raise "Unexpected result from get_user_confirmation()" - end - end - - # Perform any pre-action commands that the user has requested - if config.elements['/config/pre'] - process_pre(file, config) - end - - # If the original "file" is a directory and the user hasn't - # specifically told us we can overwrite it then raise an exception. - # - # The test is here, rather than a bit earlier where you might - # expect it, because the pre section may be used to address - # originals which are directories. So we don't check until - # after any pre commands are run. - if File.directory?(file) && !File.symlink?(file) && - !config.elements['/config/link/overwrite_directory'] - raise "Can't proceed, original of #{file} is a directory,\n" + - " consider the overwrite_directory flag if appropriate." - end - - # Give save_orig a definitive answer on whether or not to save the - # contents of an original directory. - origpath = save_orig(file, true) - # Update the history log - save_history(file) - - # Make sure the directory tree for this link exists - filedir = File.dirname(file) - if !File.directory?(filedir) - puts "Making directory tree #{filedir}" - FileUtils.mkpath(filedir) if (!@dryrun) - end - - # Make a backup in case we need to roll back. We have no use - # for a backup if there are no test commands defined (since we - # only use the backup to roll back if the test fails), so don't - # bother to create a backup unless there is a test command defined. - backup = nil - if config.elements['/config/test_before_post'] || - config.elements['/config/test'] - backup = make_backup(file) - puts "Created backup #{backup}" - end - - # Create the link - if set_link_destination - remove_file(file) if (!@dryrun) - File.symlink(dest, file) if (!@dryrun) - - # Check the permissions and ownership now to ensure they - # end up set properly - if @lchmod_supported - set_permissions = !compare_permissions(file, perms) - end - if @lchown_supported - set_ownership = !compare_ownership(file, uid, gid) - end - end - - # Ensure the permissions are set properly - if set_permissions - # Note: lchmod - File.lchmod(perms, file) if (!@dryrun) - end - - # Ensure the ownership is set properly - if set_ownership - begin - # Note: lchown - File.lchown(uid, gid, file) if (!@dryrun) - rescue Errno::EPERM - raise if Process.euid == 0 - end - end - - # Perform any test_before_post commands that the user has requested - if config.elements['/config/test_before_post'] - if !process_test_before_post(file, config) - restore_backup(file, backup) - raise "test_before_post failed" - end - end - - # Perform any post-action commands that the user has requested - if config.elements['/config/post'] - process_post(file, config) - end - - # Perform any test commands that the user has requested - if config.elements['/config/test'] - if !process_test(file, config) - restore_backup(file, backup) - - # Re-run any post commands - if config.elements['/config/post'] - process_post(file, config) - end - end - end - - # Clean up the backup, we don't need it anymore - if config.elements['/config/test_before_post'] || - config.elements['/config/test'] - puts "Removing backup #{backup}" - remove_file(backup) if (!@dryrun) - end - - # Update the history log again - save_history(file) - - throw :process_done - end - end - - if config.elements['/config/directory'] # Directory - - # A little safety check - create = config.elements['/config/directory/create'] - raise "No create element found in directory section" if !create - - permstring = config.elements['/config/directory/perms'].text - perms = permstring.oct - owner = config.elements['/config/directory/owner'].text - group = config.elements['/config/directory/group'].text - uid = lookup_uid(owner) - gid = lookup_gid(group) - - set_directory = !File.directory?(file) || File.symlink?(file) - set_permissions = nil - set_ownership = nil - # If the file is currently something other than a directory then - # always set the flags to set the permissions and ownership. - # Checking the permissions/ownership of whatever is there currently - # is useless. - if set_directory - set_permissions = true - set_ownership = true - else - set_permissions = !compare_permissions(file, perms) - set_ownership = !compare_ownership(file, uid, gid) - end - - # Proceed if: - # - The current file is not a directory - # - The permissions or ownership requested don't match the - # current permissions or ownership - if !set_directory && - !set_permissions && - !set_ownership - puts "No change to #{file} necessary" if (@debug) - throw :process_done - else - # Tell the user what we're going to do - if set_directory - puts "Making directory #{file}" - end - if set_permissions - puts "Will set permissions on #{file} to #{permstring}" - end - if set_ownership - puts "Will set ownership of #{file} to #{uid}:#{gid}" - end - - # If the user requested interactive mode ask them for - # confirmation to proceed. - if @interactive - case get_user_confirmation() - when CONFIRM_PROCEED - # No need to do anything - when CONFIRM_SKIP - save_results = false - throw :process_done - when CONFIRM_QUIT - unlock_all_files - continue_processing = false - save_results = false - throw :process_done - else - raise "Unexpected result from get_user_confirmation()" - end - end - - # Perform any pre-action commands that the user has requested - if config.elements['/config/pre'] - process_pre(file, config) - end - - # Give save_orig a definitive answer on whether or not to save the - # contents of an original directory. - origpath = save_orig(file, false) - # Update the history log - save_history(file) - - # Make sure the directory tree for this directory exists - filedir = File.dirname(file) - if !File.directory?(filedir) - puts "Making directory tree #{filedir}" - FileUtils.mkpath(filedir) if (!@dryrun) - end - - # Make a backup in case we need to roll back. We have no use - # for a backup if there are no test commands defined (since we - # only use the backup to roll back if the test fails), so don't - # bother to create a backup unless there is a test command defined. - backup = nil - if config.elements['/config/test_before_post'] || - config.elements['/config/test'] - backup = make_backup(file) - puts "Created backup #{backup}" - end - - # Create the directory - if set_directory - remove_file(file) if (!@dryrun) - Dir.mkdir(file) if (!@dryrun) - - # Check the permissions and ownership now to ensure they - # end up set properly - set_permissions = !compare_permissions(file, perms) - set_ownership = !compare_ownership(file, uid, gid) - end - - # Ensure the permissions are set properly - if set_permissions - File.chmod(perms, file) if (!@dryrun) - end - - # Ensure the ownership is set properly - if set_ownership - begin - File.chown(uid, gid, file) if (!@dryrun) - rescue Errno::EPERM - raise if Process.euid == 0 - end - end - - # Perform any test_before_post commands that the user has requested - if config.elements['/config/test_before_post'] - if !process_test_before_post(file, config) - restore_backup(file, backup) - raise "test_before_post failed" - end - end - - # Perform any post-action commands that the user has requested - if config.elements['/config/post'] - process_post(file, config) - end - - # Perform any test commands that the user has requested - if config.elements['/config/test'] - if !process_test(file, config) - restore_backup(file, backup) - - # Re-run any post commands - if config.elements['/config/post'] - process_post(file, config) - end - end - end - - # Clean up the backup, we don't need it anymore - if config.elements['/config/test_before_post'] || - config.elements['/config/test'] - puts "Removing backup #{backup}" - remove_file(backup) if (!@dryrun) - end - - # Update the history log again - save_history(file) - - throw :process_done - end - end - - if config.elements['/config/delete'] # Delete whatever is there - - # A little safety check - proceed = config.elements['/config/delete/proceed'] - raise "No proceed element found in delete section" if !proceed - - # Proceed only if the file currently exists - if !File.exist?(file) && !File.symlink?(file) - throw :process_done - else - # Tell the user what we're going to do - puts "Removing #{file}" - - # If the user requested interactive mode ask them for - # confirmation to proceed. - if @interactive - case get_user_confirmation() - when CONFIRM_PROCEED - # No need to do anything - when CONFIRM_SKIP - save_results = false - throw :process_done - when CONFIRM_QUIT - unlock_all_files - continue_processing = false - save_results = false - throw :process_done - else - raise "Unexpected result from get_user_confirmation()" - end - end - - # Perform any pre-action commands that the user has requested - if config.elements['/config/pre'] - process_pre(file, config) - end - - # If the original "file" is a directory and the user hasn't - # specifically told us we can overwrite it then raise an exception. - # - # The test is here, rather than a bit earlier where you might - # expect it, because the pre section may be used to address - # originals which are directories. So we don't check until - # after any pre commands are run. - if File.directory?(file) && !File.symlink?(file) && - !config.elements['/config/delete/overwrite_directory'] - raise "Can't proceed, original of #{file} is a directory,\n" + - " consider the overwrite_directory flag if appropriate." - end - - # Give save_orig a definitive answer on whether or not to save the - # contents of an original directory. - origpath = save_orig(file, true) - # Update the history log - save_history(file) - - # Make a backup in case we need to roll back. We have no use - # for a backup if there are no test commands defined (since we - # only use the backup to roll back if the test fails), so don't - # bother to create a backup unless there is a test command defined. - backup = nil - if config.elements['/config/test_before_post'] || - config.elements['/config/test'] - backup = make_backup(file) - puts "Created backup #{backup}" - end - - # Remove the file - remove_file(file) if (!@dryrun) - - # Perform any test_before_post commands that the user has requested - if config.elements['/config/test_before_post'] - if !process_test_before_post(file, config) - restore_backup(file, backup) - raise "test_before_post failed" - end - end - - # Perform any post-action commands that the user has requested - if config.elements['/config/post'] - process_post(file, config) - end - - # Perform any test commands that the user has requested - if config.elements['/config/test'] - if !process_test(file, config) - restore_backup(file, backup) - - # Re-run any post commands - ... [truncated message content] |
From: <jh...@us...> - 2012-03-18 15:28:50
|
Revision: 307 http://etch.svn.sourceforge.net/etch/?rev=307&view=rev Author: jheiss Date: 2012-03-18 15:28:44 +0000 (Sun, 18 Mar 2012) Log Message: ----------- ticket:14 Increase output capture timeout in interactive mode. >From the ticket: The output capture timeout causes the interactive mode prompt to timeout and fail after a few minutes. I often need to leave an interactive prompt for a few minutes while I research something. Modified Paths: -------------- trunk/client/lib/etch/client.rb Modified: trunk/client/lib/etch/client.rb =================================================================== --- trunk/client/lib/etch/client.rb 2012-03-03 16:21:43 UTC (rev 306) +++ trunk/client/lib/etch/client.rb 2012-03-18 15:28:44 UTC (rev 307) @@ -2452,6 +2452,8 @@ # for etch to handle any given file, including running any # setup/pre/post commands. OUTPUT_CAPTURE_TIMEOUT = 5 * 60 + # In interactive mode bump the timeout up to something absurdly large + OUTPUT_CAPTURE_INTERACTIVE_TIMEOUT = 14 * 24 * 60 * 60 def start_output_capture # Establish a pipe, spawn a child process, and redirect stdout/stderr # to the pipe. The child gathers up anything sent over the pipe and @@ -2503,7 +2505,13 @@ # capturing feature this results in etch hanging around forever # waiting for the pipes to close. We time out after a suitable # period of time so that etch processes don't hang around forever. - Timeout.timeout(OUTPUT_CAPTURE_TIMEOUT) do + timeout = nil + if @interactive + timeout = OUTPUT_CAPTURE_INTERACTIVE_TIMEOUT + else + timeout = OUTPUT_CAPTURE_TIMEOUT + end + Timeout.timeout(timeout) do while char = pread.getc putc(char) output << char.chr This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2012-03-03 16:21:50
|
Revision: 306 http://etch.svn.sourceforge.net/etch/?rev=306&view=rev Author: jheiss Date: 2012-03-03 16:21:43 +0000 (Sat, 03 Mar 2012) Log Message: ----------- Remove -w from ruby flags. It is too hard to eliminate warnings from libraries (mostly facter), which makes these programs noisy under ruby 1.9 Modified Paths: -------------- trunk/client/bin/etch trunk/client/bin/etch_cron_wrapper trunk/client/bin/etch_to_trunk Modified: trunk/client/bin/etch =================================================================== --- trunk/client/bin/etch 2012-03-02 16:13:50 UTC (rev 305) +++ trunk/client/bin/etch 2012-03-03 16:21:43 UTC (rev 306) @@ -1,4 +1,4 @@ -#!/usr/bin/ruby -w +#!/usr/bin/ruby ############################################################################## # Etch configuration file management tool ############################################################################## Modified: trunk/client/bin/etch_cron_wrapper =================================================================== --- trunk/client/bin/etch_cron_wrapper 2012-03-02 16:13:50 UTC (rev 305) +++ trunk/client/bin/etch_cron_wrapper 2012-03-03 16:21:43 UTC (rev 306) @@ -1,4 +1,4 @@ -#!/usr/bin/ruby -w +#!/usr/bin/ruby require 'socket' require 'digest/sha1' Modified: trunk/client/bin/etch_to_trunk =================================================================== --- trunk/client/bin/etch_to_trunk 2012-03-02 16:13:50 UTC (rev 305) +++ trunk/client/bin/etch_to_trunk 2012-03-03 16:21:43 UTC (rev 306) @@ -1,4 +1,4 @@ -#!/usr/bin/ruby -w +#!/usr/bin/ruby require 'nventory' require 'time' This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2012-03-02 16:13:57
|
Revision: 305 http://etch.svn.sourceforge.net/etch/?rev=305&view=rev Author: jheiss Date: 2012-03-02 16:13:50 +0000 (Fri, 02 Mar 2012) Log Message: ----------- Update comment about which xml library is used by default Modified Paths: -------------- trunk/server/lib/etch.rb Modified: trunk/server/lib/etch.rb =================================================================== --- trunk/server/lib/etch.rb 2012-03-02 16:13:17 UTC (rev 304) +++ trunk/server/lib/etch.rb 2012-03-02 16:13:50 UTC (rev 305) @@ -22,9 +22,9 @@ end end -# By default we try to use libxml, falling back to rexml if it is not -# available. The xmllib environment variable can be used to force one library -# or the other, mostly for testing purposes. +# By default we try to use nokogiri, falling back to rexml if it is not +# available. The xmllib environment variable can be used to force a specific +# library, mostly for testing purposes. Silently.silently do begin if !ENV['xmllib'] || ENV['xmllib'] == 'nokogiri' This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2012-03-02 16:13:23
|
Revision: 304 http://etch.svn.sourceforge.net/etch/?rev=304&view=rev Author: jheiss Date: 2012-03-02 16:13:17 +0000 (Fri, 02 Mar 2012) Log Message: ----------- Add a bundler Gemfile to make it easier for new users to get the necessary gems to run the test suite or otherwise experiment. Added Paths: ----------- trunk/Gemfile trunk/Gemfile.lock Added: trunk/Gemfile =================================================================== --- trunk/Gemfile (rev 0) +++ trunk/Gemfile 2012-03-02 16:13:17 UTC (rev 304) @@ -0,0 +1,14 @@ +source :rubygems +gem 'facter' +gem 'nokogiri' +# Tests will be run with nokogiri by default, but it might be nice to have +# libxml available too if you want to test with it as well. +gem 'libxml-ruby' + +group :server do + gem 'rails', '2.3.14' + gem 'sqlite3' + gem 'will_paginate', '~> 2.3.15' + gem 'searchlogic' +end + Added: trunk/Gemfile.lock =================================================================== --- trunk/Gemfile.lock (rev 0) +++ trunk/Gemfile.lock 2012-03-02 16:13:17 UTC (rev 304) @@ -0,0 +1,42 @@ +GEM + remote: http://rubygems.org/ + specs: + actionmailer (2.3.14) + actionpack (= 2.3.14) + actionpack (2.3.14) + activesupport (= 2.3.14) + rack (~> 1.1.0) + activerecord (2.3.14) + activesupport (= 2.3.14) + activeresource (2.3.14) + activesupport (= 2.3.14) + activesupport (2.3.14) + facter (1.6.5) + libxml-ruby (2.2.2) + nokogiri (1.5.0) + rack (1.1.3) + rails (2.3.14) + actionmailer (= 2.3.14) + actionpack (= 2.3.14) + activerecord (= 2.3.14) + activeresource (= 2.3.14) + activesupport (= 2.3.14) + rake (>= 0.8.3) + rake (0.9.2) + searchlogic (2.5.8) + activerecord (~> 2.3.12) + activerecord (~> 2.3.12) + sqlite3 (1.3.5) + will_paginate (2.3.16) + +PLATFORMS + ruby + +DEPENDENCIES + facter + libxml-ruby + nokogiri + rails (= 2.3.14) + searchlogic + sqlite3 + will_paginate (~> 2.3.15) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2011-10-13 20:21:30
|
Revision: 303 http://etch.svn.sourceforge.net/etch/?rev=303&view=rev Author: jheiss Date: 2011-10-13 20:21:24 +0000 (Thu, 13 Oct 2011) Log Message: ----------- In stop_server method send SIGKILL if SIGTERM doesn't do the trick. unicorn will exit with just TERM, but webrick needs a KILL. Modified Paths: -------------- trunk/test/etchtest.rb Modified: trunk/test/etchtest.rb =================================================================== --- trunk/test/etchtest.rb 2011-10-13 20:20:31 UTC (rev 302) +++ trunk/test/etchtest.rb 2011-10-13 20:21:24 UTC (rev 303) @@ -141,7 +141,13 @@ def stop_server(server) Process.kill('TERM', server[:pid]) - Process.waitpid(server[:pid]) + sleep 1 + r = Process.waitpid(server[:pid], Process::WNOHANG) + # SIGTERM is fine for unicorn but webrick doesn't die easily + if !r + Process.kill('KILL', server[:pid]) + Process.waitpid(server[:pid]) + end end def run_etch(server, testroot, options={}) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2011-10-13 20:20:37
|
Revision: 302 http://etch.svn.sourceforge.net/etch/?rev=302&view=rev Author: jheiss Date: 2011-10-13 20:20:31 +0000 (Thu, 13 Oct 2011) Log Message: ----------- Skip the RCS conversion tests if RCS is not installed. See code comment for more detail. Modified Paths: -------------- trunk/test/test_history.rb Modified: trunk/test/test_history.rb =================================================================== --- trunk/test/test_history.rb 2011-10-13 19:48:48 UTC (rev 301) +++ trunk/test/test_history.rb 2011-10-13 20:20:31 UTC (rev 302) @@ -380,6 +380,15 @@ # testname = 'history conversion' + # It is getting harder and harder to find a package of RCS for + # modern operating systems. And at this point the likelihood of + # anyone still having unconverted history logs is getting vanishingly + # small. So if we don't have the RCS executables available just skip + # these tests. + if `which ci` == '' || `which co` == '' + return + end + # Mock up an original file and RCS history log mockorigcontents = "This is the original text\n" FileUtils.mkdir_p(File.dirname(@origfile)) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2011-10-13 19:48:54
|
Revision: 301 http://etch.svn.sourceforge.net/etch/?rev=301&view=rev Author: jheiss Date: 2011-10-13 19:48:48 +0000 (Thu, 13 Oct 2011) Log Message: ----------- Update from rails 2.3.11 to latest in the 2.3 line: 2.3.14 Etch passes test suite with no changes needed Modified Paths: -------------- trunk/server/config/environment.rb Modified: trunk/server/config/environment.rb =================================================================== --- trunk/server/config/environment.rb 2011-10-13 19:28:26 UTC (rev 300) +++ trunk/server/config/environment.rb 2011-10-13 19:48:48 UTC (rev 301) @@ -5,7 +5,7 @@ # ENV['RAILS_ENV'] ||= 'production' # Specifies gem version of Rails to use when vendor/rails is not present -RAILS_GEM_VERSION = '2.3.11' unless defined? RAILS_GEM_VERSION +RAILS_GEM_VERSION = '2.3.14' unless defined? RAILS_GEM_VERSION # Bootstrap the Rails environment, frameworks, and default configuration require File.join(File.dirname(__FILE__), 'boot') This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2011-10-13 19:28:32
|
Revision: 300 http://etch.svn.sourceforge.net/etch/?rev=300&view=rev Author: jheiss Date: 2011-10-13 19:28:26 +0000 (Thu, 13 Oct 2011) Log Message: ----------- Something seems to have changed such that __FILE__ is now a fully qualified path. As such our mechanism for requiring etchtest.rb in all the test files has stopped working. Switch it around to a cleaner mechanism that uses File.expand_path so that it doesn't matter whether we get the old or new __FILE__ behavior. Modified Paths: -------------- trunk/test/test_actions.rb trunk/test/test_attributes.rb trunk/test/test_auth.rb trunk/test/test_commands.rb trunk/test/test_conf.rb trunk/test/test_delete.rb trunk/test/test_depend.rb trunk/test/test_file.rb trunk/test/test_history.rb trunk/test/test_link.rb trunk/test/test_local_requests.rb trunk/test/test_misc.rb trunk/test/test_nodegroups.rb trunk/test/test_options.rb trunk/test/test_outputcapture.rb trunk/test/test_scripts.rb trunk/test/test_transitions.rb Modified: trunk/test/test_actions.rb =================================================================== --- trunk/test/test_actions.rb 2011-08-15 21:49:55 UTC (rev 299) +++ trunk/test/test_actions.rb 2011-10-13 19:28:26 UTC (rev 300) @@ -4,7 +4,7 @@ # Test etch's handling of various actions: pre, post, setup, test, etc. # -require "./#{File.dirname(__FILE__)}/etchtest" +require File.expand_path('etchtest', File.dirname(__FILE__)) class EtchActionTests < Test::Unit::TestCase include EtchTests Modified: trunk/test/test_attributes.rb =================================================================== --- trunk/test/test_attributes.rb 2011-08-15 21:49:55 UTC (rev 299) +++ trunk/test/test_attributes.rb 2011-10-13 19:28:26 UTC (rev 300) @@ -4,7 +4,7 @@ # Test etch's handling of attribute filtering in config.xml files # -require "./#{File.dirname(__FILE__)}/etchtest" +require File.expand_path('etchtest', File.dirname(__FILE__)) require 'rubygems' # Might be needed to find facter require 'facter' Modified: trunk/test/test_auth.rb =================================================================== --- trunk/test/test_auth.rb 2011-08-15 21:49:55 UTC (rev 299) +++ trunk/test/test_auth.rb 2011-10-13 19:28:26 UTC (rev 300) @@ -4,7 +4,7 @@ # Test etch's handling of client authentication # -require "./#{File.dirname(__FILE__)}/etchtest" +require File.expand_path('etchtest', File.dirname(__FILE__)) require 'net/http' require 'rexml/document' begin Modified: trunk/test/test_commands.rb =================================================================== --- trunk/test/test_commands.rb 2011-08-15 21:49:55 UTC (rev 299) +++ trunk/test/test_commands.rb 2011-10-13 19:28:26 UTC (rev 300) @@ -4,7 +4,7 @@ # Test etch's handling of configuration commands # -require "./#{File.dirname(__FILE__)}/etchtest" +require File.expand_path('etchtest', File.dirname(__FILE__)) class EtchCommandTests < Test::Unit::TestCase include EtchTests Modified: trunk/test/test_conf.rb =================================================================== --- trunk/test/test_conf.rb 2011-08-15 21:49:55 UTC (rev 299) +++ trunk/test/test_conf.rb 2011-10-13 19:28:26 UTC (rev 300) @@ -4,7 +4,7 @@ # Test etch's handling of its configuration file, etch.conf # -require "./#{File.dirname(__FILE__)}/etchtest" +require File.expand_path('etchtest', File.dirname(__FILE__)) require 'net/http' require 'rexml/document' require 'cgi' Modified: trunk/test/test_delete.rb =================================================================== --- trunk/test/test_delete.rb 2011-08-15 21:49:55 UTC (rev 299) +++ trunk/test/test_delete.rb 2011-10-13 19:28:26 UTC (rev 300) @@ -4,7 +4,7 @@ # Test etch's handling of deleting files # -require "./#{File.dirname(__FILE__)}/etchtest" +require File.expand_path('etchtest', File.dirname(__FILE__)) class EtchDeleteTests < Test::Unit::TestCase include EtchTests Modified: trunk/test/test_depend.rb =================================================================== --- trunk/test/test_depend.rb 2011-08-15 21:49:55 UTC (rev 299) +++ trunk/test/test_depend.rb 2011-10-13 19:28:26 UTC (rev 300) @@ -4,7 +4,7 @@ # Test etch's handling of dependencies # -require "./#{File.dirname(__FILE__)}/etchtest" +require File.expand_path('etchtest', File.dirname(__FILE__)) class EtchDependTests < Test::Unit::TestCase include EtchTests Modified: trunk/test/test_file.rb =================================================================== --- trunk/test/test_file.rb 2011-08-15 21:49:55 UTC (rev 299) +++ trunk/test/test_file.rb 2011-10-13 19:28:26 UTC (rev 300) @@ -4,7 +4,7 @@ # Test etch's handling of creating and updating regular files # -require "./#{File.dirname(__FILE__)}/etchtest" +require File.expand_path('etchtest', File.dirname(__FILE__)) class EtchFileTests < Test::Unit::TestCase include EtchTests Modified: trunk/test/test_history.rb =================================================================== --- trunk/test/test_history.rb 2011-08-15 21:49:55 UTC (rev 299) +++ trunk/test/test_history.rb 2011-10-13 19:28:26 UTC (rev 300) @@ -5,7 +5,7 @@ # history files # -require "./#{File.dirname(__FILE__)}/etchtest" +require File.expand_path('etchtest', File.dirname(__FILE__)) class EtchHistoryTests < Test::Unit::TestCase include EtchTests Modified: trunk/test/test_link.rb =================================================================== --- trunk/test/test_link.rb 2011-08-15 21:49:55 UTC (rev 299) +++ trunk/test/test_link.rb 2011-10-13 19:28:26 UTC (rev 300) @@ -4,7 +4,7 @@ # Test etch's handling of creating and updating symbolic links # -require "./#{File.dirname(__FILE__)}/etchtest" +require File.expand_path('etchtest', File.dirname(__FILE__)) require 'pathname' class EtchLinkTests < Test::Unit::TestCase Modified: trunk/test/test_local_requests.rb =================================================================== --- trunk/test/test_local_requests.rb 2011-08-15 21:49:55 UTC (rev 299) +++ trunk/test/test_local_requests.rb 2011-10-13 19:28:26 UTC (rev 300) @@ -4,7 +4,7 @@ # Test etch's handling of local requests # -require "./#{File.dirname(__FILE__)}/etchtest" +require File.expand_path('etchtest', File.dirname(__FILE__)) class EtchLocalRequestsTests < Test::Unit::TestCase include EtchTests Modified: trunk/test/test_misc.rb =================================================================== --- trunk/test/test_misc.rb 2011-08-15 21:49:55 UTC (rev 299) +++ trunk/test/test_misc.rb 2011-10-13 19:28:26 UTC (rev 300) @@ -4,7 +4,7 @@ # Test miscellaneous items that don't fit elsewhere # -require "./#{File.dirname(__FILE__)}/etchtest" +require File.expand_path('etchtest', File.dirname(__FILE__)) require 'webrick' class EtchMiscTests < Test::Unit::TestCase Modified: trunk/test/test_nodegroups.rb =================================================================== --- trunk/test/test_nodegroups.rb 2011-08-15 21:49:55 UTC (rev 299) +++ trunk/test/test_nodegroups.rb 2011-10-13 19:28:26 UTC (rev 300) @@ -4,7 +4,7 @@ # Test etch's handling of node groups and the node group hierarchy # -require "./#{File.dirname(__FILE__)}/etchtest" +require File.expand_path('etchtest', File.dirname(__FILE__)) class EtchNodeGroupTests < Test::Unit::TestCase include EtchTests Modified: trunk/test/test_options.rb =================================================================== --- trunk/test/test_options.rb 2011-08-15 21:49:55 UTC (rev 299) +++ trunk/test/test_options.rb 2011-10-13 19:28:26 UTC (rev 300) @@ -4,7 +4,7 @@ # Test command line options to etch client # -require "./#{File.dirname(__FILE__)}/etchtest" +require File.expand_path('etchtest', File.dirname(__FILE__)) require 'webrick' class EtchOptionTests < Test::Unit::TestCase Modified: trunk/test/test_outputcapture.rb =================================================================== --- trunk/test/test_outputcapture.rb 2011-08-15 21:49:55 UTC (rev 299) +++ trunk/test/test_outputcapture.rb 2011-10-13 19:28:26 UTC (rev 300) @@ -4,7 +4,7 @@ # Test output capturing # -require "./#{File.dirname(__FILE__)}/etchtest" +require File.expand_path('etchtest', File.dirname(__FILE__)) require 'timeout' $:.unshift(File.join(EtchTests::CLIENTDIR, 'lib')) $:.unshift(File.join(EtchTests::SERVERDIR, 'lib')) Modified: trunk/test/test_scripts.rb =================================================================== --- trunk/test/test_scripts.rb 2011-08-15 21:49:55 UTC (rev 299) +++ trunk/test/test_scripts.rb 2011-10-13 19:28:26 UTC (rev 300) @@ -5,7 +5,7 @@ # creation of links and directories, and control the deletion of files # -require "./#{File.dirname(__FILE__)}/etchtest" +require File.expand_path('etchtest', File.dirname(__FILE__)) class EtchScriptTests < Test::Unit::TestCase include EtchTests Modified: trunk/test/test_transitions.rb =================================================================== --- trunk/test/test_transitions.rb 2011-08-15 21:49:55 UTC (rev 299) +++ trunk/test/test_transitions.rb 2011-10-13 19:28:26 UTC (rev 300) @@ -5,7 +5,7 @@ # file, etc.) # -require "./#{File.dirname(__FILE__)}/etchtest" +require File.expand_path('etchtest', File.dirname(__FILE__)) class EtchTransitionTests < Test::Unit::TestCase include EtchTests This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <th...@us...> - 2011-08-15 21:50:03
|
Revision: 299 http://etch.svn.sourceforge.net/etch/?rev=299&view=rev Author: thepob Date: 2011-08-15 21:49:55 +0000 (Mon, 15 Aug 2011) Log Message: ----------- adding etchdebuglog support per user request - there was an email thread about this one Modified Paths: -------------- trunk/server/lib/etch/server.rb Modified: trunk/server/lib/etch/server.rb =================================================================== --- trunk/server/lib/etch/server.rb 2011-07-09 00:36:49 UTC (rev 298) +++ trunk/server/lib/etch/server.rb 2011-08-15 21:49:55 UTC (rev 299) @@ -24,14 +24,16 @@ end @@configbase end - + @@auth_enabled = nil @@auth_deny_new_clients = nil + @@etchdebuglog = nil def self.read_config_file config_file = File.join(configbase, 'etchserver.conf') if File.exist?(config_file) auth_enabled = false auth_deny_new_clients = false + etchdebuglog = nil IO.foreach(config_file) do |line| # Skip blank lines and comments next if line =~ /^\s*$/ @@ -47,7 +49,11 @@ auth_deny_new_clients = true end end + if line =~ /^\s*etchdebuglog\s*=\s*(.*)/ + etchdebuglog = $1 + end end + @@etchdebuglog = etchdebuglog @@auth_enabled = auth_enabled @@auth_deny_new_clients = auth_deny_new_clients end @@ -203,12 +209,19 @@ @facts = facts @tag = tag @debug = debug - @dlogger = Logger.new(File.join(Rails.configuration.root_path, 'log', 'etchdebug.log')) + + if @@etchdebuglog + @dlogger = Logger.new(@@etchdebuglog) + else + @dlogger = Logger.new(File.join(Rails.configuration.root_path, 'log', 'etchdebug.log')) + end + if debug @dlogger.level = Logger::DEBUG else @dlogger.level = Logger::INFO end + @fqdn = @facts['fqdn'] if !@fqdn This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Pat O'B. <obr...@gm...> - 2011-08-10 05:05:21
|
ok, changes made and ready for review: Index: server.rb =================================================================== --- server.rb (revision 298) +++ server.rb (working copy) @@ -24,14 +24,16 @@ end @@configbase end - + @@auth_enabled = nil @@auth_deny_new_clients = nil + @@etchdebuglog = nil def self.read_config_file config_file = File.join(configbase, 'etchserver.conf') if File.exist?(config_file) auth_enabled = false auth_deny_new_clients = false + etchdebuglog = nil IO.foreach(config_file) do |line| # Skip blank lines and comments next if line =~ /^\s*$/ @@ -47,7 +49,11 @@ auth_deny_new_clients = true end end + if line =~ /^\s*etchdebuglog\s*=\s*(.*)/ + etchdebuglog = $1 + end end + @@etchdebuglog = etchdebuglog @@auth_enabled = auth_enabled @@auth_deny_new_clients = auth_deny_new_clients end @@ -203,12 +209,19 @@ @facts = facts @tag = tag @debug = debug - @dlogger = Logger.new(File.join(Rails.configuration.root_path, 'log', 'etchdebug.log')) + + if @@etchdebuglog + @dlogger = Logger.new(@@etchdebuglog) + else + @dlogger = Logger.new(File.join(Rails.configuration.root_path, 'log', 'etchdebug.log')) + end + if debug @dlogger.level = Logger::DEBUG else @dlogger.level = Logger::INFO end + @fqdn = @facts['fqdn'] if !@fqdn in regards to the ternary operators, I am pretty indifferent and more about keeping the coding style in tact within a project so that's all fine with me. -pat On Tue, Aug 9, 2011 at 5:01 PM, Jason Heiss <jh...@ap...> wrote: > (Moving this to etch-devel, bcc'ing out etch-users) > > It looks like you're adopting a different syntax for your "etchdebuglog" > from the accepted syntax for the existing config file entries. E.g. the > line for matching the "auth_enabled" option is: > > if line =~ /^\s*auth_enabled\s*=\s*(.*)/ > > Whereas you have: > > if line =~ /^etchdebuglog:/ > > I think we want to retain a common syntax. > > For the later half of your changes I personally find ternary operator > syntax hard to read at a glance. My wife tells me that's because I'm not a > real developer, so shrug, but I have to stare at this a while to figure out > what is going on: > > debug ? @dlogger.level = Logger::DEBUG : @dlogger.level = Logger::INFO > > Whereas this is obvious to me at a glance: > > if debug > @dlogger.level = Logger::DEBUG > else > @dlogger.level = Logger::INFO > end > > Maybe I'm special. > > Jason > > On Aug 8, 2011, at 11:40 PM, Pat O'Brien wrote: > > sounds good - how does this look: > > ---------------------------->%------------------------------ > wordup:etch pobrien$ svn diff > Index: server.rb > =================================================================== > --- server.rb (revision 298) > +++ server.rb (working copy) > @@ -24,14 +24,16 @@ > end > @@configbase > end > - > + > @@auth_enabled = nil > @@auth_deny_new_clients = nil > + @@etchdebuglog = nil > def self.read_config_file > config_file = File.join(configbase, 'etchserver.conf') > if File.exist?(config_file) > auth_enabled = false > auth_deny_new_clients = false > + etchdebuglog = nil > IO.foreach(config_file) do |line| > # Skip blank lines and comments > next if line =~ /^\s*$/ > @@ -47,7 +49,11 @@ > auth_deny_new_clients = true > end > end > + if line =~ /^etchdebuglog:/ > + etchdebuglog = line.split.pop > + end > end > + @@etchdebuglog = etchdebuglog > @@auth_enabled = auth_enabled > @@auth_deny_new_clients = auth_deny_new_clients > end > @@ -203,12 +209,11 @@ > @facts = facts > @tag = tag > @debug = debug > - @dlogger = Logger.new(File.join(Rails.configuration.root_path, 'log', > 'etchdebug.log')) > - if debug > - @dlogger.level = Logger::DEBUG > - else > - @dlogger.level = Logger::INFO > - end > + > + @@etchdebuglog ? @dlogger = Logger.new(@@etchdebuglog) : @dlogger = > Logger.new(File.join(Rails.configuration.root_path, 'log', 'etchdebug.log')) > + > + debug ? @dlogger.level = Logger::DEBUG : @dlogger.level = Logger::INFO > + > @fqdn = @facts['fqdn'] > > if !@fqdn > ---------------------------->%------------------------------ > > -pat > > On Mon, Aug 8, 2011 at 5:54 PM, Jason Heiss <jh...@ap...> wrote: > >> My thoughts: >> >> - Don't duplicate the logic of the self.read_config_file method, add your >> option into the existing config file parsing in that method. >> >> - Rather than an option for a log directory (your "log_dir"), I'd vote for >> an option that specifies the full path for this particular log file. I.e. >> "debuglog=/path/to/something" or similar. I think giving a log directory >> option is misleading, as most of the "etch server" logs are actually emitted >> by Rails and the Ruby app server (unicorn or the like) and as such would >> still end up in <rails root>/log even if the user specified a different log >> directory in etchserver.conf. The etch debug log is the only log file >> emitted by the etch server code itself. >> >> Jason >> >> On Aug 7, 2011, at 11:45 PM, Pat O'Brien wrote: >> >> Well, I worked out a fix for this, although I am unsure if it's a good fix >> or not. >> >> First, here is the diff: >> >> ------------------------------>%------------------------------ >> wordup:server pobrien$ svn diff >> Index: lib/etch/server.rb >> =================================================================== >> --- lib/etch/server.rb (revision 298) >> +++ lib/etch/server.rb (working copy) >> @@ -203,12 +203,24 @@ >> @facts = facts >> @tag = tag >> @debug = debug >> - @dlogger = Logger.new(File.join(Rails.configuration.root_path, 'log', >> 'etchdebug.log')) >> - if debug >> - @dlogger.level = Logger::DEBUG >> - else >> - @dlogger.level = Logger::INFO >> + @log_dir = nil >> + config_file = File.join(Etch::Server.configbase, 'etchserver.conf') >> + if File.exist?(config_file) >> + IO.foreach(config_file) do |line| >> + # Skip blank lines and comments >> + next if line =~ /^\s*$/ >> + next if line =~ /^\s*#/ >> + line.chomp >> + if line =~ /^log_dir:/ >> + @log_dir = line.split.pop >> + end >> + end >> end >> + >> + @log_dir ? @dlogger = Logger.new(File.join(@log_dir, >> 'etchdebug.log')) : @dlogger = >> Logger.new(File.join(Rails.configuration.root_path, 'log', 'etchdebug.log')) >> + >> + debug ? @dlogger.level = Logger::DEBUG : @dlogger.level = >> Logger::INFO >> + >> @fqdn = @facts['fqdn'] >> >> if !@fqdn >> ------------------------------>%------------------------------ >> >> Here are my problems with the change: the first is that I'm not sure if >> this config should go into <etchbase>/etchserver.conf or if it should be >> within the RAILS_ROOT/config/ directory. This feels like something that >> should be configured along with the rails app rather than in >> /etc/etchserver, but from what I understand (and I am in no way, shape or >> form versed in rails) in rails 2.x.x there is no generic config file to >> handle something like this. There is a railscast ( >> http://railscasts.com/episodes/85-yaml-configuration-file) that touches >> upon this, and they basically recommend RAILS_ROOT/config/config.yml along >> with some other necessary changes to actually have the config file loaded. >> >> Second, it looks like the <etchbase>/etchserver.conf file is currently >> only used to define two things: @@auth_enabled and @@auth_deny_new_clients >> = nil, and the way these are loaded is by parsing the config file the same >> way I parse it for the log_dir setting. I would prefer etchserver.conf file >> to be a YAML file and we could load it that way, but I haven't looked too >> deeply as to what else this file is used for so I don't really want to make >> any recommendations on how to change it. >> >> Third, I haven't looked hard enough to see whether or not anything else >> references a log directory of any kind and because of my two issues above I >> won't bother until there's a bit more discussion on it. >> >> Other than that the change works fine and behaves as you would expect it >> to, your etchserver.conf file would look like this: >> >> log_dir: /whatever/directory/your/heart/desires >> >> -pat >> >> >> >> >> On Sun, Aug 7, 2011 at 10:19 PM, Pat O'Brien <obr...@gm...>wrote: >> >>> I've never bothered to try this so I don't know if it's configurable or >>> not. If it's not open a bug ticket and I'll take a look at it when I get >>> some spare time this week. >>> >>> Just as a side note: my personal preference is to not have system logs >>> end up in /var/log, but to each their own :) >>> >>> -pat >>> >>> >>> >>> On Wed, Aug 3, 2011 at 3:27 PM, Johnston, Nathaniel < >>> Nat...@ca...> wrote: >>> >>>> Etch Mensches, >>>> >>>> I am not sure how best to do this, but I am trying to move my Etch logs >>>> over to /var along with the other logfiles I have. I noticed that on line >>>> 205 of lib/etchserver.rb the etchdebug.log file is specified as: >>>> >>>> @dlogger = Logger.new(File.join(Rails.configuration.root_path, 'log', >>>> 'etchdebug.log')) >>>> >>>> Is there a way that this could leverage the value of >>>> config.log_path/paths.log or another configurable parameter so that we could >>>> override the location of this file? >>>> >>>> --N. >>>> >>>> >>>> >>>> >>>> ------------------------------------------------------------------------------ >>>> BlackBerry® DevCon Americas, Oct. 18-20, San Francisco, CA >>>> The must-attend event for mobile developers. Connect with experts. >>>> Get tools for creating Super Apps. See the latest technologies. >>>> Sessions, hands-on labs, demos & much more. Register early & save! >>>> http://p.sf.net/sfu/rim-blackberry-1 >>>> _______________________________________________ >>>> etch-users mailing list >>>> etc...@li... >>>> https://lists.sourceforge.net/lists/listinfo/etch-users >>>> >>> >>> >> >> ------------------------------------------------------------------------------ >> BlackBerry® DevCon Americas, Oct. 18-20, San Francisco, CA >> The must-attend event for mobile developers. Connect with experts. >> Get tools for creating Super Apps. See the latest technologies. >> Sessions, hands-on labs, demos & much more. Register early & save! >> >> http://p.sf.net/sfu/rim-blackberry-1_______________________________________________ >> etch-users mailing list >> etc...@li... >> https://lists.sourceforge.net/lists/listinfo/etch-users >> >> >> > > |
From: Jason H. <jh...@ap...> - 2011-08-10 00:01:35
|
(Moving this to etch-devel, bcc'ing out etch-users) It looks like you're adopting a different syntax for your "etchdebuglog" from the accepted syntax for the existing config file entries. E.g. the line for matching the "auth_enabled" option is: if line =~ /^\s*auth_enabled\s*=\s*(.*)/ Whereas you have: if line =~ /^etchdebuglog:/ I think we want to retain a common syntax. For the later half of your changes I personally find ternary operator syntax hard to read at a glance. My wife tells me that's because I'm not a real developer, so shrug, but I have to stare at this a while to figure out what is going on: debug ? @dlogger.level = Logger::DEBUG : @dlogger.level = Logger::INFO Whereas this is obvious to me at a glance: if debug @dlogger.level = Logger::DEBUG else @dlogger.level = Logger::INFO end Maybe I'm special. Jason On Aug 8, 2011, at 11:40 PM, Pat O'Brien wrote: > sounds good - how does this look: > > ---------------------------->%------------------------------ > wordup:etch pobrien$ svn diff > Index: server.rb > =================================================================== > --- server.rb (revision 298) > +++ server.rb (working copy) > @@ -24,14 +24,16 @@ > end > @@configbase > end > - > + > @@auth_enabled = nil > @@auth_deny_new_clients = nil > + @@etchdebuglog = nil > def self.read_config_file > config_file = File.join(configbase, 'etchserver.conf') > if File.exist?(config_file) > auth_enabled = false > auth_deny_new_clients = false > + etchdebuglog = nil > IO.foreach(config_file) do |line| > # Skip blank lines and comments > next if line =~ /^\s*$/ > @@ -47,7 +49,11 @@ > auth_deny_new_clients = true > end > end > + if line =~ /^etchdebuglog:/ > + etchdebuglog = line.split.pop > + end > end > + @@etchdebuglog = etchdebuglog > @@auth_enabled = auth_enabled > @@auth_deny_new_clients = auth_deny_new_clients > end > @@ -203,12 +209,11 @@ > @facts = facts > @tag = tag > @debug = debug > - @dlogger = Logger.new(File.join(Rails.configuration.root_path, 'log', 'etchdebug.log')) > - if debug > - @dlogger.level = Logger::DEBUG > - else > - @dlogger.level = Logger::INFO > - end > + > + @@etchdebuglog ? @dlogger = Logger.new(@@etchdebuglog) : @dlogger = Logger.new(File.join(Rails.configuration.root_path, 'log', 'etchdebug.log')) > + > + debug ? @dlogger.level = Logger::DEBUG : @dlogger.level = Logger::INFO > + > @fqdn = @facts['fqdn'] > > if !@fqdn > ---------------------------->%------------------------------ > > -pat > > On Mon, Aug 8, 2011 at 5:54 PM, Jason Heiss <jh...@ap...> wrote: > My thoughts: > > - Don't duplicate the logic of the self.read_config_file method, add your option into the existing config file parsing in that method. > > - Rather than an option for a log directory (your "log_dir"), I'd vote for an option that specifies the full path for this particular log file. I.e. "debuglog=/path/to/something" or similar. I think giving a log directory option is misleading, as most of the "etch server" logs are actually emitted by Rails and the Ruby app server (unicorn or the like) and as such would still end up in <rails root>/log even if the user specified a different log directory in etchserver.conf. The etch debug log is the only log file emitted by the etch server code itself. > > Jason > > On Aug 7, 2011, at 11:45 PM, Pat O'Brien wrote: > >> Well, I worked out a fix for this, although I am unsure if it's a good fix or not. >> >> First, here is the diff: >> >> ------------------------------>%------------------------------ >> wordup:server pobrien$ svn diff >> Index: lib/etch/server.rb >> =================================================================== >> --- lib/etch/server.rb (revision 298) >> +++ lib/etch/server.rb (working copy) >> @@ -203,12 +203,24 @@ >> @facts = facts >> @tag = tag >> @debug = debug >> - @dlogger = Logger.new(File.join(Rails.configuration.root_path, 'log', 'etchdebug.log')) >> - if debug >> - @dlogger.level = Logger::DEBUG >> - else >> - @dlogger.level = Logger::INFO >> + @log_dir = nil >> + config_file = File.join(Etch::Server.configbase, 'etchserver.conf') >> + if File.exist?(config_file) >> + IO.foreach(config_file) do |line| >> + # Skip blank lines and comments >> + next if line =~ /^\s*$/ >> + next if line =~ /^\s*#/ >> + line.chomp >> + if line =~ /^log_dir:/ >> + @log_dir = line.split.pop >> + end >> + end >> end >> + >> + @log_dir ? @dlogger = Logger.new(File.join(@log_dir, 'etchdebug.log')) : @dlogger = Logger.new(File.join(Rails.configuration.root_path, 'log', 'etchdebug.log')) >> + >> + debug ? @dlogger.level = Logger::DEBUG : @dlogger.level = Logger::INFO >> + >> @fqdn = @facts['fqdn'] >> >> if !@fqdn >> ------------------------------>%------------------------------ >> >> Here are my problems with the change: the first is that I'm not sure if this config should go into <etchbase>/etchserver.conf or if it should be within the RAILS_ROOT/config/ directory. This feels like something that should be configured along with the rails app rather than in /etc/etchserver, but from what I understand (and I am in no way, shape or form versed in rails) in rails 2.x.x there is no generic config file to handle something like this. There is a railscast (http://railscasts.com/episodes/85-yaml-configuration-file) that touches upon this, and they basically recommend RAILS_ROOT/config/config.yml along with some other necessary changes to actually have the config file loaded. >> >> Second, it looks like the <etchbase>/etchserver.conf file is currently only used to define two things: @@auth_enabled and @@auth_deny_new_clients = nil, and the way these are loaded is by parsing the config file the same way I parse it for the log_dir setting. I would prefer etchserver.conf file to be a YAML file and we could load it that way, but I haven't looked too deeply as to what else this file is used for so I don't really want to make any recommendations on how to change it. >> >> Third, I haven't looked hard enough to see whether or not anything else references a log directory of any kind and because of my two issues above I won't bother until there's a bit more discussion on it. >> >> Other than that the change works fine and behaves as you would expect it to, your etchserver.conf file would look like this: >> >> log_dir: /whatever/directory/your/heart/desires >> >> -pat >> >> >> >> >> On Sun, Aug 7, 2011 at 10:19 PM, Pat O'Brien <obr...@gm...> wrote: >> I've never bothered to try this so I don't know if it's configurable or not. If it's not open a bug ticket and I'll take a look at it when I get some spare time this week. >> >> Just as a side note: my personal preference is to not have system logs end up in /var/log, but to each their own :) >> >> -pat >> >> >> >> On Wed, Aug 3, 2011 at 3:27 PM, Johnston, Nathaniel <Nat...@ca...> wrote: >> Etch Mensches, >> >> I am not sure how best to do this, but I am trying to move my Etch logs over to /var along with the other logfiles I have. I noticed that on line 205 of lib/etchserver.rb the etchdebug.log file is specified as: >> >> @dlogger = Logger.new(File.join(Rails.configuration.root_path, 'log', 'etchdebug.log')) >> >> Is there a way that this could leverage the value of config.log_path/paths.log or another configurable parameter so that we could override the location of this file? >> >> --N. >> >> >> >> ------------------------------------------------------------------------------ >> BlackBerry® DevCon Americas, Oct. 18-20, San Francisco, CA >> The must-attend event for mobile developers. Connect with experts. >> Get tools for creating Super Apps. See the latest technologies. >> Sessions, hands-on labs, demos & much more. Register early & save! >> http://p.sf.net/sfu/rim-blackberry-1 >> _______________________________________________ >> etch-users mailing list >> etc...@li... >> https://lists.sourceforge.net/lists/listinfo/etch-users >> >> >> ------------------------------------------------------------------------------ >> BlackBerry® DevCon Americas, Oct. 18-20, San Francisco, CA >> The must-attend event for mobile developers. Connect with experts. >> Get tools for creating Super Apps. See the latest technologies. >> Sessions, hands-on labs, demos & much more. Register early & save! >> http://p.sf.net/sfu/rim-blackberry-1_______________________________________________ >> etch-users mailing list >> etc...@li... >> https://lists.sourceforge.net/lists/listinfo/etch-users > > |
From: <jh...@us...> - 2011-07-09 00:36:55
|
Revision: 298 http://etch.svn.sourceforge.net/etch/?rev=298&view=rev Author: jheiss Date: 2011-07-09 00:36:49 +0000 (Sat, 09 Jul 2011) Log Message: ----------- Change a few instances of Dir::chdir to Dir.chdir and similar, both work but the later is more common. Modified Paths: -------------- trunk/server/lib/etch.rb Modified: trunk/server/lib/etch.rb =================================================================== --- trunk/server/lib/etch.rb 2011-07-09 00:26:29 UTC (rev 297) +++ trunk/server/lib/etch.rb 2011-07-09 00:36:49 UTC (rev 298) @@ -375,7 +375,7 @@ # Change into the corresponding directory so that the user can # refer to source files and scripts by their relative pathnames. - Dir::chdir "#{@sourcebase}/#{file}" + Dir.chdir "#{@sourcebase}/#{file}" # See what type of action the user has requested @@ -426,7 +426,7 @@ # Just slurp the file in plain_file = Etch.xmltext(plain_elements.first) - newcontents = IO::read(plain_file) + newcontents = IO.read(plain_file) elsif Etch.xmlfindfirst(config_xml, '/config/file/source/template') template_elements = Etch.xmlarray(config_xml, '/config/file/source/template') if check_for_inconsistency(template_elements) @@ -925,7 +925,7 @@ # Change into the corresponding directory so that the user can # refer to source files and scripts by their relative pathnames. - Dir::chdir "#{@commandsbase}/#{command}" + Dir.chdir "#{@commandsbase}/#{command}" # Check that the resulting document is consistent after filtering remove = [] This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2011-07-09 00:26:35
|
Revision: 297 http://etch.svn.sourceforge.net/etch/?rev=297&view=rev Author: jheiss Date: 2011-07-09 00:26:29 +0000 (Sat, 09 Jul 2011) Log Message: ----------- Use REXML's deep_clone rather than dup or clone in xmlcopyelem. I originaly used dup, but switched to clone in commit 267. dup made a copy that wasn't really a copy, xmlsettext would change the original as well. clone fixed that problem, but it turns out it didn't copy the contents of the element. So <foo>text</foo> became <foo/>. deep_clone fixes those issues. (And the unit tests now test for both of those issues.) Modified Paths: -------------- trunk/server/lib/etch.rb Modified: trunk/server/lib/etch.rb =================================================================== --- trunk/server/lib/etch.rb 2011-07-09 00:19:36 UTC (rev 296) +++ trunk/server/lib/etch.rb 2011-07-09 00:26:29 UTC (rev 297) @@ -1372,7 +1372,7 @@ when :nokogiri destelem << elem.dup when :rexml - destelem.add_element(elem.clone) + destelem.add_element(elem.deep_clone) else raise "Unknown XML library #{Etch.xmllib}" end This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2011-07-09 00:19:42
|
Revision: 296 http://etch.svn.sourceforge.net/etch/?rev=296&view=rev Author: jheiss Date: 2011-07-09 00:19:36 +0000 (Sat, 09 Jul 2011) Log Message: ----------- Modify test_xmlcopyelem to test that the contents of the element are copied. Modified Paths: -------------- trunk/test/unit/test_xml_abstraction.rb Modified: trunk/test/unit/test_xml_abstraction.rb =================================================================== --- trunk/test/unit/test_xml_abstraction.rb 2011-07-08 23:30:43 UTC (rev 295) +++ trunk/test/unit/test_xml_abstraction.rb 2011-07-09 00:19:36 UTC (rev 296) @@ -341,37 +341,53 @@ end def test_xmlcopyelem file = Tempfile.new('etch_xml_abstraction') - file.puts '<root><element><child/></element><other/></root>' + file.puts '<root><element><child>child text</child></element><other/></root>' file.close doc = Etch.xmlload(file.path) original = Etch.xmlfindfirst(doc, '/root/element/child') Etch.xmlcopyelem(original, Etch.xmlfindfirst(doc, '/root/other')) copy = Etch.xmlfindfirst(doc, '/root/other/child') - # Change the child so that we can test that it is separate from the orignal - Etch.xmlsettext(copy, 'some text') + case Etch.xmllib when :libxml assert_kind_of(LibXML::XML::Node, original) assert_kind_of(LibXML::XML::Node, copy) assert_equal('child', original.name) - assert_equal('', Etch.xmltext(original)) + assert_equal('child text', Etch.xmltext(original)) assert_equal('child', copy.name) - assert_equal('some text', Etch.xmltext(copy)) + assert_equal('child text', Etch.xmltext(copy)) when :nokogiri assert_kind_of(Nokogiri::XML::Element, original) assert_kind_of(Nokogiri::XML::Element, copy) assert_equal('child', original.name) - assert_equal('', Etch.xmltext(original)) + assert_equal('child text', Etch.xmltext(original)) assert_equal('child', copy.name) - assert_equal('some text', Etch.xmltext(copy)) + assert_equal('child text', Etch.xmltext(copy)) when :rexml assert_kind_of(REXML::Element, original) assert_kind_of(REXML::Element, copy) assert_equal('child', original.name) - assert_equal('', Etch.xmltext(original)) + assert_equal('child text', Etch.xmltext(original)) assert_equal('child', copy.name) + assert_equal('child text', Etch.xmltext(copy)) + else + raise "Unknown XML library #{Etch.xmllib}" + end + + # Change the child so that we can test that it is separate from the orignal + Etch.xmlsettext(copy, 'some text') + + case Etch.xmllib + when :libxml + assert_equal('child text', Etch.xmltext(original)) assert_equal('some text', Etch.xmltext(copy)) + when :nokogiri + assert_equal('child text', Etch.xmltext(original)) + assert_equal('some text', Etch.xmltext(copy)) + when :rexml + assert_equal('child text', Etch.xmltext(original)) + assert_equal('some text', Etch.xmltext(copy)) else raise "Unknown XML library #{Etch.xmllib}" end This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2011-07-08 23:30:49
|
Revision: 295 http://etch.svn.sourceforge.net/etch/?rev=295&view=rev Author: jheiss Date: 2011-07-08 23:30:43 +0000 (Fri, 08 Jul 2011) Log Message: ----------- Use "$:.unshift" rather than "$: <<" when manipulating the library search path. Otherwise the system paths are searched first. Modified Paths: -------------- trunk/test/test_outputcapture.rb trunk/test/unit/test_xml_abstraction.rb Modified: trunk/test/test_outputcapture.rb =================================================================== --- trunk/test/test_outputcapture.rb 2011-07-08 23:18:47 UTC (rev 294) +++ trunk/test/test_outputcapture.rb 2011-07-08 23:30:43 UTC (rev 295) @@ -6,8 +6,8 @@ require "./#{File.dirname(__FILE__)}/etchtest" require 'timeout' -$: << File.join(EtchTests::CLIENTDIR, 'lib') -$: << File.join(EtchTests::SERVERDIR, 'lib') +$:.unshift(File.join(EtchTests::CLIENTDIR, 'lib')) +$:.unshift(File.join(EtchTests::SERVERDIR, 'lib')) require 'etch/client' class EtchOutputCaptureTests < Test::Unit::TestCase Modified: trunk/test/unit/test_xml_abstraction.rb =================================================================== --- trunk/test/unit/test_xml_abstraction.rb 2011-07-08 23:18:47 UTC (rev 294) +++ trunk/test/unit/test_xml_abstraction.rb 2011-07-08 23:30:43 UTC (rev 295) @@ -1,6 +1,6 @@ require 'test/unit' require 'tempfile' -$: << "#{File.dirname(File.expand_path(__FILE__))}/../../server/lib" +$:.unshift("#{File.dirname(File.expand_path(__FILE__))}/../../server/lib") require 'etch' # Test the XML abstraction methods in etch.rb This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2011-07-08 23:18:53
|
Revision: 294 http://etch.svn.sourceforge.net/etch/?rev=294&view=rev Author: jheiss Date: 2011-07-08 23:18:47 +0000 (Fri, 08 Jul 2011) Log Message: ----------- Add a test that xmlfindfirst returns a false value when used to query for a non-existent element. Modified Paths: -------------- trunk/test/unit/test_xml_abstraction.rb Modified: trunk/test/unit/test_xml_abstraction.rb =================================================================== --- trunk/test/unit/test_xml_abstraction.rb 2011-07-07 22:52:42 UTC (rev 293) +++ trunk/test/unit/test_xml_abstraction.rb 2011-07-08 23:18:47 UTC (rev 294) @@ -279,6 +279,9 @@ else raise "Unknown XML library #{Etch.xmllib}" end + # We have code that assumes xmlfindfirst returns a false value when + # queried for non-existent elements + assert(!Etch.xmlfindfirst(doc, '/not_an_element')) end def test_xmltext file = Tempfile.new('etch_xml_abstraction') This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |