Sucuri Security – Auditing, Malware Scanner and Security Hardening - Version 1.8.8

Version Description

This version adds support for the latest version of WordPress. Introduces new features and fixes some bugs reported by the WordPress community as well as bugs found by our automated testing system.

=

Download this release

Release Info

Developer yorman
Plugin Icon 128x128 Sucuri Security – Auditing, Malware Scanner and Security Hardening
Version 1.8.8
Comparing to
See all releases

Code changes from version 1.8.7 to 1.8.8

Files changed (59) hide show
  1. inc/css/c3.min.css +0 -1
  2. inc/css/styles.css +22 -4
  3. inc/js/c3.min.js +0 -6
  4. inc/js/d3.min.js +0 -5
  5. inc/js/scripts.js +18 -1
  6. inc/tpl/auditlogs-report.html.tpl +0 -103
  7. inc/tpl/auditlogs.html.tpl +31 -13
  8. inc/tpl/dashboard.html.tpl +23 -8
  9. inc/tpl/firewall-auditlogs.snippet.tpl +42 -38
  10. inc/tpl/firewall-clearcache.html.tpl +50 -5
  11. inc/tpl/firewall-ipaccess.html.tpl +118 -0
  12. inc/tpl/firewall-settings.html.tpl +34 -2
  13. inc/tpl/firewall-settings.snippet.tpl +0 -5
  14. inc/tpl/firewall.html.tpl +5 -0
  15. inc/tpl/integrity-diff-utility.html.tpl +3 -10
  16. inc/tpl/integrity-incorrect.html.tpl +73 -5
  17. inc/tpl/settings-alerts-events.html.tpl +4 -0
  18. inc/tpl/settings-alerts-ignore-posts.html.tpl +3 -3
  19. inc/tpl/settings-apiservice-checksums.html.tpl +23 -0
  20. inc/tpl/{settings-general-auditlogstats.html.tpl → settings-general-timezone.html.tpl} +7 -4
  21. inc/tpl/settings-webinfo-wpconfig.html.tpl +0 -19
  22. inc/tpl/settings-webinfo-wpconfig.snippet.tpl +0 -6
  23. inc/tpl/settings.html.tpl +5 -3
  24. inc/tpl/sitecheck-links.html.tpl +0 -6
  25. inc/tpl/sitecheck-links.snippet.tpl +0 -7
  26. inc/tpl/sitecheck-target.html.tpl +24 -0
  27. languages/sucuri-scanner-en_US.mo +0 -0
  28. languages/sucuri-scanner-en_US.po +55 -16
  29. languages/sucuri-scanner-es_ES.mo +0 -0
  30. languages/sucuri-scanner-es_ES.po +162 -122
  31. readme.txt +100 -113
  32. src/api.lib.php +206 -85
  33. src/auditlogs.lib.php +43 -103
  34. src/cache.lib.php +4 -2
  35. src/command.lib.php +14 -20
  36. src/event.lib.php +77 -65
  37. src/fileinfo.lib.php +32 -17
  38. src/firewall.lib.php +282 -110
  39. src/fsscanner.lib.php +1 -1
  40. src/globals.php +29 -32
  41. src/hook.lib.php +40 -9
  42. src/integrity.lib.php +205 -217
  43. src/interface.lib.php +30 -40
  44. src/lastlogins-failed.php +2 -1
  45. src/lastlogins.php +2 -2
  46. src/mail.lib.php +1 -1
  47. src/option.lib.php +61 -6
  48. src/pagehandler.php +16 -15
  49. src/settings-alerts.php +119 -89
  50. src/settings-apiservice.php +37 -0
  51. src/settings-general.php +58 -45
  52. src/settings-hardening.php +15 -3
  53. src/settings-integrity.php +1 -1
  54. src/settings-scanner.php +4 -11
  55. src/settings-webinfo.php +22 -105
  56. src/sitecheck.lib.php +58 -88
  57. src/sucuriscan.lib.php +48 -81
  58. src/template.lib.php +9 -8
  59. sucuri.php +3 -13
inc/css/c3.min.css DELETED
@@ -1 +0,0 @@
1
- .c3 svg{font:10px sans-serif;-webkit-tap-highlight-color:transparent}.c3 line,.c3 path{fill:none;stroke:#000}.c3 text{-webkit-user-select:none;-moz-user-select:none;user-select:none}.c3-bars path,.c3-event-rect,.c3-legend-item-tile,.c3-xgrid-focus,.c3-ygrid{shape-rendering:crispEdges}.c3-chart-arc path{stroke:#fff}.c3-chart-arc text{fill:#fff;font-size:13px}.c3-grid line{stroke:#aaa}.c3-grid text{fill:#aaa}.c3-xgrid,.c3-ygrid{stroke-dasharray:3 3}.c3-text.c3-empty{fill:gray;font-size:2em}.c3-line{stroke-width:1px}.c3-circle._expanded_{stroke-width:1px;stroke:#fff}.c3-selected-circle{fill:#fff;stroke-width:2px}.c3-bar{stroke-width:0}.c3-bar._expanded_{fill-opacity:.75}.c3-target.c3-focused{opacity:1}.c3-target.c3-focused path.c3-line,.c3-target.c3-focused path.c3-step{stroke-width:2px}.c3-target.c3-defocused{opacity:.3!important}.c3-region{fill:#4682b4;fill-opacity:.1}.c3-brush .extent{fill-opacity:.1}.c3-legend-item{font-size:12px}.c3-legend-item-hidden{opacity:.15}.c3-legend-background{opacity:.75;fill:#fff;stroke:#d3d3d3;stroke-width:1}.c3-title{font:14px sans-serif}.c3-tooltip-container{z-index:10}.c3-tooltip{border-collapse:collapse;border-spacing:0;background-color:#fff;empty-cells:show;-webkit-box-shadow:7px 7px 12px -9px #777;-moz-box-shadow:7px 7px 12px -9px #777;box-shadow:7px 7px 12px -9px #777;opacity:.9}.c3-tooltip tr{border:1px solid #CCC}.c3-tooltip th{background-color:#aaa;font-size:14px;padding:2px 5px;text-align:left;color:#FFF}.c3-tooltip td{font-size:13px;padding:3px 6px;background-color:#fff;border-left:1px dotted #999}.c3-tooltip td>span{display:inline-block;width:10px;height:10px;margin-right:6px}.c3-tooltip td.value{text-align:right}.c3-area{stroke-width:0;opacity:.2}.c3-chart-arcs-title{dominant-baseline:middle;font-size:1.3em}.c3-chart-arcs .c3-chart-arcs-background{fill:#e0e0e0;stroke:none}.c3-chart-arcs .c3-chart-arcs-gauge-unit{fill:#000;font-size:16px}.c3-chart-arcs .c3-chart-arcs-gauge-max,.c3-chart-arcs .c3-chart-arcs-gauge-min{fill:#777}.c3-chart-arc .c3-gauge-value{fill:#000}
 
inc/css/styles.css CHANGED
@@ -224,6 +224,7 @@ body.sucuri-security_page_sucuriscan_hardening {
224
  padding: 20px;
225
  font-size: 12px;
226
  color: #fff;
 
227
  }
228
  .sucuriscan-tooltip-object::before {
229
  left: 50%;
@@ -775,13 +776,11 @@ body.sucuri-security_page_sucuriscan_hardening {
775
  text-overflow: ellipsis;
776
  }
777
  .sucuriscan-auditlog-entry-time {
778
- width: 6.5111%;
779
  color: #808080;
780
- margin-right: 20px;
781
  }
782
  .sucuriscan-auditlog-entry-event {
783
- width: 3.2811%;
784
- margin-right: 20px;
785
  }
786
  .sucuriscan-auditlog-entry-message {
787
  width: 64.3111%;
@@ -845,3 +844,22 @@ body.sucuri-security_page_sucuriscan_hardening {
845
  .sucuriscan-accesslog-label {
846
  font-weight: 700;
847
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  padding: 20px;
225
  font-size: 12px;
226
  color: #fff;
227
+ z-index: 10;
228
  }
229
  .sucuriscan-tooltip-object::before {
230
  left: 50%;
776
  text-overflow: ellipsis;
777
  }
778
  .sucuriscan-auditlog-entry-time {
779
+ width: 45px;
780
  color: #808080;
 
781
  }
782
  .sucuriscan-auditlog-entry-event {
783
+ width: 28px;
 
784
  }
785
  .sucuriscan-auditlog-entry-message {
786
  width: 64.3111%;
844
  .sucuriscan-accesslog-label {
845
  font-weight: 700;
846
  }
847
+ .sucuriscan-ipaccess-form,
848
+ .sucuriscan-ipaccess-table {
849
+ margin-top: 20px;
850
+ }
851
+ .sucuriscan-ipaccess-table tbody td + td {
852
+ text-align: right;
853
+ }
854
+ .sucuriscan-ipaccess-table .sucuriscan-monospace {
855
+ line-height: 30px;
856
+ }
857
+ .sucuriscan-settings-alerts .dashicons-before::before {
858
+ padding-right: 10px;
859
+ }
860
+ #firewall-clear-cache-auto {
861
+ margin-bottom: 15px;
862
+ }
863
+ .sucuriscan-firewall-accesslog {
864
+ word-break: break-all;
865
+ }
inc/js/c3.min.js DELETED
@@ -1,6 +0,0 @@
1
- !function(a){"use strict";function b(a){this.owner=a}function c(a,b){if(Object.create)b.prototype=Object.create(a.prototype);else{var c=function(){};c.prototype=a.prototype,b.prototype=new c}return b.prototype.constructor=b,b}function d(a){var b=this.internal=new e(this);b.loadConfig(a),b.beforeInit(a),b.init(),b.afterInit(a),function c(a,b,d){Object.keys(a).forEach(function(e){b[e]=a[e].bind(d),Object.keys(a[e]).length>0&&c(a[e],b[e],d)})}(h,this,this)}function e(b){var c=this;c.d3=a.d3?a.d3:"undefined"!=typeof require?require("d3"):void 0,c.api=b,c.config=c.getDefaultConfig(),c.data={},c.cache={},c.axes={}}function f(a){b.call(this,a)}function g(a,b){function c(a,b){a.attr("transform",function(a){return"translate("+Math.ceil(b(a)+u)+", 0)"})}function d(a,b){a.attr("transform",function(a){return"translate(0,"+Math.ceil(b(a))+")"})}function e(a){var b=a[0],c=a[a.length-1];return c>b?[b,c]:[c,b]}function f(a){var b,c,d=[];if(a.ticks)return a.ticks.apply(a,n);for(c=a.domain(),b=Math.ceil(c[0]);b<c[1];b++)d.push(b);return d.length>0&&d[0]>0&&d.unshift(d[0]-(d[1]-d[0])),d}function g(){var a,c=p.copy();return b.isCategory&&(a=p.domain(),c.domain([a[0],a[1]-1])),c}function h(a){var b=m?m(a):a;return"undefined"!=typeof b?b:""}function i(a){if(A)return A;var b={h:11.5,w:5.5};return a.select("text").text(h).each(function(a){var c=this.getBoundingClientRect(),d=h(a),e=c.height,f=d?c.width/d.length:void 0;e&&f&&(b.h=e,b.w=f)}).text(""),A=b,b}function j(c){return b.withoutTransition?c:a.transition(c)}function k(m){m.each(function(){function m(a,c){function d(a,b){f=void 0;for(var h=1;h<b.length;h++)if(" "===b.charAt(h)&&(f=h),e=b.substr(0,h+1),g=U.w*e.length,g>c)return d(a.concat(b.substr(0,f?f:h)),b.slice(f?f+1:h));return a.concat(b)}var e,f,g,i=h(a),j=[];return"[object Array]"===Object.prototype.toString.call(i)?i:((!c||0>=c)&&(c=X?95:b.isCategory?Math.ceil(F(G[1])-F(G[0]))-12:110),d(j,i+""))}function n(a,b){var c=U.h;return 0===b&&(c="left"===q||"right"===q?-((V[a.index]-1)*(U.h/2)-3):".71em"),c}function v(a){var b=p(a)+(o?0:u);return L[0]<b&&b<L[1]?r:0}function w(a){return a?a>0?"start":"end":"middle"}function x(a){return a?"rotate("+a+")":""}function y(a){return a?8*Math.sin(Math.PI*(a/180)):0}function z(a){return a?11.5-2.5*(a/15)*(a>0?1:-1):W}var A,B,C,D=k.g=a.select(this),E=this.__chart__||p,F=this.__chart__=g(),G=t?t:f(F),H=D.selectAll(".tick").data(G,F),I=H.enter().insert("g",".domain").attr("class","tick").style("opacity",1e-6),J=H.exit().remove(),K=j(H).style("opacity",1),L=p.rangeExtent?p.rangeExtent():e(p.range()),M=D.selectAll(".domain").data([0]),N=(M.enter().append("path").attr("class","domain"),j(M));I.append("line"),I.append("text");var O=I.select("line"),P=K.select("line"),Q=I.select("text"),R=K.select("text");b.isCategory?(u=Math.ceil((F(1)-F(0))/2),B=o?0:u,C=o?u:0):u=B=0;var S,T,U=i(D.select(".tick")),V=[],W=Math.max(r,0)+s,X="left"===q||"right"===q;S=H.select("text"),T=S.selectAll("tspan").data(function(a,c){var d=b.tickMultiline?m(a,b.tickWidth):[].concat(h(a));return V[c]=d.length,d.map(function(a){return{index:c,splitted:a}})}),T.enter().append("tspan"),T.exit().remove(),T.text(function(a){return a.splitted});var Y=b.tickTextRotate;switch(q){case"bottom":A=c,O.attr("y2",r),Q.attr("y",W),P.attr("x1",B).attr("x2",B).attr("y2",v),R.attr("x",0).attr("y",z(Y)).style("text-anchor",w(Y)).attr("transform",x(Y)),T.attr("x",0).attr("dy",n).attr("dx",y(Y)),N.attr("d","M"+L[0]+","+l+"V0H"+L[1]+"V"+l);break;case"top":A=c,O.attr("y2",-r),Q.attr("y",-W),P.attr("x2",0).attr("y2",-r),R.attr("x",0).attr("y",-W),S.style("text-anchor","middle"),T.attr("x",0).attr("dy","0em"),N.attr("d","M"+L[0]+","+-l+"V0H"+L[1]+"V"+-l);break;case"left":A=d,O.attr("x2",-r),Q.attr("x",-W),P.attr("x2",-r).attr("y1",C).attr("y2",C),R.attr("x",-W).attr("y",u),S.style("text-anchor","end"),T.attr("x",-W).attr("dy",n),N.attr("d","M"+-l+","+L[0]+"H0V"+L[1]+"H"+-l);break;case"right":A=d,O.attr("x2",r),Q.attr("x",W),P.attr("x2",r).attr("y2",0),R.attr("x",W).attr("y",0),S.style("text-anchor","start"),T.attr("x",W).attr("dy",n),N.attr("d","M"+l+","+L[0]+"H0V"+L[1]+"H"+l)}if(F.rangeBand){var Z=F,$=Z.rangeBand()/2;E=F=function(a){return Z(a)+$}}else E.rangeBand?E=F:J.call(A,F);I.call(A,E),K.call(A,F)})}var l,m,n,o,p=a.scale.linear(),q="bottom",r=6,s=3,t=null,u=0,v=!0;return b=b||{},l=b.withOuterTick?6:0,k.scale=function(a){return arguments.length?(p=a,k):p},k.orient=function(a){return arguments.length?(q=a in{top:1,right:1,bottom:1,left:1}?a+"":"bottom",k):q},k.tickFormat=function(a){return arguments.length?(m=a,k):m},k.tickCentered=function(a){return arguments.length?(o=a,k):o},k.tickOffset=function(){return u},k.tickInterval=function(){var a,c;return b.isCategory?a=2*u:(c=k.g.select("path.domain").node().getTotalLength()-2*l,a=c/k.g.selectAll("line").size()),a===1/0?0:a},k.ticks=function(){return arguments.length?(n=arguments,k):n},k.tickCulling=function(a){return arguments.length?(v=a,k):v},k.tickValues=function(a){if("function"==typeof a)t=function(){return a(p.domain())};else{if(!arguments.length)return t;t=a}return k},k}var h,i,j,k={version:"0.4.11"};k.generate=function(a){return new d(a)},k.chart={fn:d.prototype,internal:{fn:e.prototype,axis:{fn:f.prototype}}},h=k.chart.fn,i=k.chart.internal.fn,j=k.chart.internal.axis.fn,i.beforeInit=function(){},i.afterInit=function(){},i.init=function(){var a=this,b=a.config;if(a.initParams(),b.data_url)a.convertUrlToData(b.data_url,b.data_mimeType,b.data_headers,b.data_keys,a.initWithData);else if(b.data_json)a.initWithData(a.convertJsonToData(b.data_json,b.data_keys));else if(b.data_rows)a.initWithData(a.convertRowsToData(b.data_rows));else{if(!b.data_columns)throw Error("url or json or rows or columns is required.");a.initWithData(a.convertColumnsToData(b.data_columns))}},i.initParams=function(){var a=this,b=a.d3,c=a.config;a.clipId="c3-"+ +new Date+"-clip",a.clipIdForXAxis=a.clipId+"-xaxis",a.clipIdForYAxis=a.clipId+"-yaxis",a.clipIdForGrid=a.clipId+"-grid",a.clipIdForSubchart=a.clipId+"-subchart",a.clipPath=a.getClipPath(a.clipId),a.clipPathForXAxis=a.getClipPath(a.clipIdForXAxis),a.clipPathForYAxis=a.getClipPath(a.clipIdForYAxis),a.clipPathForGrid=a.getClipPath(a.clipIdForGrid),a.clipPathForSubchart=a.getClipPath(a.clipIdForSubchart),a.dragStart=null,a.dragging=!1,a.flowing=!1,a.cancelClick=!1,a.mouseover=!1,a.transiting=!1,a.color=a.generateColor(),a.levelColor=a.generateLevelColor(),a.dataTimeFormat=c.data_xLocaltime?b.time.format:b.time.format.utc,a.axisTimeFormat=c.axis_x_localtime?b.time.format:b.time.format.utc,a.defaultAxisTimeFormat=a.axisTimeFormat.multi([[".%L",function(a){return a.getMilliseconds()}],[":%S",function(a){return a.getSeconds()}],["%I:%M",function(a){return a.getMinutes()}],["%I %p",function(a){return a.getHours()}],["%-m/%-d",function(a){return a.getDay()&&1!==a.getDate()}],["%-m/%-d",function(a){return 1!==a.getDate()}],["%-m/%-d",function(a){return a.getMonth()}],["%Y/%-m/%-d",function(){return!0}]]),a.hiddenTargetIds=[],a.hiddenLegendIds=[],a.focusedTargetIds=[],a.defocusedTargetIds=[],a.xOrient=c.axis_rotated?"left":"bottom",a.yOrient=c.axis_rotated?c.axis_y_inner?"top":"bottom":c.axis_y_inner?"right":"left",a.y2Orient=c.axis_rotated?c.axis_y2_inner?"bottom":"top":c.axis_y2_inner?"left":"right",a.subXOrient=c.axis_rotated?"left":"bottom",a.isLegendRight="right"===c.legend_position,a.isLegendInset="inset"===c.legend_position,a.isLegendTop="top-left"===c.legend_inset_anchor||"top-right"===c.legend_inset_anchor,a.isLegendLeft="top-left"===c.legend_inset_anchor||"bottom-left"===c.legend_inset_anchor,a.legendStep=0,a.legendItemWidth=0,a.legendItemHeight=0,a.currentMaxTickWidths={x:0,y:0,y2:0},a.rotated_padding_left=30,a.rotated_padding_right=c.axis_rotated&&!c.axis_x_show?0:30,a.rotated_padding_top=5,a.withoutFadeIn={},a.intervalForObserveInserted=void 0,a.axes.subx=b.selectAll([])},i.initChartElements=function(){this.initBar&&this.initBar(),this.initLine&&this.initLine(),this.initArc&&this.initArc(),this.initGauge&&this.initGauge(),this.initText&&this.initText()},i.initWithData=function(a){var b,c,d=this,e=d.d3,g=d.config,h=!0;d.axis=new f(d),d.initPie&&d.initPie(),d.initBrush&&d.initBrush(),d.initZoom&&d.initZoom(),g.bindto?"function"==typeof g.bindto.node?d.selectChart=g.bindto:d.selectChart=e.select(g.bindto):d.selectChart=e.selectAll([]),d.selectChart.empty()&&(d.selectChart=e.select(document.createElement("div")).style("opacity",0),d.observeInserted(d.selectChart),h=!1),d.selectChart.html("").classed("c3",!0),d.data.xs={},d.data.targets=d.convertDataToTargets(a),g.data_filter&&(d.data.targets=d.data.targets.filter(g.data_filter)),g.data_hide&&d.addHiddenTargetIds(g.data_hide===!0?d.mapToIds(d.data.targets):g.data_hide),g.legend_hide&&d.addHiddenLegendIds(g.legend_hide===!0?d.mapToIds(d.data.targets):g.legend_hide),d.hasType("gauge")&&(g.legend_show=!1),d.updateSizes(),d.updateScales(),d.x.domain(e.extent(d.getXDomain(d.data.targets))),d.y.domain(d.getYDomain(d.data.targets,"y")),d.y2.domain(d.getYDomain(d.data.targets,"y2")),d.subX.domain(d.x.domain()),d.subY.domain(d.y.domain()),d.subY2.domain(d.y2.domain()),d.orgXDomain=d.x.domain(),d.brush&&d.brush.scale(d.subX),g.zoom_enabled&&d.zoom.scale(d.x),d.svg=d.selectChart.append("svg").style("overflow","hidden").on("mouseenter",function(){return g.onmouseover.call(d)}).on("mouseleave",function(){return g.onmouseout.call(d)}),d.config.svg_classname&&d.svg.attr("class",d.config.svg_classname),b=d.svg.append("defs"),d.clipChart=d.appendClip(b,d.clipId),d.clipXAxis=d.appendClip(b,d.clipIdForXAxis),d.clipYAxis=d.appendClip(b,d.clipIdForYAxis),d.clipGrid=d.appendClip(b,d.clipIdForGrid),d.clipSubchart=d.appendClip(b,d.clipIdForSubchart),d.updateSvgSize(),c=d.main=d.svg.append("g").attr("transform",d.getTranslate("main")),d.initSubchart&&d.initSubchart(),d.initTooltip&&d.initTooltip(),d.initLegend&&d.initLegend(),d.initTitle&&d.initTitle(),c.append("text").attr("class",l.text+" "+l.empty).attr("text-anchor","middle").attr("dominant-baseline","middle"),d.initRegion(),d.initGrid(),c.append("g").attr("clip-path",d.clipPath).attr("class",l.chart),g.grid_lines_front&&d.initGridLines(),d.initEventRect(),d.initChartElements(),c.insert("rect",g.zoom_privileged?null:"g."+l.regions).attr("class",l.zoomRect).attr("width",d.width).attr("height",d.height).style("opacity",0).on("dblclick.zoom",null),g.axis_x_extent&&d.brush.extent(d.getDefaultExtent()),d.axis.init(),d.updateTargets(d.data.targets),h&&(d.updateDimension(),d.config.oninit.call(d),d.redraw({withTransition:!1,withTransform:!0,withUpdateXDomain:!0,withUpdateOrgXDomain:!0,withTransitionForAxis:!1})),d.bindResize(),d.api.element=d.selectChart.node()},i.smoothLines=function(a,b){var c=this;"grid"===b&&a.each(function(){var a=c.d3.select(this),b=a.attr("x1"),d=a.attr("x2"),e=a.attr("y1"),f=a.attr("y2");a.attr({x1:Math.ceil(b),x2:Math.ceil(d),y1:Math.ceil(e),y2:Math.ceil(f)})})},i.updateSizes=function(){var a=this,b=a.config,c=a.legend?a.getLegendHeight():0,d=a.legend?a.getLegendWidth():0,e=a.isLegendRight||a.isLegendInset?0:c,f=a.hasArcType(),g=b.axis_rotated||f?0:a.getHorizontalAxisHeight("x"),h=b.subchart_show&&!f?b.subchart_size_height+g:0;a.currentWidth=a.getCurrentWidth(),a.currentHeight=a.getCurrentHeight(),a.margin=b.axis_rotated?{top:a.getHorizontalAxisHeight("y2")+a.getCurrentPaddingTop(),right:f?0:a.getCurrentPaddingRight(),bottom:a.getHorizontalAxisHeight("y")+e+a.getCurrentPaddingBottom(),left:h+(f?0:a.getCurrentPaddingLeft())}:{top:4+a.getCurrentPaddingTop(),right:f?0:a.getCurrentPaddingRight(),bottom:g+h+e+a.getCurrentPaddingBottom(),left:f?0:a.getCurrentPaddingLeft()},a.margin2=b.axis_rotated?{top:a.margin.top,right:NaN,bottom:20+e,left:a.rotated_padding_left}:{top:a.currentHeight-h-e,right:NaN,bottom:g+e,left:a.margin.left},a.margin3={top:0,right:NaN,bottom:0,left:0},a.updateSizeForLegend&&a.updateSizeForLegend(c,d),a.width=a.currentWidth-a.margin.left-a.margin.right,a.height=a.currentHeight-a.margin.top-a.margin.bottom,a.width<0&&(a.width=0),a.height<0&&(a.height=0),a.width2=b.axis_rotated?a.margin.left-a.rotated_padding_left-a.rotated_padding_right:a.width,a.height2=b.axis_rotated?a.height:a.currentHeight-a.margin2.top-a.margin2.bottom,a.width2<0&&(a.width2=0),a.height2<0&&(a.height2=0),a.arcWidth=a.width-(a.isLegendRight?d+10:0),a.arcHeight=a.height-(a.isLegendRight?0:10),a.hasType("gauge")&&!b.gauge_fullCircle&&(a.arcHeight+=a.height-a.getGaugeLabelHeight()),a.updateRadius&&a.updateRadius(),a.isLegendRight&&f&&(a.margin3.left=a.arcWidth/2+1.1*a.radiusExpanded)},i.updateTargets=function(a){var b=this;b.updateTargetsForText(a),b.updateTargetsForBar(a),b.updateTargetsForLine(a),b.hasArcType()&&b.updateTargetsForArc&&b.updateTargetsForArc(a),b.updateTargetsForSubchart&&b.updateTargetsForSubchart(a),b.showTargets()},i.showTargets=function(){var a=this;a.svg.selectAll("."+l.target).filter(function(b){return a.isTargetToShow(b.id)}).transition().duration(a.config.transition_duration).style("opacity",1)},i.redraw=function(a,b){var c,d,e,f,g,h,i,j,k,m,n,o,p,q,r,s,t,u,v,x,y,z,A,B,C,D,E,F,G,H=this,I=H.main,J=H.d3,K=H.config,L=H.getShapeIndices(H.isAreaType),M=H.getShapeIndices(H.isBarType),N=H.getShapeIndices(H.isLineType),O=H.hasArcType(),P=H.filterTargetsToShow(H.data.targets),Q=H.xv.bind(H);if(a=a||{},c=w(a,"withY",!0),d=w(a,"withSubchart",!0),e=w(a,"withTransition",!0),h=w(a,"withTransform",!1),i=w(a,"withUpdateXDomain",!1),j=w(a,"withUpdateOrgXDomain",!1),k=w(a,"withTrimXDomain",!0),p=w(a,"withUpdateXAxis",i),m=w(a,"withLegend",!1),n=w(a,"withEventRect",!0),o=w(a,"withDimension",!0),f=w(a,"withTransitionForExit",e),g=w(a,"withTransitionForAxis",e),v=e?K.transition_duration:0,x=f?v:0,y=g?v:0,b=b||H.axis.generateTransitions(y),m&&K.legend_show?H.updateLegend(H.mapToIds(H.data.targets),a,b):o&&H.updateDimension(!0),H.isCategorized()&&0===P.length&&H.x.domain([0,H.axes.x.selectAll(".tick").size()]),P.length?(H.updateXDomain(P,i,j,k),K.axis_x_tick_values||(B=H.axis.updateXAxisTickValues(P))):(H.xAxis.tickValues([]),H.subXAxis.tickValues([])),K.zoom_rescale&&!a.flow&&(E=H.x.orgDomain()),H.y.domain(H.getYDomain(P,"y",E)),H.y2.domain(H.getYDomain(P,"y2",E)),!K.axis_y_tick_values&&K.axis_y_tick_count&&H.yAxis.tickValues(H.axis.generateTickValues(H.y.domain(),K.axis_y_tick_count)),!K.axis_y2_tick_values&&K.axis_y2_tick_count&&H.y2Axis.tickValues(H.axis.generateTickValues(H.y2.domain(),K.axis_y2_tick_count)),H.axis.redraw(b,O),H.axis.updateLabels(e),(i||p)&&P.length)if(K.axis_x_tick_culling&&B){for(C=1;C<B.length;C++)if(B.length/C<K.axis_x_tick_culling_max){D=C;break}H.svg.selectAll("."+l.axisX+" .tick text").each(function(a){var b=B.indexOf(a);b>=0&&J.select(this).style("display",b%D?"none":"block")})}else H.svg.selectAll("."+l.axisX+" .tick text").style("display","block");q=H.generateDrawArea?H.generateDrawArea(L,!1):void 0,r=H.generateDrawBar?H.generateDrawBar(M):void 0,s=H.generateDrawLine?H.generateDrawLine(N,!1):void 0,t=H.generateXYForText(L,M,N,!0),u=H.generateXYForText(L,M,N,!1),c&&(H.subY.domain(H.getYDomain(P,"y")),H.subY2.domain(H.getYDomain(P,"y2"))),H.updateXgridFocus(),I.select("text."+l.text+"."+l.empty).attr("x",H.width/2).attr("y",H.height/2).text(K.data_empty_label_text).transition().style("opacity",P.length?0:1),H.updateGrid(v),H.updateRegion(v),H.updateBar(x),H.updateLine(x),H.updateArea(x),H.updateCircle(),H.hasDataLabel()&&H.updateText(x),H.redrawTitle&&H.redrawTitle(),H.redrawArc&&H.redrawArc(v,x,h),H.redrawSubchart&&H.redrawSubchart(d,b,v,x,L,M,N),I.selectAll("."+l.selectedCircles).filter(H.isBarType.bind(H)).selectAll("circle").remove(),K.interaction_enabled&&!a.flow&&n&&(H.redrawEventRect(),H.updateZoom&&H.updateZoom()),H.updateCircleY(),F=(H.config.axis_rotated?H.circleY:H.circleX).bind(H),G=(H.config.axis_rotated?H.circleX:H.circleY).bind(H),a.flow&&(A=H.generateFlow({targets:P,flow:a.flow,duration:a.flow.duration,drawBar:r,drawLine:s,drawArea:q,cx:F,cy:G,xv:Q,xForText:t,yForText:u})),(v||A)&&H.isTabVisible()?J.transition().duration(v).each(function(){var b=[];[H.redrawBar(r,!0),H.redrawLine(s,!0),H.redrawArea(q,!0),H.redrawCircle(F,G,!0),H.redrawText(t,u,a.flow,!0),H.redrawRegion(!0),H.redrawGrid(!0)].forEach(function(a){a.forEach(function(a){b.push(a)})}),z=H.generateWait(),b.forEach(function(a){z.add(a)})}).call(z,function(){A&&A(),K.onrendered&&K.onrendered.call(H)}):(H.redrawBar(r),H.redrawLine(s),H.redrawArea(q),H.redrawCircle(F,G),H.redrawText(t,u,a.flow),H.redrawRegion(),H.redrawGrid(),K.onrendered&&K.onrendered.call(H)),H.mapToIds(H.data.targets).forEach(function(a){H.withoutFadeIn[a]=!0})},i.updateAndRedraw=function(a){var b,c=this,d=c.config;a=a||{},a.withTransition=w(a,"withTransition",!0),a.withTransform=w(a,"withTransform",!1),a.withLegend=w(a,"withLegend",!1),a.withUpdateXDomain=!0,a.withUpdateOrgXDomain=!0,a.withTransitionForExit=!1,a.withTransitionForTransform=w(a,"withTransitionForTransform",a.withTransition),c.updateSizes(),a.withLegend&&d.legend_show||(b=c.axis.generateTransitions(a.withTransitionForAxis?d.transition_duration:0),c.updateScales(),c.updateSvgSize(),c.transformAll(a.withTransitionForTransform,b)),c.redraw(a,b)},i.redrawWithoutRescale=function(){this.redraw({withY:!1,withSubchart:!1,withEventRect:!1,withTransitionForAxis:!1})},i.isTimeSeries=function(){return"timeseries"===this.config.axis_x_type},i.isCategorized=function(){return this.config.axis_x_type.indexOf("categor")>=0},i.isCustomX=function(){var a=this,b=a.config;return!a.isTimeSeries()&&(b.data_x||v(b.data_xs))},i.isTimeSeriesY=function(){return"timeseries"===this.config.axis_y_type},i.getTranslate=function(a){var b,c,d=this,e=d.config;return"main"===a?(b=s(d.margin.left),c=s(d.margin.top)):"context"===a?(b=s(d.margin2.left),c=s(d.margin2.top)):"legend"===a?(b=d.margin3.left,c=d.margin3.top):"x"===a?(b=0,c=e.axis_rotated?0:d.height):"y"===a?(b=0,c=e.axis_rotated?d.height:0):"y2"===a?(b=e.axis_rotated?0:d.width,c=e.axis_rotated?1:0):"subx"===a?(b=0,c=e.axis_rotated?0:d.height2):"arc"===a&&(b=d.arcWidth/2,c=d.arcHeight/2),"translate("+b+","+c+")"},i.initialOpacity=function(a){return null!==a.value&&this.withoutFadeIn[a.id]?1:0},i.initialOpacityForCircle=function(a){return null!==a.value&&this.withoutFadeIn[a.id]?this.opacityForCircle(a):0},i.opacityForCircle=function(a){var b=this.config.point_show?1:0;return m(a.value)?this.isScatterType(a)?.5:b:0},i.opacityForText=function(){return this.hasDataLabel()?1:0},i.xx=function(a){return a?this.x(a.x):null},i.xv=function(a){var b=this,c=a.value;return b.isTimeSeries()?c=b.parseDate(a.value):b.isCategorized()&&"string"==typeof a.value&&(c=b.config.axis_x_categories.indexOf(a.value)),Math.ceil(b.x(c))},i.yv=function(a){var b=this,c=a.axis&&"y2"===a.axis?b.y2:b.y;return Math.ceil(c(a.value))},i.subxx=function(a){return a?this.subX(a.x):null},i.transformMain=function(a,b){var c,d,e,f=this;b&&b.axisX?c=b.axisX:(c=f.main.select("."+l.axisX),a&&(c=c.transition())),b&&b.axisY?d=b.axisY:(d=f.main.select("."+l.axisY),a&&(d=d.transition())),b&&b.axisY2?e=b.axisY2:(e=f.main.select("."+l.axisY2),a&&(e=e.transition())),(a?f.main.transition():f.main).attr("transform",f.getTranslate("main")),c.attr("transform",f.getTranslate("x")),d.attr("transform",f.getTranslate("y")),e.attr("transform",f.getTranslate("y2")),f.main.select("."+l.chartArcs).attr("transform",f.getTranslate("arc"))},i.transformAll=function(a,b){var c=this;c.transformMain(a,b),c.config.subchart_show&&c.transformContext(a,b),c.legend&&c.transformLegend(a)},i.updateSvgSize=function(){var a=this,b=a.svg.select(".c3-brush .background");a.svg.attr("width",a.currentWidth).attr("height",a.currentHeight),a.svg.selectAll(["#"+a.clipId,"#"+a.clipIdForGrid]).select("rect").attr("width",a.width).attr("height",a.height),a.svg.select("#"+a.clipIdForXAxis).select("rect").attr("x",a.getXAxisClipX.bind(a)).attr("y",a.getXAxisClipY.bind(a)).attr("width",a.getXAxisClipWidth.bind(a)).attr("height",a.getXAxisClipHeight.bind(a)),a.svg.select("#"+a.clipIdForYAxis).select("rect").attr("x",a.getYAxisClipX.bind(a)).attr("y",a.getYAxisClipY.bind(a)).attr("width",a.getYAxisClipWidth.bind(a)).attr("height",a.getYAxisClipHeight.bind(a)),a.svg.select("#"+a.clipIdForSubchart).select("rect").attr("width",a.width).attr("height",b.size()?b.attr("height"):0),a.svg.select("."+l.zoomRect).attr("width",a.width).attr("height",a.height),a.selectChart.style("max-height",a.currentHeight+"px")},i.updateDimension=function(a){var b=this;a||(b.config.axis_rotated?(b.axes.x.call(b.xAxis),b.axes.subx.call(b.subXAxis)):(b.axes.y.call(b.yAxis),b.axes.y2.call(b.y2Axis))),b.updateSizes(),b.updateScales(),b.updateSvgSize(),b.transformAll(!1)},i.observeInserted=function(b){var c,d=this;return"undefined"==typeof MutationObserver?void a.console.error("MutationObserver not defined."):(c=new MutationObserver(function(e){e.forEach(function(e){"childList"===e.type&&e.previousSibling&&(c.disconnect(),d.intervalForObserveInserted=a.setInterval(function(){b.node().parentNode&&(a.clearInterval(d.intervalForObserveInserted),d.updateDimension(),d.brush&&d.brush.update(),d.config.oninit.call(d),d.redraw({withTransform:!0,withUpdateXDomain:!0,withUpdateOrgXDomain:!0,withTransition:!1,withTransitionForTransform:!1,withLegend:!0}),b.transition().style("opacity",1))},10))})}),void c.observe(b.node(),{attributes:!0,childList:!0,characterData:!0}))},i.bindResize=function(){var b=this,c=b.config;if(b.resizeFunction=b.generateResize(),b.resizeFunction.add(function(){c.onresize.call(b)}),c.resize_auto&&b.resizeFunction.add(function(){void 0!==b.resizeTimeout&&a.clearTimeout(b.resizeTimeout),b.resizeTimeout=a.setTimeout(function(){delete b.resizeTimeout,b.api.flush()},100)}),b.resizeFunction.add(function(){c.onresized.call(b)}),a.attachEvent)a.attachEvent("onresize",b.resizeFunction);else if(a.addEventListener)a.addEventListener("resize",b.resizeFunction,!1);else{var d=a.onresize;d?d.add&&d.remove||(d=b.generateResize(),d.add(a.onresize)):d=b.generateResize(),d.add(b.resizeFunction),a.onresize=d}},i.generateResize=function(){function a(){b.forEach(function(a){a()})}var b=[];return a.add=function(a){b.push(a)},a.remove=function(a){for(var c=0;c<b.length;c++)if(b[c]===a){b.splice(c,1);break}},a},i.endall=function(a,b){var c=0;a.each(function(){++c}).each("end",function(){--c||b.apply(this,arguments)})},i.generateWait=function(){var a=[],b=function(b,c){var d=setInterval(function(){var b=0;a.forEach(function(a){if(a.empty())return void(b+=1);try{a.transition()}catch(c){b+=1}}),b===a.length&&(clearInterval(d),c&&c())},10)};return b.add=function(b){a.push(b)},b},i.parseDate=function(b){var c,d=this;return b instanceof Date?c=b:"string"==typeof b?c=d.dataTimeFormat(d.config.data_xFormat).parse(b):"number"!=typeof b||isNaN(b)||(c=new Date(+b)),c&&!isNaN(+c)||a.console.error("Failed to parse x '"+b+"' to Date object"),c},i.isTabVisible=function(){var a;return"undefined"!=typeof document.hidden?a="hidden":"undefined"!=typeof document.mozHidden?a="mozHidden":"undefined"!=typeof document.msHidden?a="msHidden":"undefined"!=typeof document.webkitHidden&&(a="webkitHidden"),!document[a]},i.getDefaultConfig=function(){var a={bindto:"#chart",svg_classname:void 0,size_width:void 0,size_height:void 0,padding_left:void 0,padding_right:void 0,padding_top:void 0,padding_bottom:void 0,resize_auto:!0,zoom_enabled:!1,zoom_extent:void 0,zoom_privileged:!1,zoom_rescale:!1,zoom_onzoom:function(){},zoom_onzoomstart:function(){},zoom_onzoomend:function(){},zoom_x_min:void 0,zoom_x_max:void 0,interaction_brighten:!0,interaction_enabled:!0,onmouseover:function(){},onmouseout:function(){},onresize:function(){},onresized:function(){},oninit:function(){},onrendered:function(){},transition_duration:350,data_x:void 0,data_xs:{},data_xFormat:"%Y-%m-%d",data_xLocaltime:!0,data_xSort:!0,data_idConverter:function(a){return a},data_names:{},data_classes:{},data_groups:[],data_axes:{},data_type:void 0,data_types:{},data_labels:{},data_order:"desc",data_regions:{},data_color:void 0,data_colors:{},data_hide:!1,data_filter:void 0,data_selection_enabled:!1,data_selection_grouped:!1,data_selection_isselectable:function(){return!0},data_selection_multiple:!0,data_selection_draggable:!1,data_onclick:function(){},data_onmouseover:function(){},data_onmouseout:function(){},data_onselected:function(){},data_onunselected:function(){},data_url:void 0,data_headers:void 0,data_json:void 0,data_rows:void 0,data_columns:void 0,data_mimeType:void 0,data_keys:void 0,data_empty_label_text:"",subchart_show:!1,subchart_size_height:60,subchart_axis_x_show:!0,subchart_onbrush:function(){},color_pattern:[],color_threshold:{},legend_show:!0,legend_hide:!1,legend_position:"bottom",legend_inset_anchor:"top-left",legend_inset_x:10,legend_inset_y:0,legend_inset_step:void 0,legend_item_onclick:void 0,legend_item_onmouseover:void 0,legend_item_onmouseout:void 0,legend_equally:!1,legend_padding:0,legend_item_tile_width:10,legend_item_tile_height:10,axis_rotated:!1,axis_x_show:!0,axis_x_type:"indexed",axis_x_localtime:!0,axis_x_categories:[],axis_x_tick_centered:!1,axis_x_tick_format:void 0,axis_x_tick_culling:{},axis_x_tick_culling_max:10,axis_x_tick_count:void 0,axis_x_tick_fit:!0,axis_x_tick_values:null,axis_x_tick_rotate:0,axis_x_tick_outer:!0,axis_x_tick_multiline:!0,axis_x_tick_width:null,axis_x_max:void 0,axis_x_min:void 0,axis_x_padding:{},axis_x_height:void 0,axis_x_extent:void 0,axis_x_label:{},axis_y_show:!0,axis_y_type:void 0,axis_y_max:void 0,axis_y_min:void 0,axis_y_inverted:!1,axis_y_center:void 0,axis_y_inner:void 0,axis_y_label:{},axis_y_tick_format:void 0,axis_y_tick_outer:!0,axis_y_tick_values:null,axis_y_tick_rotate:0,axis_y_tick_count:void 0,axis_y_tick_time_value:void 0,axis_y_tick_time_interval:void 0,axis_y_padding:{},axis_y_default:void 0,axis_y2_show:!1,axis_y2_max:void 0,axis_y2_min:void 0,axis_y2_inverted:!1,axis_y2_center:void 0,axis_y2_inner:void 0,axis_y2_label:{},axis_y2_tick_format:void 0,axis_y2_tick_outer:!0,axis_y2_tick_values:null,axis_y2_tick_count:void 0,axis_y2_padding:{},axis_y2_default:void 0,grid_x_show:!1,grid_x_type:"tick",grid_x_lines:[],grid_y_show:!1,grid_y_lines:[],grid_y_ticks:10,grid_focus_show:!0,grid_lines_front:!0,point_show:!0,point_r:2.5,point_sensitivity:10,point_focus_expand_enabled:!0,point_focus_expand_r:void 0,point_select_r:void 0,line_connectNull:!1,line_step_type:"step",bar_width:void 0,bar_width_ratio:.6,bar_width_max:void 0,bar_zerobased:!0,area_zerobased:!0,area_above:!1,pie_label_show:!0,pie_label_format:void 0,pie_label_threshold:.05,pie_label_ratio:void 0,pie_expand:{},pie_expand_duration:50,gauge_fullCircle:!1,gauge_label_show:!0,gauge_label_format:void 0,gauge_min:0,gauge_max:100,gauge_startingAngle:-1*Math.PI/2,gauge_units:void 0,gauge_width:void 0,gauge_expand:{},gauge_expand_duration:50,donut_label_show:!0,donut_label_format:void 0,donut_label_threshold:.05,donut_label_ratio:void 0,donut_width:void 0,donut_title:"",donut_expand:{},donut_expand_duration:50,spline_interpolation_type:"cardinal",regions:[],tooltip_show:!0,tooltip_grouped:!0,tooltip_format_title:void 0,tooltip_format_name:void 0,tooltip_format_value:void 0,tooltip_position:void 0,tooltip_contents:function(a,b,c,d){return this.getTooltipContent?this.getTooltipContent(a,b,c,d):""},tooltip_init_show:!1,tooltip_init_x:0,tooltip_init_position:{top:"0px",left:"50px"},tooltip_onshow:function(){},tooltip_onhide:function(){},title_text:void 0,title_padding:{top:0,right:0,bottom:0,left:0},title_position:"top-center"};return Object.keys(this.additionalConfig).forEach(function(b){a[b]=this.additionalConfig[b]},this),a},i.additionalConfig={},i.loadConfig=function(a){function b(){var a=d.shift();return a&&c&&"object"==typeof c&&a in c?(c=c[a],b()):a?void 0:c}var c,d,e,f=this.config;Object.keys(f).forEach(function(g){c=a,d=g.split("_"),e=b(),q(e)&&(f[g]=e)})},i.getScale=function(a,b,c){return(c?this.d3.time.scale():this.d3.scale.linear()).range([a,b])},i.getX=function(a,b,c,d){var e,f=this,g=f.getScale(a,b,f.isTimeSeries()),h=c?g.domain(c):g;f.isCategorized()?(d=d||function(){return 0},g=function(a,b){var c=h(a)+d(a);return b?c:Math.ceil(c)}):g=function(a,b){var c=h(a);return b?c:Math.ceil(c)};for(e in h)g[e]=h[e];return g.orgDomain=function(){return h.domain()},f.isCategorized()&&(g.domain=function(a){return arguments.length?(h.domain(a),g):(a=this.orgDomain(),[a[0],a[1]+1])}),g},i.getY=function(a,b,c){var d=this.getScale(a,b,this.isTimeSeriesY());return c&&d.domain(c),d},i.getYScale=function(a){return"y2"===this.axis.getId(a)?this.y2:this.y},i.getSubYScale=function(a){return"y2"===this.axis.getId(a)?this.subY2:this.subY},i.updateScales=function(){var a=this,b=a.config,c=!a.x;a.xMin=b.axis_rotated?1:0,a.xMax=b.axis_rotated?a.height:a.width,a.yMin=b.axis_rotated?0:a.height,a.yMax=b.axis_rotated?a.width:1,a.subXMin=a.xMin,a.subXMax=a.xMax,a.subYMin=b.axis_rotated?0:a.height2,a.subYMax=b.axis_rotated?a.width2:1,a.x=a.getX(a.xMin,a.xMax,c?void 0:a.x.orgDomain(),function(){return a.xAxis.tickOffset()}),a.y=a.getY(a.yMin,a.yMax,c?b.axis_y_default:a.y.domain()),a.y2=a.getY(a.yMin,a.yMax,c?b.axis_y2_default:a.y2.domain()),a.subX=a.getX(a.xMin,a.xMax,a.orgXDomain,function(b){return b%1?0:a.subXAxis.tickOffset()}),a.subY=a.getY(a.subYMin,a.subYMax,c?b.axis_y_default:a.subY.domain()),a.subY2=a.getY(a.subYMin,a.subYMax,c?b.axis_y2_default:a.subY2.domain()),a.xAxisTickFormat=a.axis.getXAxisTickFormat(),a.xAxisTickValues=a.axis.getXAxisTickValues(),a.yAxisTickValues=a.axis.getYAxisTickValues(),a.y2AxisTickValues=a.axis.getY2AxisTickValues(),a.xAxis=a.axis.getXAxis(a.x,a.xOrient,a.xAxisTickFormat,a.xAxisTickValues,b.axis_x_tick_outer),a.subXAxis=a.axis.getXAxis(a.subX,a.subXOrient,a.xAxisTickFormat,a.xAxisTickValues,b.axis_x_tick_outer),a.yAxis=a.axis.getYAxis(a.y,a.yOrient,b.axis_y_tick_format,a.yAxisTickValues,b.axis_y_tick_outer),a.y2Axis=a.axis.getYAxis(a.y2,a.y2Orient,b.axis_y2_tick_format,a.y2AxisTickValues,b.axis_y2_tick_outer),c||(a.brush&&a.brush.scale(a.subX),b.zoom_enabled&&a.zoom.scale(a.x)),a.updateArc&&a.updateArc()},i.getYDomainMin=function(a){var b,c,d,e,f,g,h=this,i=h.config,j=h.mapToIds(a),k=h.getValuesAsIdKeyed(a);if(i.data_groups.length>0)for(g=h.hasNegativeValueInTargets(a),b=0;b<i.data_groups.length;b++)if(e=i.data_groups[b].filter(function(a){return j.indexOf(a)>=0}),0!==e.length)for(d=e[0],g&&k[d]&&k[d].forEach(function(a,b){k[d][b]=0>a?a:0}),c=1;c<e.length;c++)f=e[c],k[f]&&k[f].forEach(function(a,b){h.axis.getId(f)!==h.axis.getId(d)||!k[d]||g&&+a>0||(k[d][b]+=+a)});return h.d3.min(Object.keys(k).map(function(a){return h.d3.min(k[a])}))},i.getYDomainMax=function(a){var b,c,d,e,f,g,h=this,i=h.config,j=h.mapToIds(a),k=h.getValuesAsIdKeyed(a);if(i.data_groups.length>0)for(g=h.hasPositiveValueInTargets(a),b=0;b<i.data_groups.length;b++)if(e=i.data_groups[b].filter(function(a){return j.indexOf(a)>=0}),0!==e.length)for(d=e[0],g&&k[d]&&k[d].forEach(function(a,b){k[d][b]=a>0?a:0}),c=1;c<e.length;c++)f=e[c],k[f]&&k[f].forEach(function(a,b){h.axis.getId(f)!==h.axis.getId(d)||!k[d]||g&&0>+a||(k[d][b]+=+a)});return h.d3.max(Object.keys(k).map(function(a){return h.d3.max(k[a])}))},i.getYDomain=function(a,b,c){var d,e,f,g,h,i,j,k,l,n,o,p=this,q=p.config,r=a.filter(function(a){return p.axis.getId(a.id)===b}),s=c?p.filterByXDomain(r,c):r,u="y2"===b?q.axis_y2_min:q.axis_y_min,w="y2"===b?q.axis_y2_max:q.axis_y_max,x=p.getYDomainMin(s),y=p.getYDomainMax(s),z="y2"===b?q.axis_y2_center:q.axis_y_center,A=p.hasType("bar",s)&&q.bar_zerobased||p.hasType("area",s)&&q.area_zerobased,B="y2"===b?q.axis_y2_inverted:q.axis_y_inverted,C=p.hasDataLabel()&&q.axis_rotated,D=p.hasDataLabel()&&!q.axis_rotated;return x=m(u)?u:m(w)?w>x?x:w-10:x,y=m(w)?w:m(u)?y>u?y:u+10:y,0===s.length?"y2"===b?p.y2.domain():p.y.domain():(isNaN(x)&&(x=0),isNaN(y)&&(y=x),x===y&&(0>x?y=0:x=0),n=x>=0&&y>=0,o=0>=x&&0>=y,(m(u)&&n||m(w)&&o)&&(A=!1),A&&(n&&(x=0),o&&(y=0)),e=Math.abs(y-x),f=g=h=.1*e,"undefined"!=typeof z&&(i=Math.max(Math.abs(x),Math.abs(y)),y=z+i,x=z-i),C?(j=p.getDataLabelLength(x,y,"width"),k=t(p.y.range()),l=[j[0]/k,j[1]/k],
2
- g+=e*(l[1]/(1-l[0]-l[1])),h+=e*(l[0]/(1-l[0]-l[1]))):D&&(j=p.getDataLabelLength(x,y,"height"),g+=p.axis.convertPixelsToAxisPadding(j[1],e),h+=p.axis.convertPixelsToAxisPadding(j[0],e)),"y"===b&&v(q.axis_y_padding)&&(g=p.axis.getPadding(q.axis_y_padding,"top",g,e),h=p.axis.getPadding(q.axis_y_padding,"bottom",h,e)),"y2"===b&&v(q.axis_y2_padding)&&(g=p.axis.getPadding(q.axis_y2_padding,"top",g,e),h=p.axis.getPadding(q.axis_y2_padding,"bottom",h,e)),A&&(n&&(h=x),o&&(g=-y)),d=[x-h,y+g],B?d.reverse():d)},i.getXDomainMin=function(a){var b=this,c=b.config;return q(c.axis_x_min)?b.isTimeSeries()?this.parseDate(c.axis_x_min):c.axis_x_min:b.d3.min(a,function(a){return b.d3.min(a.values,function(a){return a.x})})},i.getXDomainMax=function(a){var b=this,c=b.config;return q(c.axis_x_max)?b.isTimeSeries()?this.parseDate(c.axis_x_max):c.axis_x_max:b.d3.max(a,function(a){return b.d3.max(a.values,function(a){return a.x})})},i.getXDomainPadding=function(a){var b,c,d,e,f=this,g=f.config,h=a[1]-a[0];return f.isCategorized()?c=0:f.hasType("bar")?(b=f.getMaxDataCount(),c=b>1?h/(b-1)/2:.5):c=.01*h,"object"==typeof g.axis_x_padding&&v(g.axis_x_padding)?(d=m(g.axis_x_padding.left)?g.axis_x_padding.left:c,e=m(g.axis_x_padding.right)?g.axis_x_padding.right:c):d=e="number"==typeof g.axis_x_padding?g.axis_x_padding:c,{left:d,right:e}},i.getXDomain=function(a){var b=this,c=[b.getXDomainMin(a),b.getXDomainMax(a)],d=c[0],e=c[1],f=b.getXDomainPadding(c),g=0,h=0;return d-e!==0||b.isCategorized()||(b.isTimeSeries()?(d=new Date(.5*d.getTime()),e=new Date(1.5*e.getTime())):(d=0===d?1:.5*d,e=0===e?-1:1.5*e)),(d||0===d)&&(g=b.isTimeSeries()?new Date(d.getTime()-f.left):d-f.left),(e||0===e)&&(h=b.isTimeSeries()?new Date(e.getTime()+f.right):e+f.right),[g,h]},i.updateXDomain=function(a,b,c,d,e){var f=this,g=f.config;return c&&(f.x.domain(e?e:f.d3.extent(f.getXDomain(a))),f.orgXDomain=f.x.domain(),g.zoom_enabled&&f.zoom.scale(f.x).updateScaleExtent(),f.subX.domain(f.x.domain()),f.brush&&f.brush.scale(f.subX)),b&&(f.x.domain(e?e:!f.brush||f.brush.empty()?f.orgXDomain:f.brush.extent()),g.zoom_enabled&&f.zoom.scale(f.x).updateScaleExtent()),d&&f.x.domain(f.trimXDomain(f.x.orgDomain())),f.x.domain()},i.trimXDomain=function(a){var b=this.getZoomDomain(),c=b[0],d=b[1];return a[0]<=c&&(a[1]=+a[1]+(c-a[0]),a[0]=c),d<=a[1]&&(a[0]=+a[0]-(a[1]-d),a[1]=d),a},i.isX=function(a){var b=this,c=b.config;return c.data_x&&a===c.data_x||v(c.data_xs)&&x(c.data_xs,a)},i.isNotX=function(a){return!this.isX(a)},i.getXKey=function(a){var b=this,c=b.config;return c.data_x?c.data_x:v(c.data_xs)?c.data_xs[a]:null},i.getXValuesOfXKey=function(a,b){var c,d=this,e=b&&v(b)?d.mapToIds(b):[];return e.forEach(function(b){d.getXKey(b)===a&&(c=d.data.xs[b])}),c},i.getIndexByX=function(a){var b=this,c=b.filterByX(b.data.targets,a);return c.length?c[0].index:null},i.getXValue=function(a,b){var c=this;return a in c.data.xs&&c.data.xs[a]&&m(c.data.xs[a][b])?c.data.xs[a][b]:b},i.getOtherTargetXs=function(){var a=this,b=Object.keys(a.data.xs);return b.length?a.data.xs[b[0]]:null},i.getOtherTargetX=function(a){var b=this.getOtherTargetXs();return b&&a<b.length?b[a]:null},i.addXs=function(a){var b=this;Object.keys(a).forEach(function(c){b.config.data_xs[c]=a[c]})},i.hasMultipleX=function(a){return this.d3.set(Object.keys(a).map(function(b){return a[b]})).size()>1},i.isMultipleX=function(){return v(this.config.data_xs)||!this.config.data_xSort||this.hasType("scatter")},i.addName=function(a){var b,c=this;return a&&(b=c.config.data_names[a.id],a.name=void 0!==b?b:a.id),a},i.getValueOnIndex=function(a,b){var c=a.filter(function(a){return a.index===b});return c.length?c[0]:null},i.updateTargetX=function(a,b){var c=this;a.forEach(function(a){a.values.forEach(function(d,e){d.x=c.generateTargetX(b[e],a.id,e)}),c.data.xs[a.id]=b})},i.updateTargetXs=function(a,b){var c=this;a.forEach(function(a){b[a.id]&&c.updateTargetX([a],b[a.id])})},i.generateTargetX=function(a,b,c){var d,e=this;return d=e.isTimeSeries()?a?e.parseDate(a):e.parseDate(e.getXValue(b,c)):e.isCustomX()&&!e.isCategorized()?m(a)?+a:e.getXValue(b,c):c},i.cloneTarget=function(a){return{id:a.id,id_org:a.id_org,values:a.values.map(function(a){return{x:a.x,value:a.value,id:a.id}})}},i.updateXs=function(){var a=this;a.data.targets.length&&(a.xs=[],a.data.targets[0].values.forEach(function(b){a.xs[b.index]=b.x}))},i.getPrevX=function(a){var b=this.xs[a-1];return"undefined"!=typeof b?b:null},i.getNextX=function(a){var b=this.xs[a+1];return"undefined"!=typeof b?b:null},i.getMaxDataCount=function(){var a=this;return a.d3.max(a.data.targets,function(a){return a.values.length})},i.getMaxDataCountTarget=function(a){var b,c=a.length,d=0;return c>1?a.forEach(function(a){a.values.length>d&&(b=a,d=a.values.length)}):b=c?a[0]:null,b},i.getEdgeX=function(a){var b=this;return a.length?[b.d3.min(a,function(a){return a.values[0].x}),b.d3.max(a,function(a){return a.values[a.values.length-1].x})]:[0,0]},i.mapToIds=function(a){return a.map(function(a){return a.id})},i.mapToTargetIds=function(a){var b=this;return a?[].concat(a):b.mapToIds(b.data.targets)},i.hasTarget=function(a,b){var c,d=this.mapToIds(a);for(c=0;c<d.length;c++)if(d[c]===b)return!0;return!1},i.isTargetToShow=function(a){return this.hiddenTargetIds.indexOf(a)<0},i.isLegendToShow=function(a){return this.hiddenLegendIds.indexOf(a)<0},i.filterTargetsToShow=function(a){var b=this;return a.filter(function(a){return b.isTargetToShow(a.id)})},i.mapTargetsToUniqueXs=function(a){var b=this,c=b.d3.set(b.d3.merge(a.map(function(a){return a.values.map(function(a){return+a.x})}))).values();return c=b.isTimeSeries()?c.map(function(a){return new Date(+a)}):c.map(function(a){return+a}),c.sort(function(a,b){return b>a?-1:a>b?1:a>=b?0:NaN})},i.addHiddenTargetIds=function(a){this.hiddenTargetIds=this.hiddenTargetIds.concat(a)},i.removeHiddenTargetIds=function(a){this.hiddenTargetIds=this.hiddenTargetIds.filter(function(b){return a.indexOf(b)<0})},i.addHiddenLegendIds=function(a){this.hiddenLegendIds=this.hiddenLegendIds.concat(a)},i.removeHiddenLegendIds=function(a){this.hiddenLegendIds=this.hiddenLegendIds.filter(function(b){return a.indexOf(b)<0})},i.getValuesAsIdKeyed=function(a){var b={};return a.forEach(function(a){b[a.id]=[],a.values.forEach(function(c){b[a.id].push(c.value)})}),b},i.checkValueInTargets=function(a,b){var c,d,e,f=Object.keys(a);for(c=0;c<f.length;c++)for(e=a[f[c]].values,d=0;d<e.length;d++)if(b(e[d].value))return!0;return!1},i.hasNegativeValueInTargets=function(a){return this.checkValueInTargets(a,function(a){return 0>a})},i.hasPositiveValueInTargets=function(a){return this.checkValueInTargets(a,function(a){return a>0})},i.isOrderDesc=function(){var a=this.config;return"string"==typeof a.data_order&&"desc"===a.data_order.toLowerCase()},i.isOrderAsc=function(){var a=this.config;return"string"==typeof a.data_order&&"asc"===a.data_order.toLowerCase()},i.orderTargets=function(a){var b=this,c=b.config,d=b.isOrderAsc(),e=b.isOrderDesc();return d||e?a.sort(function(a,b){var c=function(a,b){return a+Math.abs(b.value)},e=a.values.reduce(c,0),f=b.values.reduce(c,0);return d?f-e:e-f}):n(c.data_order)&&a.sort(c.data_order),a},i.filterByX=function(a,b){return this.d3.merge(a.map(function(a){return a.values})).filter(function(a){return a.x-b===0})},i.filterRemoveNull=function(a){return a.filter(function(a){return m(a.value)})},i.filterByXDomain=function(a,b){return a.map(function(a){return{id:a.id,id_org:a.id_org,values:a.values.filter(function(a){return b[0]<=a.x&&a.x<=b[1]})}})},i.hasDataLabel=function(){var a=this.config;return"boolean"==typeof a.data_labels&&a.data_labels?!0:!("object"!=typeof a.data_labels||!v(a.data_labels))},i.getDataLabelLength=function(a,b,c){var d=this,e=[0,0],f=1.3;return d.selectChart.select("svg").selectAll(".dummy").data([a,b]).enter().append("text").text(function(a){return d.dataLabelFormat(a.id)(a)}).each(function(a,b){e[b]=this.getBoundingClientRect()[c]*f}).remove(),e},i.isNoneArc=function(a){return this.hasTarget(this.data.targets,a.id)},i.isArc=function(a){return"data"in a&&this.hasTarget(this.data.targets,a.data.id)},i.findSameXOfValues=function(a,b){var c,d=a[b].x,e=[];for(c=b-1;c>=0&&d===a[c].x;c--)e.push(a[c]);for(c=b;c<a.length&&d===a[c].x;c++)e.push(a[c]);return e},i.findClosestFromTargets=function(a,b){var c,d=this;return c=a.map(function(a){return d.findClosest(a.values,b)}),d.findClosest(c,b)},i.findClosest=function(a,b){var c,d=this,e=d.config.point_sensitivity;return a.filter(function(a){return a&&d.isBarType(a.id)}).forEach(function(a){var b=d.main.select("."+l.bars+d.getTargetSelectorSuffix(a.id)+" ."+l.bar+"-"+a.index).node();!c&&d.isWithinBar(b)&&(c=a)}),a.filter(function(a){return a&&!d.isBarType(a.id)}).forEach(function(a){var f=d.dist(a,b);e>f&&(e=f,c=a)}),c},i.dist=function(a,b){var c=this,d=c.config,e=d.axis_rotated?1:0,f=d.axis_rotated?0:1,g=c.circleY(a,a.index),h=c.x(a.x);return Math.sqrt(Math.pow(h-b[e],2)+Math.pow(g-b[f],2))},i.convertValuesToStep=function(a){var b,c=[].concat(a);if(!this.isCategorized())return a;for(b=a.length+1;b>0;b--)c[b]=c[b-1];return c[0]={x:c[0].x-1,value:c[0].value,id:c[0].id},c[a.length+1]={x:c[a.length].x+1,value:c[a.length].value,id:c[a.length].id},c},i.updateDataAttributes=function(a,b){var c=this,d=c.config,e=d["data_"+a];return"undefined"==typeof b?e:(Object.keys(b).forEach(function(a){e[a]=b[a]}),c.redraw({withLegend:!0}),e)},i.convertUrlToData=function(a,b,c,d,e){var f=this,g=b?b:"csv",h=f.d3.xhr(a);c&&Object.keys(c).forEach(function(a){h.header(a,c[a])}),h.get(function(a,b){var c;if(!b)throw new Error(a.responseURL+" "+a.status+" ("+a.statusText+")");c="json"===g?f.convertJsonToData(JSON.parse(b.response),d):"tsv"===g?f.convertTsvToData(b.response):f.convertCsvToData(b.response),e.call(f,c)})},i.convertXsvToData=function(a,b){var c,d=b.parseRows(a);return 1===d.length?(c=[{}],d[0].forEach(function(a){c[0][a]=null})):c=b.parse(a),c},i.convertCsvToData=function(a){return this.convertXsvToData(a,this.d3.csv)},i.convertTsvToData=function(a){return this.convertXsvToData(a,this.d3.tsv)},i.convertJsonToData=function(a,b){var c,d,e=this,f=[];return b?(b.x?(c=b.value.concat(b.x),e.config.data_x=b.x):c=b.value,f.push(c),a.forEach(function(a){var b=[];c.forEach(function(c){var d=e.findValueInJson(a,c);p(d)&&(d=null),b.push(d)}),f.push(b)}),d=e.convertRowsToData(f)):(Object.keys(a).forEach(function(b){f.push([b].concat(a[b]))}),d=e.convertColumnsToData(f)),d},i.findValueInJson=function(a,b){b=b.replace(/\[(\w+)\]/g,".$1"),b=b.replace(/^\./,"");for(var c=b.split("."),d=0;d<c.length;++d){var e=c[d];if(!(e in a))return;a=a[e]}return a},i.convertRowsToData=function(a){var b,c,d=a[0],e={},f=[];for(b=1;b<a.length;b++){for(e={},c=0;c<a[b].length;c++){if(p(a[b][c]))throw new Error("Source data is missing a component at ("+b+","+c+")!");e[d[c]]=a[b][c]}f.push(e)}return f},i.convertColumnsToData=function(a){var b,c,d,e=[];for(b=0;b<a.length;b++)for(d=a[b][0],c=1;c<a[b].length;c++){if(p(e[c-1])&&(e[c-1]={}),p(a[b][c]))throw new Error("Source data is missing a component at ("+b+","+c+")!");e[c-1][d]=a[b][c]}return e},i.convertDataToTargets=function(a,b){var c,d=this,e=d.config,f=d.d3.keys(a[0]).filter(d.isNotX,d),g=d.d3.keys(a[0]).filter(d.isX,d);return f.forEach(function(c){var f=d.getXKey(c);d.isCustomX()||d.isTimeSeries()?g.indexOf(f)>=0?d.data.xs[c]=(b&&d.data.xs[c]?d.data.xs[c]:[]).concat(a.map(function(a){return a[f]}).filter(m).map(function(a,b){return d.generateTargetX(a,c,b)})):e.data_x?d.data.xs[c]=d.getOtherTargetXs():v(e.data_xs)&&(d.data.xs[c]=d.getXValuesOfXKey(f,d.data.targets)):d.data.xs[c]=a.map(function(a,b){return b})}),f.forEach(function(a){if(!d.data.xs[a])throw new Error('x is not defined for id = "'+a+'".')}),c=f.map(function(b,c){var f=e.data_idConverter(b);return{id:f,id_org:b,values:a.map(function(a,g){var h,i=d.getXKey(b),j=a[i],k=null===a[b]||isNaN(a[b])?null:+a[b];return d.isCustomX()&&d.isCategorized()&&0===c&&!p(j)?(0===c&&0===g&&(e.axis_x_categories=[]),h=e.axis_x_categories.indexOf(j),-1===h&&(h=e.axis_x_categories.length,e.axis_x_categories.push(j))):h=d.generateTargetX(j,b,g),(p(a[b])||d.data.xs[b].length<=g)&&(h=void 0),{x:h,value:k,id:f}}).filter(function(a){return q(a.x)})}}),c.forEach(function(a){var b;e.data_xSort&&(a.values=a.values.sort(function(a,b){var c=a.x||0===a.x?a.x:1/0,d=b.x||0===b.x?b.x:1/0;return c-d})),b=0,a.values.forEach(function(a){a.index=b++}),d.data.xs[a.id].sort(function(a,b){return a-b})}),d.hasNegativeValue=d.hasNegativeValueInTargets(c),d.hasPositiveValue=d.hasPositiveValueInTargets(c),e.data_type&&d.setTargetType(d.mapToIds(c).filter(function(a){return!(a in e.data_types)}),e.data_type),c.forEach(function(a){d.addCache(a.id_org,a)}),c},i.load=function(a,b){var c=this;a&&(b.filter&&(a=a.filter(b.filter)),(b.type||b.types)&&a.forEach(function(a){var d=b.types&&b.types[a.id]?b.types[a.id]:b.type;c.setTargetType(a.id,d)}),c.data.targets.forEach(function(b){for(var c=0;c<a.length;c++)if(b.id===a[c].id){b.values=a[c].values,a.splice(c,1);break}}),c.data.targets=c.data.targets.concat(a)),c.updateTargets(c.data.targets),c.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0,withLegend:!0}),b.done&&b.done()},i.loadFromArgs=function(a){var b=this;a.data?b.load(b.convertDataToTargets(a.data),a):a.url?b.convertUrlToData(a.url,a.mimeType,a.headers,a.keys,function(c){b.load(b.convertDataToTargets(c),a)}):a.json?b.load(b.convertDataToTargets(b.convertJsonToData(a.json,a.keys)),a):a.rows?b.load(b.convertDataToTargets(b.convertRowsToData(a.rows)),a):a.columns?b.load(b.convertDataToTargets(b.convertColumnsToData(a.columns)),a):b.load(null,a)},i.unload=function(a,b){var c=this;return b||(b=function(){}),a=a.filter(function(a){return c.hasTarget(c.data.targets,a)}),a&&0!==a.length?(c.svg.selectAll(a.map(function(a){return c.selectorTarget(a)})).transition().style("opacity",0).remove().call(c.endall,b),void a.forEach(function(a){c.withoutFadeIn[a]=!1,c.legend&&c.legend.selectAll("."+l.legendItem+c.getTargetSelectorSuffix(a)).remove(),c.data.targets=c.data.targets.filter(function(b){return b.id!==a})})):void b()},i.categoryName=function(a){var b=this.config;return a<b.axis_x_categories.length?b.axis_x_categories[a]:a},i.initEventRect=function(){var a=this;a.main.select("."+l.chart).append("g").attr("class",l.eventRects).style("fill-opacity",0)},i.redrawEventRect=function(){var a,b,c=this,d=c.config,e=c.isMultipleX(),f=c.main.select("."+l.eventRects).style("cursor",d.zoom_enabled?d.axis_rotated?"ns-resize":"ew-resize":null).classed(l.eventRectsMultiple,e).classed(l.eventRectsSingle,!e);f.selectAll("."+l.eventRect).remove(),c.eventRect=f.selectAll("."+l.eventRect),e?(a=c.eventRect.data([0]),c.generateEventRectsForMultipleXs(a.enter()),c.updateEventRect(a)):(b=c.getMaxDataCountTarget(c.data.targets),f.datum(b?b.values:[]),c.eventRect=f.selectAll("."+l.eventRect),a=c.eventRect.data(function(a){return a}),c.generateEventRectsForSingleX(a.enter()),c.updateEventRect(a),a.exit().remove())},i.updateEventRect=function(a){var b,c,d,e,f,g,h=this,i=h.config;a=a||h.eventRect.data(function(a){return a}),h.isMultipleX()?(b=0,c=0,d=h.width,e=h.height):(!h.isCustomX()&&!h.isTimeSeries()||h.isCategorized()?(f=h.getEventRectWidth(),g=function(a){return h.x(a.x)-f/2}):(h.updateXs(),f=function(a){var b=h.getPrevX(a.index),c=h.getNextX(a.index);return null===b&&null===c?i.axis_rotated?h.height:h.width:(null===b&&(b=h.x.domain()[0]),null===c&&(c=h.x.domain()[1]),Math.max(0,(h.x(c)-h.x(b))/2))},g=function(a){var b=h.getPrevX(a.index),c=h.getNextX(a.index),d=h.data.xs[a.id][a.index];return null===b&&null===c?0:(null===b&&(b=h.x.domain()[0]),(h.x(d)+h.x(b))/2)}),b=i.axis_rotated?0:g,c=i.axis_rotated?g:0,d=i.axis_rotated?h.width:f,e=i.axis_rotated?f:h.height),a.attr("class",h.classEvent.bind(h)).attr("x",b).attr("y",c).attr("width",d).attr("height",e)},i.generateEventRectsForSingleX=function(a){var b=this,c=b.d3,d=b.config;a.append("rect").attr("class",b.classEvent.bind(b)).style("cursor",d.data_selection_enabled&&d.data_selection_grouped?"pointer":null).on("mouseover",function(a){var c=a.index;b.dragging||b.flowing||b.hasArcType()||(d.point_focus_expand_enabled&&b.expandCircles(c,null,!0),b.expandBars(c,null,!0),b.main.selectAll("."+l.shape+"-"+c).each(function(a){d.data_onmouseover.call(b.api,a)}))}).on("mouseout",function(a){var c=a.index;b.config&&(b.hasArcType()||(b.hideXGridFocus(),b.hideTooltip(),b.unexpandCircles(),b.unexpandBars(),b.main.selectAll("."+l.shape+"-"+c).each(function(a){d.data_onmouseout.call(b.api,a)})))}).on("mousemove",function(a){var e,f=a.index,g=b.svg.select("."+l.eventRect+"-"+f);b.dragging||b.flowing||b.hasArcType()||(b.isStepType(a)&&"step-after"===b.config.line_step_type&&c.mouse(this)[0]<b.x(b.getXValue(a.id,f))&&(f-=1),e=b.filterTargetsToShow(b.data.targets).map(function(a){return b.addName(b.getValueOnIndex(a.values,f))}),d.tooltip_grouped&&(b.showTooltip(e,this),b.showXGridFocus(e)),(!d.tooltip_grouped||d.data_selection_enabled&&!d.data_selection_grouped)&&b.main.selectAll("."+l.shape+"-"+f).each(function(){c.select(this).classed(l.EXPANDED,!0),d.data_selection_enabled&&g.style("cursor",d.data_selection_grouped?"pointer":null),d.tooltip_grouped||(b.hideXGridFocus(),b.hideTooltip(),d.data_selection_grouped||(b.unexpandCircles(f),b.unexpandBars(f)))}).filter(function(a){return b.isWithinShape(this,a)}).each(function(a){d.data_selection_enabled&&(d.data_selection_grouped||d.data_selection_isselectable(a))&&g.style("cursor","pointer"),d.tooltip_grouped||(b.showTooltip([a],this),b.showXGridFocus([a]),d.point_focus_expand_enabled&&b.expandCircles(f,a.id,!0),b.expandBars(f,a.id,!0))}))}).on("click",function(a){var e=a.index;if(!b.hasArcType()&&b.toggleShape){if(b.cancelClick)return void(b.cancelClick=!1);b.isStepType(a)&&"step-after"===d.line_step_type&&c.mouse(this)[0]<b.x(b.getXValue(a.id,e))&&(e-=1),b.main.selectAll("."+l.shape+"-"+e).each(function(a){(d.data_selection_grouped||b.isWithinShape(this,a))&&(b.toggleShape(this,a,e),b.config.data_onclick.call(b.api,a,this))})}}).call(d.data_selection_draggable&&b.drag?c.behavior.drag().origin(Object).on("drag",function(){b.drag(c.mouse(this))}).on("dragstart",function(){b.dragstart(c.mouse(this))}).on("dragend",function(){b.dragend()}):function(){})},i.generateEventRectsForMultipleXs=function(a){function b(){c.svg.select("."+l.eventRect).style("cursor",null),c.hideXGridFocus(),c.hideTooltip(),c.unexpandCircles(),c.unexpandBars()}var c=this,d=c.d3,e=c.config;a.append("rect").attr("x",0).attr("y",0).attr("width",c.width).attr("height",c.height).attr("class",l.eventRect).on("mouseout",function(){c.config&&(c.hasArcType()||b())}).on("mousemove",function(){var a,f,g,h,i=c.filterTargetsToShow(c.data.targets);if(!c.dragging&&!c.hasArcType(i)){if(a=d.mouse(this),f=c.findClosestFromTargets(i,a),!c.mouseover||f&&f.id===c.mouseover.id||(e.data_onmouseout.call(c.api,c.mouseover),c.mouseover=void 0),!f)return void b();g=c.isScatterType(f)||!e.tooltip_grouped?[f]:c.filterByX(i,f.x),h=g.map(function(a){return c.addName(a)}),c.showTooltip(h,this),e.point_focus_expand_enabled&&c.expandCircles(f.index,f.id,!0),c.expandBars(f.index,f.id,!0),c.showXGridFocus(h),(c.isBarType(f.id)||c.dist(f,a)<e.point_sensitivity)&&(c.svg.select("."+l.eventRect).style("cursor","pointer"),c.mouseover||(e.data_onmouseover.call(c.api,f),c.mouseover=f))}}).on("click",function(){var a,b,f=c.filterTargetsToShow(c.data.targets);c.hasArcType(f)||(a=d.mouse(this),b=c.findClosestFromTargets(f,a),b&&(c.isBarType(b.id)||c.dist(b,a)<e.point_sensitivity)&&c.main.selectAll("."+l.shapes+c.getTargetSelectorSuffix(b.id)).selectAll("."+l.shape+"-"+b.index).each(function(){(e.data_selection_grouped||c.isWithinShape(this,b))&&(c.toggleShape(this,b,b.index),c.config.data_onclick.call(c.api,b,this))}))}).call(e.data_selection_draggable&&c.drag?d.behavior.drag().origin(Object).on("drag",function(){c.drag(d.mouse(this))}).on("dragstart",function(){c.dragstart(d.mouse(this))}).on("dragend",function(){c.dragend()}):function(){})},i.dispatchEvent=function(b,c,d){var e=this,f="."+l.eventRect+(e.isMultipleX()?"":"-"+c),g=e.main.select(f).node(),h=g.getBoundingClientRect(),i=h.left+(d?d[0]:0),j=h.top+(d?d[1]:0),k=document.createEvent("MouseEvents");k.initMouseEvent(b,!0,!0,a,0,i,j,i,j,!1,!1,!1,!1,0,null),g.dispatchEvent(k)},i.getCurrentWidth=function(){var a=this,b=a.config;return b.size_width?b.size_width:a.getParentWidth()},i.getCurrentHeight=function(){var a=this,b=a.config,c=b.size_height?b.size_height:a.getParentHeight();return c>0?c:320/(a.hasType("gauge")&&!b.gauge_fullCircle?2:1)},i.getCurrentPaddingTop=function(){var a=this,b=a.config,c=m(b.padding_top)?b.padding_top:0;return a.title&&a.title.node()&&(c+=a.getTitlePadding()),c},i.getCurrentPaddingBottom=function(){var a=this.config;return m(a.padding_bottom)?a.padding_bottom:0},i.getCurrentPaddingLeft=function(a){var b=this,c=b.config;return m(c.padding_left)?c.padding_left:c.axis_rotated?c.axis_x_show?Math.max(r(b.getAxisWidthByAxisId("x",a)),40):1:!c.axis_y_show||c.axis_y_inner?b.axis.getYAxisLabelPosition().isOuter?30:1:r(b.getAxisWidthByAxisId("y",a))},i.getCurrentPaddingRight=function(){var a=this,b=a.config,c=10,d=a.isLegendRight?a.getLegendWidth()+20:0;return m(b.padding_right)?b.padding_right+1:b.axis_rotated?c+d:!b.axis_y2_show||b.axis_y2_inner?2+d+(a.axis.getY2AxisLabelPosition().isOuter?20:0):r(a.getAxisWidthByAxisId("y2"))+d},i.getParentRectValue=function(a){for(var b,c=this.selectChart.node();c&&"BODY"!==c.tagName;){try{b=c.getBoundingClientRect()[a]}catch(d){"width"===a&&(b=c.offsetWidth)}if(b)break;c=c.parentNode}return b},i.getParentWidth=function(){return this.getParentRectValue("width")},i.getParentHeight=function(){var a=this.selectChart.style("height");return a.indexOf("px")>0?+a.replace("px",""):0},i.getSvgLeft=function(a){var b=this,c=b.config,d=c.axis_rotated||!c.axis_rotated&&!c.axis_y_inner,e=c.axis_rotated?l.axisX:l.axisY,f=b.main.select("."+e).node(),g=f&&d?f.getBoundingClientRect():{right:0},h=b.selectChart.node().getBoundingClientRect(),i=b.hasArcType(),j=g.right-h.left-(i?0:b.getCurrentPaddingLeft(a));return j>0?j:0},i.getAxisWidthByAxisId=function(a,b){var c=this,d=c.axis.getLabelPositionById(a);return c.axis.getMaxTickWidth(a,b)+(d.isInner?20:40)},i.getHorizontalAxisHeight=function(a){var b=this,c=b.config,d=30;return"x"!==a||c.axis_x_show?"x"===a&&c.axis_x_height?c.axis_x_height:"y"!==a||c.axis_y_show?"y2"!==a||c.axis_y2_show?("x"===a&&!c.axis_rotated&&c.axis_x_tick_rotate&&(d=30+b.axis.getMaxTickWidth(a)*Math.cos(Math.PI*(90-c.axis_x_tick_rotate)/180)),"y"===a&&c.axis_rotated&&c.axis_y_tick_rotate&&(d=30+b.axis.getMaxTickWidth(a)*Math.cos(Math.PI*(90-c.axis_y_tick_rotate)/180)),d+(b.axis.getLabelPositionById(a).isInner?0:10)+("y2"===a?-10:0)):b.rotated_padding_top:!c.legend_show||b.isLegendRight||b.isLegendInset?1:10:8},i.getEventRectWidth=function(){return Math.max(0,this.xAxis.tickInterval())},i.getShapeIndices=function(a){var b,c,d=this,e=d.config,f={},g=0;return d.filterTargetsToShow(d.data.targets.filter(a,d)).forEach(function(a){for(b=0;b<e.data_groups.length;b++)if(!(e.data_groups[b].indexOf(a.id)<0))for(c=0;c<e.data_groups[b].length;c++)if(e.data_groups[b][c]in f){f[a.id]=f[e.data_groups[b][c]];break}p(f[a.id])&&(f[a.id]=g++)}),f.__max__=g-1,f},i.getShapeX=function(a,b,c,d){var e=this,f=d?e.subX:e.x;return function(d){var e=d.id in c?c[d.id]:0;return d.x||0===d.x?f(d.x)-a*(b/2-e):0}},i.getShapeY=function(a){var b=this;return function(c){var d=a?b.getSubYScale(c.id):b.getYScale(c.id);return d(c.value)}},i.getShapeOffset=function(a,b,c){var d=this,e=d.orderTargets(d.filterTargetsToShow(d.data.targets.filter(a,d))),f=e.map(function(a){return a.id});return function(a,g){var h=c?d.getSubYScale(a.id):d.getYScale(a.id),i=h(0),j=i;return e.forEach(function(c){var e=d.isStepType(a)?d.convertValuesToStep(c.values):c.values;c.id!==a.id&&b[c.id]===b[a.id]&&f.indexOf(c.id)<f.indexOf(a.id)&&("undefined"!=typeof e[g]&&+e[g].x===+a.x||(g=-1,e.forEach(function(b,c){b.x===a.x&&(g=c)})),g in e&&e[g].value*a.value>=0&&(j+=h(e[g].value)-i))}),j}},i.isWithinShape=function(a,b){var c,d=this,e=d.d3.select(a);return d.isTargetToShow(b.id)?"circle"===a.nodeName?c=d.isStepType(b)?d.isWithinStep(a,d.getYScale(b.id)(b.value)):d.isWithinCircle(a,1.5*d.pointSelectR(b)):"path"===a.nodeName&&(c=e.classed(l.bar)?d.isWithinBar(a):!0):c=!1,c},i.getInterpolate=function(a){var b=this,c=b.isInterpolationType(b.config.spline_interpolation_type)?b.config.spline_interpolation_type:"cardinal";return b.isSplineType(a)?c:b.isStepType(a)?b.config.line_step_type:"linear"},i.initLine=function(){var a=this;a.main.select("."+l.chart).append("g").attr("class",l.chartLines)},i.updateTargetsForLine=function(a){var b,c,d=this,e=d.config,f=d.classChartLine.bind(d),g=d.classLines.bind(d),h=d.classAreas.bind(d),i=d.classCircles.bind(d),j=d.classFocus.bind(d);b=d.main.select("."+l.chartLines).selectAll("."+l.chartLine).data(a).attr("class",function(a){return f(a)+j(a)}),c=b.enter().append("g").attr("class",f).style("opacity",0).style("pointer-events","none"),c.append("g").attr("class",g),c.append("g").attr("class",h),c.append("g").attr("class",function(a){return d.generateClass(l.selectedCircles,a.id)}),c.append("g").attr("class",i).style("cursor",function(a){return e.data_selection_isselectable(a)?"pointer":null}),a.forEach(function(a){d.main.selectAll("."+l.selectedCircles+d.getTargetSelectorSuffix(a.id)).selectAll("."+l.selectedCircle).each(function(b){b.value=a.values[b.index].value})})},i.updateLine=function(a){var b=this;b.mainLine=b.main.selectAll("."+l.lines).selectAll("."+l.line).data(b.lineData.bind(b)),b.mainLine.enter().append("path").attr("class",b.classLine.bind(b)).style("stroke",b.color),b.mainLine.style("opacity",b.initialOpacity.bind(b)).style("shape-rendering",function(a){return b.isStepType(a)?"crispEdges":""}).attr("transform",null),b.mainLine.exit().transition().duration(a).style("opacity",0).remove()},i.redrawLine=function(a,b){return[(b?this.mainLine.transition(Math.random().toString()):this.mainLine).attr("d",a).style("stroke",this.color).style("opacity",1)]},i.generateDrawLine=function(a,b){var c=this,d=c.config,e=c.d3.svg.line(),f=c.generateGetLinePoints(a,b),g=b?c.getSubYScale:c.getYScale,h=function(a){return(b?c.subxx:c.xx).call(c,a)},i=function(a,b){return d.data_groups.length>0?f(a,b)[0][1]:g.call(c,a.id)(a.value)};return e=d.axis_rotated?e.x(i).y(h):e.x(h).y(i),d.line_connectNull||(e=e.defined(function(a){return null!=a.value})),function(a){var f,h=d.line_connectNull?c.filterRemoveNull(a.values):a.values,i=b?c.x:c.subX,j=g.call(c,a.id),k=0,l=0;return c.isLineType(a)?d.data_regions[a.id]?f=c.lineWithRegions(h,i,j,d.data_regions[a.id]):(c.isStepType(a)&&(h=c.convertValuesToStep(h)),f=e.interpolate(c.getInterpolate(a))(h)):(h[0]&&(k=i(h[0].x),l=j(h[0].value)),f=d.axis_rotated?"M "+l+" "+k:"M "+k+" "+l),f?f:"M 0 0"}},i.generateGetLinePoints=function(a,b){var c=this,d=c.config,e=a.__max__+1,f=c.getShapeX(0,e,a,!!b),g=c.getShapeY(!!b),h=c.getShapeOffset(c.isLineType,a,!!b),i=b?c.getSubYScale:c.getYScale;return function(a,b){var e=i.call(c,a.id)(0),j=h(a,b)||e,k=f(a),l=g(a);return d.axis_rotated&&(0<a.value&&e>l||a.value<0&&l>e)&&(l=e),[[k,l-(e-j)],[k,l-(e-j)],[k,l-(e-j)],[k,l-(e-j)]]}},i.lineWithRegions=function(a,b,c,d){function e(a,b){var c;for(c=0;c<b.length;c++)if(b[c].start<a&&a<=b[c].end)return!0;return!1}function f(a){return"M"+a[0][0]+" "+a[0][1]+" "+a[1][0]+" "+a[1][1]}var g,h,i,j,k,l,m,n,o,r,s,t,u=this,v=u.config,w=-1,x="M",y=u.isCategorized()?.5:0,z=[];if(q(d))for(g=0;g<d.length;g++)z[g]={},p(d[g].start)?z[g].start=a[0].x:z[g].start=u.isTimeSeries()?u.parseDate(d[g].start):d[g].start,p(d[g].end)?z[g].end=a[a.length-1].x:z[g].end=u.isTimeSeries()?u.parseDate(d[g].end):d[g].end;for(s=v.axis_rotated?function(a){return c(a.value)}:function(a){return b(a.x)},t=v.axis_rotated?function(a){return b(a.x)}:function(a){return c(a.value)},i=u.isTimeSeries()?function(a,d,e,g){var h,i=a.x.getTime(),j=d.x-a.x,l=new Date(i+j*e),m=new Date(i+j*(e+g));return h=v.axis_rotated?[[c(k(e)),b(l)],[c(k(e+g)),b(m)]]:[[b(l),c(k(e))],[b(m),c(k(e+g))]],f(h)}:function(a,d,e,g){var h;return h=v.axis_rotated?[[c(k(e),!0),b(j(e))],[c(k(e+g),!0),b(j(e+g))]]:[[b(j(e),!0),c(k(e))],[b(j(e+g),!0),c(k(e+g))]],f(h)},g=0;g<a.length;g++){if(p(z)||!e(a[g].x,z))x+=" "+s(a[g])+" "+t(a[g]);else for(j=u.getScale(a[g-1].x+y,a[g].x+y,u.isTimeSeries()),k=u.getScale(a[g-1].value,a[g].value),l=b(a[g].x)-b(a[g-1].x),m=c(a[g].value)-c(a[g-1].value),n=Math.sqrt(Math.pow(l,2)+Math.pow(m,2)),o=2/n,r=2*o,h=o;1>=h;h+=r)x+=i(a[g-1],a[g],h,o);w=a[g].x}return x},i.updateArea=function(a){var b=this,c=b.d3;b.mainArea=b.main.selectAll("."+l.areas).selectAll("."+l.area).data(b.lineData.bind(b)),b.mainArea.enter().append("path").attr("class",b.classArea.bind(b)).style("fill",b.color).style("opacity",function(){return b.orgAreaOpacity=+c.select(this).style("opacity"),0}),b.mainArea.style("opacity",b.orgAreaOpacity),b.mainArea.exit().transition().duration(a).style("opacity",0).remove()},i.redrawArea=function(a,b){return[(b?this.mainArea.transition(Math.random().toString()):this.mainArea).attr("d",a).style("fill",this.color).style("opacity",this.orgAreaOpacity)]},i.generateDrawArea=function(a,b){var c=this,d=c.config,e=c.d3.svg.area(),f=c.generateGetAreaPoints(a,b),g=b?c.getSubYScale:c.getYScale,h=function(a){return(b?c.subxx:c.xx).call(c,a)},i=function(a,b){return d.data_groups.length>0?f(a,b)[0][1]:g.call(c,a.id)(c.getAreaBaseValue(a.id))},j=function(a,b){return d.data_groups.length>0?f(a,b)[1][1]:g.call(c,a.id)(a.value)};return e=d.axis_rotated?e.x0(i).x1(j).y(h):e.x(h).y0(d.area_above?0:i).y1(j),d.line_connectNull||(e=e.defined(function(a){return null!==a.value})),function(a){var b,f=d.line_connectNull?c.filterRemoveNull(a.values):a.values,g=0,h=0;return c.isAreaType(a)?(c.isStepType(a)&&(f=c.convertValuesToStep(f)),b=e.interpolate(c.getInterpolate(a))(f)):(f[0]&&(g=c.x(f[0].x),h=c.getYScale(a.id)(f[0].value)),b=d.axis_rotated?"M "+h+" "+g:"M "+g+" "+h),b?b:"M 0 0"}},i.getAreaBaseValue=function(){return 0},i.generateGetAreaPoints=function(a,b){var c=this,d=c.config,e=a.__max__+1,f=c.getShapeX(0,e,a,!!b),g=c.getShapeY(!!b),h=c.getShapeOffset(c.isAreaType,a,!!b),i=b?c.getSubYScale:c.getYScale;return function(a,b){var e=i.call(c,a.id)(0),j=h(a,b)||e,k=f(a),l=g(a);return d.axis_rotated&&(0<a.value&&e>l||a.value<0&&l>e)&&(l=e),[[k,j],[k,l-(e-j)],[k,l-(e-j)],[k,j]]}},i.updateCircle=function(){var a=this;a.mainCircle=a.main.selectAll("."+l.circles).selectAll("."+l.circle).data(a.lineOrScatterData.bind(a)),a.mainCircle.enter().append("circle").attr("class",a.classCircle.bind(a)).attr("r",a.pointR.bind(a)).style("fill",a.color),a.mainCircle.style("opacity",a.initialOpacityForCircle.bind(a)),a.mainCircle.exit().remove()},i.redrawCircle=function(a,b,c){var d=this.main.selectAll("."+l.selectedCircle);return[(c?this.mainCircle.transition(Math.random().toString()):this.mainCircle).style("opacity",this.opacityForCircle.bind(this)).style("fill",this.color).attr("cx",a).attr("cy",b),(c?d.transition(Math.random().toString()):d).attr("cx",a).attr("cy",b)]},i.circleX=function(a){return a.x||0===a.x?this.x(a.x):null},i.updateCircleY=function(){var a,b,c=this;c.config.data_groups.length>0?(a=c.getShapeIndices(c.isLineType),b=c.generateGetLinePoints(a),c.circleY=function(a,c){return b(a,c)[0][1]}):c.circleY=function(a){return c.getYScale(a.id)(a.value)}},i.getCircles=function(a,b){var c=this;return(b?c.main.selectAll("."+l.circles+c.getTargetSelectorSuffix(b)):c.main).selectAll("."+l.circle+(m(a)?"-"+a:""))},i.expandCircles=function(a,b,c){var d=this,e=d.pointExpandedR.bind(d);c&&d.unexpandCircles(),d.getCircles(a,b).classed(l.EXPANDED,!0).attr("r",e)},i.unexpandCircles=function(a){var b=this,c=b.pointR.bind(b);b.getCircles(a).filter(function(){return b.d3.select(this).classed(l.EXPANDED)}).classed(l.EXPANDED,!1).attr("r",c)},i.pointR=function(a){var b=this,c=b.config;return b.isStepType(a)?0:n(c.point_r)?c.point_r(a):c.point_r;
3
- },i.pointExpandedR=function(a){var b=this,c=b.config;return c.point_focus_expand_enabled?c.point_focus_expand_r?c.point_focus_expand_r:1.75*b.pointR(a):b.pointR(a)},i.pointSelectR=function(a){var b=this,c=b.config;return n(c.point_select_r)?c.point_select_r(a):c.point_select_r?c.point_select_r:4*b.pointR(a)},i.isWithinCircle=function(a,b){var c=this.d3,d=c.mouse(a),e=c.select(a),f=+e.attr("cx"),g=+e.attr("cy");return Math.sqrt(Math.pow(f-d[0],2)+Math.pow(g-d[1],2))<b},i.isWithinStep=function(a,b){return Math.abs(b-this.d3.mouse(a)[1])<30},i.initBar=function(){var a=this;a.main.select("."+l.chart).append("g").attr("class",l.chartBars)},i.updateTargetsForBar=function(a){var b,c,d=this,e=d.config,f=d.classChartBar.bind(d),g=d.classBars.bind(d),h=d.classFocus.bind(d);b=d.main.select("."+l.chartBars).selectAll("."+l.chartBar).data(a).attr("class",function(a){return f(a)+h(a)}),c=b.enter().append("g").attr("class",f).style("opacity",0).style("pointer-events","none"),c.append("g").attr("class",g).style("cursor",function(a){return e.data_selection_isselectable(a)?"pointer":null})},i.updateBar=function(a){var b=this,c=b.barData.bind(b),d=b.classBar.bind(b),e=b.initialOpacity.bind(b),f=function(a){return b.color(a.id)};b.mainBar=b.main.selectAll("."+l.bars).selectAll("."+l.bar).data(c),b.mainBar.enter().append("path").attr("class",d).style("stroke",f).style("fill",f),b.mainBar.style("opacity",e),b.mainBar.exit().transition().duration(a).style("opacity",0).remove()},i.redrawBar=function(a,b){return[(b?this.mainBar.transition(Math.random().toString()):this.mainBar).attr("d",a).style("fill",this.color).style("opacity",1)]},i.getBarW=function(a,b){var c=this,d=c.config,e="number"==typeof d.bar_width?d.bar_width:b?a.tickInterval()*d.bar_width_ratio/b:0;return d.bar_width_max&&e>d.bar_width_max?d.bar_width_max:e},i.getBars=function(a,b){var c=this;return(b?c.main.selectAll("."+l.bars+c.getTargetSelectorSuffix(b)):c.main).selectAll("."+l.bar+(m(a)?"-"+a:""))},i.expandBars=function(a,b,c){var d=this;c&&d.unexpandBars(),d.getBars(a,b).classed(l.EXPANDED,!0)},i.unexpandBars=function(a){var b=this;b.getBars(a).classed(l.EXPANDED,!1)},i.generateDrawBar=function(a,b){var c=this,d=c.config,e=c.generateGetBarPoints(a,b);return function(a,b){var c=e(a,b),f=d.axis_rotated?1:0,g=d.axis_rotated?0:1,h="M "+c[0][f]+","+c[0][g]+" L"+c[1][f]+","+c[1][g]+" L"+c[2][f]+","+c[2][g]+" L"+c[3][f]+","+c[3][g]+" z";return h}},i.generateGetBarPoints=function(a,b){var c=this,d=b?c.subXAxis:c.xAxis,e=a.__max__+1,f=c.getBarW(d,e),g=c.getShapeX(f,e,a,!!b),h=c.getShapeY(!!b),i=c.getShapeOffset(c.isBarType,a,!!b),j=b?c.getSubYScale:c.getYScale;return function(a,b){var d=j.call(c,a.id)(0),e=i(a,b)||d,k=g(a),l=h(a);return c.config.axis_rotated&&(0<a.value&&d>l||a.value<0&&l>d)&&(l=d),[[k,e],[k,l-(d-e)],[k+f,l-(d-e)],[k+f,e]]}},i.isWithinBar=function(a){var b=this.d3.mouse(a),c=a.getBoundingClientRect(),d=a.pathSegList.getItem(0),e=a.pathSegList.getItem(1),f=Math.min(d.x,e.x),g=Math.min(d.y,e.y),h=c.width,i=c.height,j=2,k=f-j,l=f+h+j,m=g+i+j,n=g-j;return k<b[0]&&b[0]<l&&n<b[1]&&b[1]<m},i.initText=function(){var a=this;a.main.select("."+l.chart).append("g").attr("class",l.chartTexts),a.mainText=a.d3.selectAll([])},i.updateTargetsForText=function(a){var b,c,d=this,e=d.classChartText.bind(d),f=d.classTexts.bind(d),g=d.classFocus.bind(d);b=d.main.select("."+l.chartTexts).selectAll("."+l.chartText).data(a).attr("class",function(a){return e(a)+g(a)}),c=b.enter().append("g").attr("class",e).style("opacity",0).style("pointer-events","none"),c.append("g").attr("class",f)},i.updateText=function(a){var b=this,c=b.config,d=b.barOrLineData.bind(b),e=b.classText.bind(b);b.mainText=b.main.selectAll("."+l.texts).selectAll("."+l.text).data(d),b.mainText.enter().append("text").attr("class",e).attr("text-anchor",function(a){return c.axis_rotated?a.value<0?"end":"start":"middle"}).style("stroke","none").style("fill",function(a){return b.color(a)}).style("fill-opacity",0),b.mainText.text(function(a,c,d){return b.dataLabelFormat(a.id)(a.value,a.id,c,d)}),b.mainText.exit().transition().duration(a).style("fill-opacity",0).remove()},i.redrawText=function(a,b,c,d){return[(d?this.mainText.transition():this.mainText).attr("x",a).attr("y",b).style("fill",this.color).style("fill-opacity",c?0:this.opacityForText.bind(this))]},i.getTextRect=function(a,b,c){var d,e=this.d3.select("body").append("div").classed("c3",!0),f=e.append("svg").style("visibility","hidden").style("position","fixed").style("top",0).style("left",0),g=this.d3.select(c).style("font");return f.selectAll(".dummy").data([a]).enter().append("text").classed(b?b:"",!0).style("font",g).text(a).each(function(){d=this.getBoundingClientRect()}),e.remove(),d},i.generateXYForText=function(a,b,c,d){var e=this,f=e.generateGetAreaPoints(a,!1),g=e.generateGetBarPoints(b,!1),h=e.generateGetLinePoints(c,!1),i=d?e.getXForText:e.getYForText;return function(a,b){var c=e.isAreaType(a)?f:e.isBarType(a)?g:h;return i.call(e,c(a,b),a,this)}},i.getXForText=function(a,b,c){var d,e,f=this,g=c.getBoundingClientRect();return f.config.axis_rotated?(e=f.isBarType(b)?4:6,d=a[2][1]+e*(b.value<0?-1:1)):d=f.hasType("bar")?(a[2][0]+a[0][0])/2:a[0][0],null===b.value&&(d>f.width?d=f.width-g.width:0>d&&(d=4)),d},i.getYForText=function(a,b,c){var d,e=this,f=c.getBoundingClientRect();return e.config.axis_rotated?d=(a[0][0]+a[2][0]+.6*f.height)/2:(d=a[2][1],b.value<0||0===b.value&&!e.hasPositiveValue?(d+=f.height,e.isBarType(b)&&e.isSafari()?d-=3:!e.isBarType(b)&&e.isChrome()&&(d+=3)):d+=e.isBarType(b)?-3:-6),null!==b.value||e.config.axis_rotated||(d<f.height?d=f.height:d>this.height&&(d=this.height-4)),d},i.setTargetType=function(a,b){var c=this,d=c.config;c.mapToTargetIds(a).forEach(function(a){c.withoutFadeIn[a]=b===d.data_types[a],d.data_types[a]=b}),a||(d.data_type=b)},i.hasType=function(a,b){var c=this,d=c.config.data_types,e=!1;return b=b||c.data.targets,b&&b.length?b.forEach(function(b){var c=d[b.id];(c&&c.indexOf(a)>=0||!c&&"line"===a)&&(e=!0)}):Object.keys(d).length?Object.keys(d).forEach(function(b){d[b]===a&&(e=!0)}):e=c.config.data_type===a,e},i.hasArcType=function(a){return this.hasType("pie",a)||this.hasType("donut",a)||this.hasType("gauge",a)},i.isLineType=function(a){var b=this.config,c=o(a)?a:a.id;return!b.data_types[c]||["line","spline","area","area-spline","step","area-step"].indexOf(b.data_types[c])>=0},i.isStepType=function(a){var b=o(a)?a:a.id;return["step","area-step"].indexOf(this.config.data_types[b])>=0},i.isSplineType=function(a){var b=o(a)?a:a.id;return["spline","area-spline"].indexOf(this.config.data_types[b])>=0},i.isAreaType=function(a){var b=o(a)?a:a.id;return["area","area-spline","area-step"].indexOf(this.config.data_types[b])>=0},i.isBarType=function(a){var b=o(a)?a:a.id;return"bar"===this.config.data_types[b]},i.isScatterType=function(a){var b=o(a)?a:a.id;return"scatter"===this.config.data_types[b]},i.isPieType=function(a){var b=o(a)?a:a.id;return"pie"===this.config.data_types[b]},i.isGaugeType=function(a){var b=o(a)?a:a.id;return"gauge"===this.config.data_types[b]},i.isDonutType=function(a){var b=o(a)?a:a.id;return"donut"===this.config.data_types[b]},i.isArcType=function(a){return this.isPieType(a)||this.isDonutType(a)||this.isGaugeType(a)},i.lineData=function(a){return this.isLineType(a)?[a]:[]},i.arcData=function(a){return this.isArcType(a.data)?[a]:[]},i.barData=function(a){return this.isBarType(a)?a.values:[]},i.lineOrScatterData=function(a){return this.isLineType(a)||this.isScatterType(a)?a.values:[]},i.barOrLineData=function(a){return this.isBarType(a)||this.isLineType(a)?a.values:[]},i.isInterpolationType=function(a){return["linear","linear-closed","basis","basis-open","basis-closed","bundle","cardinal","cardinal-open","cardinal-closed","monotone"].indexOf(a)>=0},i.initGrid=function(){var a=this,b=a.config,c=a.d3;a.grid=a.main.append("g").attr("clip-path",a.clipPathForGrid).attr("class",l.grid),b.grid_x_show&&a.grid.append("g").attr("class",l.xgrids),b.grid_y_show&&a.grid.append("g").attr("class",l.ygrids),b.grid_focus_show&&a.grid.append("g").attr("class",l.xgridFocus).append("line").attr("class",l.xgridFocus),a.xgrid=c.selectAll([]),b.grid_lines_front||a.initGridLines()},i.initGridLines=function(){var a=this,b=a.d3;a.gridLines=a.main.append("g").attr("clip-path",a.clipPathForGrid).attr("class",l.grid+" "+l.gridLines),a.gridLines.append("g").attr("class",l.xgridLines),a.gridLines.append("g").attr("class",l.ygridLines),a.xgridLines=b.selectAll([])},i.updateXGrid=function(a){var b=this,c=b.config,d=b.d3,e=b.generateGridData(c.grid_x_type,b.x),f=b.isCategorized()?b.xAxis.tickOffset():0;b.xgridAttr=c.axis_rotated?{x1:0,x2:b.width,y1:function(a){return b.x(a)-f},y2:function(a){return b.x(a)-f}}:{x1:function(a){return b.x(a)+f},x2:function(a){return b.x(a)+f},y1:0,y2:b.height},b.xgrid=b.main.select("."+l.xgrids).selectAll("."+l.xgrid).data(e),b.xgrid.enter().append("line").attr("class",l.xgrid),a||b.xgrid.attr(b.xgridAttr).style("opacity",function(){return+d.select(this).attr(c.axis_rotated?"y1":"x1")===(c.axis_rotated?b.height:0)?0:1}),b.xgrid.exit().remove()},i.updateYGrid=function(){var a=this,b=a.config,c=a.yAxis.tickValues()||a.y.ticks(b.grid_y_ticks);a.ygrid=a.main.select("."+l.ygrids).selectAll("."+l.ygrid).data(c),a.ygrid.enter().append("line").attr("class",l.ygrid),a.ygrid.attr("x1",b.axis_rotated?a.y:0).attr("x2",b.axis_rotated?a.y:a.width).attr("y1",b.axis_rotated?0:a.y).attr("y2",b.axis_rotated?a.height:a.y),a.ygrid.exit().remove(),a.smoothLines(a.ygrid,"grid")},i.gridTextAnchor=function(a){return a.position?a.position:"end"},i.gridTextDx=function(a){return"start"===a.position?4:"middle"===a.position?0:-4},i.xGridTextX=function(a){return"start"===a.position?-this.height:"middle"===a.position?-this.height/2:0},i.yGridTextX=function(a){return"start"===a.position?0:"middle"===a.position?this.width/2:this.width},i.updateGrid=function(a){var b,c,d,e=this,f=e.main,g=e.config;e.grid.style("visibility",e.hasArcType()?"hidden":"visible"),f.select("line."+l.xgridFocus).style("visibility","hidden"),g.grid_x_show&&e.updateXGrid(),e.xgridLines=f.select("."+l.xgridLines).selectAll("."+l.xgridLine).data(g.grid_x_lines),b=e.xgridLines.enter().append("g").attr("class",function(a){return l.xgridLine+(a["class"]?" "+a["class"]:"")}),b.append("line").style("opacity",0),b.append("text").attr("text-anchor",e.gridTextAnchor).attr("transform",g.axis_rotated?"":"rotate(-90)").attr("dx",e.gridTextDx).attr("dy",-5).style("opacity",0),e.xgridLines.exit().transition().duration(a).style("opacity",0).remove(),g.grid_y_show&&e.updateYGrid(),e.ygridLines=f.select("."+l.ygridLines).selectAll("."+l.ygridLine).data(g.grid_y_lines),c=e.ygridLines.enter().append("g").attr("class",function(a){return l.ygridLine+(a["class"]?" "+a["class"]:"")}),c.append("line").style("opacity",0),c.append("text").attr("text-anchor",e.gridTextAnchor).attr("transform",g.axis_rotated?"rotate(-90)":"").attr("dx",e.gridTextDx).attr("dy",-5).style("opacity",0),d=e.yv.bind(e),e.ygridLines.select("line").transition().duration(a).attr("x1",g.axis_rotated?d:0).attr("x2",g.axis_rotated?d:e.width).attr("y1",g.axis_rotated?0:d).attr("y2",g.axis_rotated?e.height:d).style("opacity",1),e.ygridLines.select("text").transition().duration(a).attr("x",g.axis_rotated?e.xGridTextX.bind(e):e.yGridTextX.bind(e)).attr("y",d).text(function(a){return a.text}).style("opacity",1),e.ygridLines.exit().transition().duration(a).style("opacity",0).remove()},i.redrawGrid=function(a){var b=this,c=b.config,d=b.xv.bind(b),e=b.xgridLines.select("line"),f=b.xgridLines.select("text");return[(a?e.transition():e).attr("x1",c.axis_rotated?0:d).attr("x2",c.axis_rotated?b.width:d).attr("y1",c.axis_rotated?d:0).attr("y2",c.axis_rotated?d:b.height).style("opacity",1),(a?f.transition():f).attr("x",c.axis_rotated?b.yGridTextX.bind(b):b.xGridTextX.bind(b)).attr("y",d).text(function(a){return a.text}).style("opacity",1)]},i.showXGridFocus=function(a){var b=this,c=b.config,d=a.filter(function(a){return a&&m(a.value)}),e=b.main.selectAll("line."+l.xgridFocus),f=b.xx.bind(b);c.tooltip_show&&(b.hasType("scatter")||b.hasArcType()||(e.style("visibility","visible").data([d[0]]).attr(c.axis_rotated?"y1":"x1",f).attr(c.axis_rotated?"y2":"x2",f),b.smoothLines(e,"grid")))},i.hideXGridFocus=function(){this.main.select("line."+l.xgridFocus).style("visibility","hidden")},i.updateXgridFocus=function(){var a=this,b=a.config;a.main.select("line."+l.xgridFocus).attr("x1",b.axis_rotated?0:-10).attr("x2",b.axis_rotated?a.width:-10).attr("y1",b.axis_rotated?-10:0).attr("y2",b.axis_rotated?-10:a.height)},i.generateGridData=function(a,b){var c,d,e,f,g=this,h=[],i=g.main.select("."+l.axisX).selectAll(".tick").size();if("year"===a)for(c=g.getXDomain(),d=c[0].getFullYear(),e=c[1].getFullYear(),f=d;e>=f;f++)h.push(new Date(f+"-01-01 00:00:00"));else h=b.ticks(10),h.length>i&&(h=h.filter(function(a){return(""+a).indexOf(".")<0}));return h},i.getGridFilterToRemove=function(a){return a?function(b){var c=!1;return[].concat(a).forEach(function(a){("value"in a&&b.value===a.value||"class"in a&&b["class"]===a["class"])&&(c=!0)}),c}:function(){return!0}},i.removeGridLines=function(a,b){var c=this,d=c.config,e=c.getGridFilterToRemove(a),f=function(a){return!e(a)},g=b?l.xgridLines:l.ygridLines,h=b?l.xgridLine:l.ygridLine;c.main.select("."+g).selectAll("."+h).filter(e).transition().duration(d.transition_duration).style("opacity",0).remove(),b?d.grid_x_lines=d.grid_x_lines.filter(f):d.grid_y_lines=d.grid_y_lines.filter(f)},i.initTooltip=function(){var a,b=this,c=b.config;if(b.tooltip=b.selectChart.style("position","relative").append("div").attr("class",l.tooltipContainer).style("position","absolute").style("pointer-events","none").style("display","none"),c.tooltip_init_show){if(b.isTimeSeries()&&o(c.tooltip_init_x)){for(c.tooltip_init_x=b.parseDate(c.tooltip_init_x),a=0;a<b.data.targets[0].values.length&&b.data.targets[0].values[a].x-c.tooltip_init_x!==0;a++);c.tooltip_init_x=a}b.tooltip.html(c.tooltip_contents.call(b,b.data.targets.map(function(a){return b.addName(a.values[c.tooltip_init_x])}),b.axis.getXAxisTickFormat(),b.getYFormat(b.hasArcType()),b.color)),b.tooltip.style("top",c.tooltip_init_position.top).style("left",c.tooltip_init_position.left).style("display","block")}},i.getTooltipContent=function(a,b,c,d){var e,f,g,h,i,j,k=this,l=k.config,m=l.tooltip_format_title||b,n=l.tooltip_format_name||function(a){return a},o=l.tooltip_format_value||c,p=k.isOrderAsc();if(0===l.data_groups.length)a.sort(function(a,b){var c=a?a.value:null,d=b?b.value:null;return p?c-d:d-c});else{var q=k.orderTargets(k.data.targets).map(function(a){return a.id});a.sort(function(a,b){var c=a?a.value:null,d=b?b.value:null;return c>0&&d>0&&(c=a?q.indexOf(a.id):null,d=b?q.indexOf(b.id):null),p?c-d:d-c})}for(f=0;f<a.length;f++)if(a[f]&&(a[f].value||0===a[f].value)&&(e||(g=y(m?m(a[f].x):a[f].x),e="<table class='"+k.CLASS.tooltip+"'>"+(g||0===g?"<tr><th colspan='2'>"+g+"</th></tr>":"")),h=y(o(a[f].value,a[f].ratio,a[f].id,a[f].index,a)),void 0!==h)){if(null===a[f].name)continue;i=y(n(a[f].name,a[f].ratio,a[f].id,a[f].index)),j=k.levelColor?k.levelColor(a[f].value):d(a[f].id),e+="<tr class='"+k.CLASS.tooltipName+"-"+k.getTargetSelectorSuffix(a[f].id)+"'>",e+="<td class='name'><span style='background-color:"+j+"'></span>"+i+"</td>",e+="<td class='value'>"+h+"</td>",e+="</tr>"}return e+"</table>"},i.tooltipPosition=function(a,b,c,d){var e,f,g,h,i,j=this,k=j.config,l=j.d3,m=j.hasArcType(),n=l.mouse(d);return m?(f=(j.width-(j.isLegendRight?j.getLegendWidth():0))/2+n[0],h=j.height/2+n[1]+20):(e=j.getSvgLeft(!0),k.axis_rotated?(f=e+n[0]+100,g=f+b,i=j.currentWidth-j.getCurrentPaddingRight(),h=j.x(a[0].x)+20):(f=e+j.getCurrentPaddingLeft(!0)+j.x(a[0].x)+20,g=f+b,i=e+j.currentWidth-j.getCurrentPaddingRight(),h=n[1]+15),g>i&&(f-=g-i+20),h+c>j.currentHeight&&(h-=c+30)),0>h&&(h=0),{top:h,left:f}},i.showTooltip=function(a,b){var c,d,e,f=this,g=f.config,h=f.hasArcType(),j=a.filter(function(a){return a&&m(a.value)}),k=g.tooltip_position||i.tooltipPosition;0!==j.length&&g.tooltip_show&&(f.tooltip.html(g.tooltip_contents.call(f,a,f.axis.getXAxisTickFormat(),f.getYFormat(h),f.color)).style("display","block"),c=f.tooltip.property("offsetWidth"),d=f.tooltip.property("offsetHeight"),e=k.call(this,j,c,d,b),f.tooltip.style("top",e.top+"px").style("left",e.left+"px"))},i.hideTooltip=function(){this.tooltip.style("display","none")},i.initLegend=function(){var a=this;return a.legendItemTextBox={},a.legendHasRendered=!1,a.legend=a.svg.append("g").attr("transform",a.getTranslate("legend")),a.config.legend_show?void a.updateLegendWithDefaults():(a.legend.style("visibility","hidden"),void(a.hiddenLegendIds=a.mapToIds(a.data.targets)))},i.updateLegendWithDefaults=function(){var a=this;a.updateLegend(a.mapToIds(a.data.targets),{withTransform:!1,withTransitionForTransform:!1,withTransition:!1})},i.updateSizeForLegend=function(a,b){var c=this,d=c.config,e={top:c.isLegendTop?c.getCurrentPaddingTop()+d.legend_inset_y+5.5:c.currentHeight-a-c.getCurrentPaddingBottom()-d.legend_inset_y,left:c.isLegendLeft?c.getCurrentPaddingLeft()+d.legend_inset_x+.5:c.currentWidth-b-c.getCurrentPaddingRight()-d.legend_inset_x+.5};c.margin3={top:c.isLegendRight?0:c.isLegendInset?e.top:c.currentHeight-a,right:NaN,bottom:0,left:c.isLegendRight?c.currentWidth-b:c.isLegendInset?e.left:0}},i.transformLegend=function(a){var b=this;(a?b.legend.transition():b.legend).attr("transform",b.getTranslate("legend"))},i.updateLegendStep=function(a){this.legendStep=a},i.updateLegendItemWidth=function(a){this.legendItemWidth=a},i.updateLegendItemHeight=function(a){this.legendItemHeight=a},i.getLegendWidth=function(){var a=this;return a.config.legend_show?a.isLegendRight||a.isLegendInset?a.legendItemWidth*(a.legendStep+1):a.currentWidth:0},i.getLegendHeight=function(){var a=this,b=0;return a.config.legend_show&&(b=a.isLegendRight?a.currentHeight:Math.max(20,a.legendItemHeight)*(a.legendStep+1)),b},i.opacityForLegend=function(a){return a.classed(l.legendItemHidden)?null:1},i.opacityForUnfocusedLegend=function(a){return a.classed(l.legendItemHidden)?null:.3},i.toggleFocusLegend=function(a,b){var c=this;a=c.mapToTargetIds(a),c.legend.selectAll("."+l.legendItem).filter(function(b){return a.indexOf(b)>=0}).classed(l.legendItemFocused,b).transition().duration(100).style("opacity",function(){var a=b?c.opacityForLegend:c.opacityForUnfocusedLegend;return a.call(c,c.d3.select(this))})},i.revertLegend=function(){var a=this,b=a.d3;a.legend.selectAll("."+l.legendItem).classed(l.legendItemFocused,!1).transition().duration(100).style("opacity",function(){return a.opacityForLegend(b.select(this))})},i.showLegend=function(a){var b=this,c=b.config;c.legend_show||(c.legend_show=!0,b.legend.style("visibility","visible"),b.legendHasRendered||b.updateLegendWithDefaults()),b.removeHiddenLegendIds(a),b.legend.selectAll(b.selectorLegends(a)).style("visibility","visible").transition().style("opacity",function(){return b.opacityForLegend(b.d3.select(this))})},i.hideLegend=function(a){var b=this,c=b.config;c.legend_show&&u(a)&&(c.legend_show=!1,b.legend.style("visibility","hidden")),b.addHiddenLegendIds(a),b.legend.selectAll(b.selectorLegends(a)).style("opacity",0).style("visibility","hidden")},i.clearLegendItemTextBoxCache=function(){this.legendItemTextBox={}},i.updateLegend=function(a,b,c){function d(a,b){return y.legendItemTextBox[b]||(y.legendItemTextBox[b]=y.getTextRect(a.textContent,l.legendItem,a)),y.legendItemTextBox[b]}function e(b,c,e){function f(a,b){b||(g=(o-G-n)/2,E>g&&(g=(o-n)/2,G=0,M++)),L[a]=M,K[M]=y.isLegendInset?10:g,H[a]=G,G+=n}var g,h,i=0===e,j=e===a.length-1,k=d(b,c),l=k.width+F+(!j||y.isLegendRight||y.isLegendInset?B:0)+z.legend_padding,m=k.height+A,n=y.isLegendRight||y.isLegendInset?m:l,o=y.isLegendRight||y.isLegendInset?y.getLegendHeight():y.getLegendWidth();return i&&(G=0,M=0,C=0,D=0),z.legend_show&&!y.isLegendToShow(c)?void(I[c]=J[c]=L[c]=H[c]=0):(I[c]=l,J[c]=m,(!C||l>=C)&&(C=l),(!D||m>=D)&&(D=m),h=y.isLegendRight||y.isLegendInset?D:C,void(z.legend_equally?(Object.keys(I).forEach(function(a){I[a]=C}),Object.keys(J).forEach(function(a){J[a]=D}),g=(o-h*a.length)/2,E>g?(G=0,M=0,a.forEach(function(a){f(a)})):f(c,!0)):f(c)))}var f,g,h,i,j,k,m,n,o,p,r,s,t,u,v,x,y=this,z=y.config,A=4,B=10,C=0,D=0,E=10,F=z.legend_item_tile_width+5,G=0,H={},I={},J={},K=[0],L={},M=0;a=a.filter(function(a){return!q(z.data_names[a])||null!==z.data_names[a]}),b=b||{},r=w(b,"withTransition",!0),s=w(b,"withTransitionForTransform",!0),y.isLegendInset&&(M=z.legend_inset_step?z.legend_inset_step:a.length,y.updateLegendStep(M)),y.isLegendRight?(f=function(a){return C*L[a]},i=function(a){return K[L[a]]+H[a]}):y.isLegendInset?(f=function(a){return C*L[a]+10},i=function(a){return K[L[a]]+H[a]}):(f=function(a){return K[L[a]]+H[a]},i=function(a){return D*L[a]}),g=function(a,b){return f(a,b)+4+z.legend_item_tile_width},j=function(a,b){return i(a,b)+9},h=function(a,b){return f(a,b)},k=function(a,b){return i(a,b)-5},m=function(a,b){return f(a,b)-2},n=function(a,b){return f(a,b)-2+z.legend_item_tile_width},o=function(a,b){return i(a,b)+4},p=y.legend.selectAll("."+l.legendItem).data(a).enter().append("g").attr("class",function(a){return y.generateClass(l.legendItem,a)}).style("visibility",function(a){return y.isLegendToShow(a)?"visible":"hidden"}).style("cursor","pointer").on("click",function(a){z.legend_item_onclick?z.legend_item_onclick.call(y,a):y.d3.event.altKey?(y.api.hide(),y.api.show(a)):(y.api.toggle(a),y.isTargetToShow(a)?y.api.focus(a):y.api.revert())}).on("mouseover",function(a){z.legend_item_onmouseover?z.legend_item_onmouseover.call(y,a):(y.d3.select(this).classed(l.legendItemFocused,!0),!y.transiting&&y.isTargetToShow(a)&&y.api.focus(a))}).on("mouseout",function(a){z.legend_item_onmouseout?z.legend_item_onmouseout.call(y,a):(y.d3.select(this).classed(l.legendItemFocused,!1),y.api.revert())}),p.append("text").text(function(a){return q(z.data_names[a])?z.data_names[a]:a}).each(function(a,b){e(this,a,b)}).style("pointer-events","none").attr("x",y.isLegendRight||y.isLegendInset?g:-200).attr("y",y.isLegendRight||y.isLegendInset?-200:j),p.append("rect").attr("class",l.legendItemEvent).style("fill-opacity",0).attr("x",y.isLegendRight||y.isLegendInset?h:-200).attr("y",y.isLegendRight||y.isLegendInset?-200:k),p.append("line").attr("class",l.legendItemTile).style("stroke",y.color).style("pointer-events","none").attr("x1",y.isLegendRight||y.isLegendInset?m:-200).attr("y1",y.isLegendRight||y.isLegendInset?-200:o).attr("x2",y.isLegendRight||y.isLegendInset?n:-200).attr("y2",y.isLegendRight||y.isLegendInset?-200:o).attr("stroke-width",z.legend_item_tile_height),x=y.legend.select("."+l.legendBackground+" rect"),y.isLegendInset&&C>0&&0===x.size()&&(x=y.legend.insert("g","."+l.legendItem).attr("class",l.legendBackground).append("rect")),t=y.legend.selectAll("text").data(a).text(function(a){return q(z.data_names[a])?z.data_names[a]:a}).each(function(a,b){e(this,a,b)}),(r?t.transition():t).attr("x",g).attr("y",j),u=y.legend.selectAll("rect."+l.legendItemEvent).data(a),(r?u.transition():u).attr("width",function(a){return I[a]}).attr("height",function(a){return J[a]}).attr("x",h).attr("y",k),v=y.legend.selectAll("line."+l.legendItemTile).data(a),(r?v.transition():v).style("stroke",y.color).attr("x1",m).attr("y1",o).attr("x2",n).attr("y2",o),x&&(r?x.transition():x).attr("height",y.getLegendHeight()-12).attr("width",C*(M+1)+10),y.legend.selectAll("."+l.legendItem).classed(l.legendItemHidden,function(a){return!y.isTargetToShow(a)}),y.updateLegendItemWidth(C),y.updateLegendItemHeight(D),y.updateLegendStep(M),y.updateSizes(),y.updateScales(),y.updateSvgSize(),y.transformAll(s,c),y.legendHasRendered=!0},i.initTitle=function(){var a=this;a.title=a.svg.append("text").text(a.config.title_text).attr("class",a.CLASS.title)},i.redrawTitle=function(){var a=this;a.title.attr("x",a.xForTitle.bind(a)).attr("y",a.yForTitle.bind(a))},i.xForTitle=function(){var a,b=this,c=b.config,d=c.title_position||"left";return a=d.indexOf("right")>=0?b.currentWidth-b.getTextRect(b.title.node().textContent,b.CLASS.title,b.title.node()).width-c.title_padding.right:d.indexOf("center")>=0?(b.currentWidth-b.getTextRect(b.title.node().textContent,b.CLASS.title,b.title.node()).width)/2:c.title_padding.left},i.yForTitle=function(){var a=this;return a.config.title_padding.top+a.getTextRect(a.title.node().textContent,a.CLASS.title,a.title.node()).height},i.getTitlePadding=function(){var a=this;return a.yForTitle()+a.config.title_padding.bottom},c(b,f),f.prototype.init=function(){var a=this.owner,b=a.config,c=a.main;a.axes.x=c.append("g").attr("class",l.axis+" "+l.axisX).attr("clip-path",a.clipPathForXAxis).attr("transform",a.getTranslate("x")).style("visibility",b.axis_x_show?"visible":"hidden"),a.axes.x.append("text").attr("class",l.axisXLabel).attr("transform",b.axis_rotated?"rotate(-90)":"").style("text-anchor",this.textAnchorForXAxisLabel.bind(this)),a.axes.y=c.append("g").attr("class",l.axis+" "+l.axisY).attr("clip-path",b.axis_y_inner?"":a.clipPathForYAxis).attr("transform",a.getTranslate("y")).style("visibility",b.axis_y_show?"visible":"hidden"),a.axes.y.append("text").attr("class",l.axisYLabel).attr("transform",b.axis_rotated?"":"rotate(-90)").style("text-anchor",this.textAnchorForYAxisLabel.bind(this)),a.axes.y2=c.append("g").attr("class",l.axis+" "+l.axisY2).attr("transform",a.getTranslate("y2")).style("visibility",b.axis_y2_show?"visible":"hidden"),a.axes.y2.append("text").attr("class",l.axisY2Label).attr("transform",b.axis_rotated?"":"rotate(-90)").style("text-anchor",this.textAnchorForY2AxisLabel.bind(this))},f.prototype.getXAxis=function(a,b,c,d,e,f,h){var i=this.owner,j=i.config,k={isCategory:i.isCategorized(),withOuterTick:e,tickMultiline:j.axis_x_tick_multiline,tickWidth:j.axis_x_tick_width,tickTextRotate:h?0:j.axis_x_tick_rotate,withoutTransition:f},l=g(i.d3,k).scale(a).orient(b);return i.isTimeSeries()&&d&&"function"!=typeof d&&(d=d.map(function(a){return i.parseDate(a)})),l.tickFormat(c).tickValues(d),i.isCategorized()&&(l.tickCentered(j.axis_x_tick_centered),u(j.axis_x_tick_culling)&&(j.axis_x_tick_culling=!1)),l},f.prototype.updateXAxisTickValues=function(a,b){var c,d=this.owner,e=d.config;return(e.axis_x_tick_fit||e.axis_x_tick_count)&&(c=this.generateTickValues(d.mapTargetsToUniqueXs(a),e.axis_x_tick_count,d.isTimeSeries())),b?b.tickValues(c):(d.xAxis.tickValues(c),d.subXAxis.tickValues(c)),c},f.prototype.getYAxis=function(a,b,c,d,e,f,h){var i=this.owner,j=i.config,k={withOuterTick:e,withoutTransition:f,tickTextRotate:h?0:j.axis_y_tick_rotate},l=g(i.d3,k).scale(a).orient(b).tickFormat(c);return i.isTimeSeriesY()?l.ticks(i.d3.time[j.axis_y_tick_time_value],j.axis_y_tick_time_interval):l.tickValues(d),l},f.prototype.getId=function(a){var b=this.owner.config;return a in b.data_axes?b.data_axes[a]:"y"},f.prototype.getXAxisTickFormat=function(){var a=this.owner,b=a.config,c=a.isTimeSeries()?a.defaultAxisTimeFormat:a.isCategorized()?a.categoryName:function(a){return 0>a?a.toFixed(0):a};return b.axis_x_tick_format&&(n(b.axis_x_tick_format)?c=b.axis_x_tick_format:a.isTimeSeries()&&(c=function(c){return c?a.axisTimeFormat(b.axis_x_tick_format)(c):""})),n(c)?function(b){return c.call(a,b)}:c},f.prototype.getTickValues=function(a,b){return a?a:b?b.tickValues():void 0},f.prototype.getXAxisTickValues=function(){return this.getTickValues(this.owner.config.axis_x_tick_values,this.owner.xAxis)},f.prototype.getYAxisTickValues=function(){return this.getTickValues(this.owner.config.axis_y_tick_values,this.owner.yAxis)},f.prototype.getY2AxisTickValues=function(){return this.getTickValues(this.owner.config.axis_y2_tick_values,this.owner.y2Axis)},f.prototype.getLabelOptionByAxisId=function(a){var b,c=this.owner,d=c.config;return"y"===a?b=d.axis_y_label:"y2"===a?b=d.axis_y2_label:"x"===a&&(b=d.axis_x_label),b},f.prototype.getLabelText=function(a){var b=this.getLabelOptionByAxisId(a);return o(b)?b:b?b.text:null},f.prototype.setLabelText=function(a,b){var c=this.owner,d=c.config,e=this.getLabelOptionByAxisId(a);o(e)?"y"===a?d.axis_y_label=b:"y2"===a?d.axis_y2_label=b:"x"===a&&(d.axis_x_label=b):e&&(e.text=b)},f.prototype.getLabelPosition=function(a,b){var c=this.getLabelOptionByAxisId(a),d=c&&"object"==typeof c&&c.position?c.position:b;return{isInner:d.indexOf("inner")>=0,isOuter:d.indexOf("outer")>=0,isLeft:d.indexOf("left")>=0,isCenter:d.indexOf("center")>=0,isRight:d.indexOf("right")>=0,isTop:d.indexOf("top")>=0,isMiddle:d.indexOf("middle")>=0,isBottom:d.indexOf("bottom")>=0}},f.prototype.getXAxisLabelPosition=function(){return this.getLabelPosition("x",this.owner.config.axis_rotated?"inner-top":"inner-right")},f.prototype.getYAxisLabelPosition=function(){return this.getLabelPosition("y",this.owner.config.axis_rotated?"inner-right":"inner-top")},f.prototype.getY2AxisLabelPosition=function(){return this.getLabelPosition("y2",this.owner.config.axis_rotated?"inner-right":"inner-top")},f.prototype.getLabelPositionById=function(a){return"y2"===a?this.getY2AxisLabelPosition():"y"===a?this.getYAxisLabelPosition():this.getXAxisLabelPosition()},f.prototype.textForXAxisLabel=function(){return this.getLabelText("x")},f.prototype.textForYAxisLabel=function(){return this.getLabelText("y")},f.prototype.textForY2AxisLabel=function(){return this.getLabelText("y2")},f.prototype.xForAxisLabel=function(a,b){var c=this.owner;return a?b.isLeft?0:b.isCenter?c.width/2:c.width:b.isBottom?-c.height:b.isMiddle?-c.height/2:0},f.prototype.dxForAxisLabel=function(a,b){return a?b.isLeft?"0.5em":b.isRight?"-0.5em":"0":b.isTop?"-0.5em":b.isBottom?"0.5em":"0"},f.prototype.textAnchorForAxisLabel=function(a,b){return a?b.isLeft?"start":b.isCenter?"middle":"end":b.isBottom?"start":b.isMiddle?"middle":"end"},f.prototype.xForXAxisLabel=function(){return this.xForAxisLabel(!this.owner.config.axis_rotated,this.getXAxisLabelPosition())},f.prototype.xForYAxisLabel=function(){return this.xForAxisLabel(this.owner.config.axis_rotated,this.getYAxisLabelPosition())},f.prototype.xForY2AxisLabel=function(){return this.xForAxisLabel(this.owner.config.axis_rotated,this.getY2AxisLabelPosition())},f.prototype.dxForXAxisLabel=function(){return this.dxForAxisLabel(!this.owner.config.axis_rotated,this.getXAxisLabelPosition())},f.prototype.dxForYAxisLabel=function(){return this.dxForAxisLabel(this.owner.config.axis_rotated,this.getYAxisLabelPosition())},f.prototype.dxForY2AxisLabel=function(){return this.dxForAxisLabel(this.owner.config.axis_rotated,this.getY2AxisLabelPosition())},f.prototype.dyForXAxisLabel=function(){var a=this.owner,b=a.config,c=this.getXAxisLabelPosition();return b.axis_rotated?c.isInner?"1.2em":-25-this.getMaxTickWidth("x"):c.isInner?"-0.5em":b.axis_x_height?b.axis_x_height-10:"3em"},f.prototype.dyForYAxisLabel=function(){var a=this.owner,b=this.getYAxisLabelPosition();return a.config.axis_rotated?b.isInner?"-0.5em":"3em":b.isInner?"1.2em":-10-(a.config.axis_y_inner?0:this.getMaxTickWidth("y")+10)},f.prototype.dyForY2AxisLabel=function(){var a=this.owner,b=this.getY2AxisLabelPosition();return a.config.axis_rotated?b.isInner?"1.2em":"-2.2em":b.isInner?"-0.5em":15+(a.config.axis_y2_inner?0:this.getMaxTickWidth("y2")+15)},f.prototype.textAnchorForXAxisLabel=function(){var a=this.owner;return this.textAnchorForAxisLabel(!a.config.axis_rotated,this.getXAxisLabelPosition())},f.prototype.textAnchorForYAxisLabel=function(){var a=this.owner;return this.textAnchorForAxisLabel(a.config.axis_rotated,this.getYAxisLabelPosition())},f.prototype.textAnchorForY2AxisLabel=function(){var a=this.owner;return this.textAnchorForAxisLabel(a.config.axis_rotated,this.getY2AxisLabelPosition())},f.prototype.getMaxTickWidth=function(a,b){var c,d,e,f,g,h=this.owner,i=h.config,j=0;return b&&h.currentMaxTickWidths[a]?h.currentMaxTickWidths[a]:(h.svg&&(c=h.filterTargetsToShow(h.data.targets),"y"===a?(d=h.y.copy().domain(h.getYDomain(c,"y")),e=this.getYAxis(d,h.yOrient,i.axis_y_tick_format,h.yAxisTickValues,!1,!0,!0)):"y2"===a?(d=h.y2.copy().domain(h.getYDomain(c,"y2")),
4
- e=this.getYAxis(d,h.y2Orient,i.axis_y2_tick_format,h.y2AxisTickValues,!1,!0,!0)):(d=h.x.copy().domain(h.getXDomain(c)),e=this.getXAxis(d,h.xOrient,h.xAxisTickFormat,h.xAxisTickValues,!1,!0,!0),this.updateXAxisTickValues(c,e)),f=h.d3.select("body").append("div").classed("c3",!0),g=f.append("svg").style("visibility","hidden").style("position","fixed").style("top",0).style("left",0),g.append("g").call(e).each(function(){h.d3.select(this).selectAll("text").each(function(){var a=this.getBoundingClientRect();j<a.width&&(j=a.width)}),f.remove()})),h.currentMaxTickWidths[a]=0>=j?h.currentMaxTickWidths[a]:j,h.currentMaxTickWidths[a])},f.prototype.updateLabels=function(a){var b=this.owner,c=b.main.select("."+l.axisX+" ."+l.axisXLabel),d=b.main.select("."+l.axisY+" ."+l.axisYLabel),e=b.main.select("."+l.axisY2+" ."+l.axisY2Label);(a?c.transition():c).attr("x",this.xForXAxisLabel.bind(this)).attr("dx",this.dxForXAxisLabel.bind(this)).attr("dy",this.dyForXAxisLabel.bind(this)).text(this.textForXAxisLabel.bind(this)),(a?d.transition():d).attr("x",this.xForYAxisLabel.bind(this)).attr("dx",this.dxForYAxisLabel.bind(this)).attr("dy",this.dyForYAxisLabel.bind(this)).text(this.textForYAxisLabel.bind(this)),(a?e.transition():e).attr("x",this.xForY2AxisLabel.bind(this)).attr("dx",this.dxForY2AxisLabel.bind(this)).attr("dy",this.dyForY2AxisLabel.bind(this)).text(this.textForY2AxisLabel.bind(this))},f.prototype.getPadding=function(a,b,c,d){var e="number"==typeof a?a:a[b];return m(e)?"ratio"===a.unit?a[b]*d:this.convertPixelsToAxisPadding(e,d):c},f.prototype.convertPixelsToAxisPadding=function(a,b){var c=this.owner,d=c.config.axis_rotated?c.width:c.height;return b*(a/d)},f.prototype.generateTickValues=function(a,b,c){var d,e,f,g,h,i,j,k=a;if(b)if(d=n(b)?b():b,1===d)k=[a[0]];else if(2===d)k=[a[0],a[a.length-1]];else if(d>2){for(g=d-2,e=a[0],f=a[a.length-1],h=(f-e)/(g+1),k=[e],i=0;g>i;i++)j=+e+h*(i+1),k.push(c?new Date(j):j);k.push(f)}return c||(k=k.sort(function(a,b){return a-b})),k},f.prototype.generateTransitions=function(a){var b=this.owner,c=b.axes;return{axisX:a?c.x.transition().duration(a):c.x,axisY:a?c.y.transition().duration(a):c.y,axisY2:a?c.y2.transition().duration(a):c.y2,axisSubX:a?c.subx.transition().duration(a):c.subx}},f.prototype.redraw=function(a,b){var c=this.owner;c.axes.x.style("opacity",b?0:1),c.axes.y.style("opacity",b?0:1),c.axes.y2.style("opacity",b?0:1),c.axes.subx.style("opacity",b?0:1),a.axisX.call(c.xAxis),a.axisY.call(c.yAxis),a.axisY2.call(c.y2Axis),a.axisSubX.call(c.subXAxis)},i.getClipPath=function(b){var c=a.navigator.appVersion.toLowerCase().indexOf("msie 9.")>=0;return"url("+(c?"":document.URL.split("#")[0])+"#"+b+")"},i.appendClip=function(a,b){return a.append("clipPath").attr("id",b).append("rect")},i.getAxisClipX=function(a){var b=Math.max(30,this.margin.left);return a?-(1+b):-(b-1)},i.getAxisClipY=function(a){return a?-20:-this.margin.top},i.getXAxisClipX=function(){var a=this;return a.getAxisClipX(!a.config.axis_rotated)},i.getXAxisClipY=function(){var a=this;return a.getAxisClipY(!a.config.axis_rotated)},i.getYAxisClipX=function(){var a=this;return a.config.axis_y_inner?-1:a.getAxisClipX(a.config.axis_rotated)},i.getYAxisClipY=function(){var a=this;return a.getAxisClipY(a.config.axis_rotated)},i.getAxisClipWidth=function(a){var b=this,c=Math.max(30,b.margin.left),d=Math.max(30,b.margin.right);return a?b.width+2+c+d:b.margin.left+20},i.getAxisClipHeight=function(a){return(a?this.margin.bottom:this.margin.top+this.height)+20},i.getXAxisClipWidth=function(){var a=this;return a.getAxisClipWidth(!a.config.axis_rotated)},i.getXAxisClipHeight=function(){var a=this;return a.getAxisClipHeight(!a.config.axis_rotated)},i.getYAxisClipWidth=function(){var a=this;return a.getAxisClipWidth(a.config.axis_rotated)+(a.config.axis_y_inner?20:0)},i.getYAxisClipHeight=function(){var a=this;return a.getAxisClipHeight(a.config.axis_rotated)},i.initPie=function(){var a=this,b=a.d3,c=a.config;a.pie=b.layout.pie().value(function(a){return a.values.reduce(function(a,b){return a+b.value},0)}),c.data_order||a.pie.sort(null)},i.updateRadius=function(){var a=this,b=a.config,c=b.gauge_width||b.donut_width;a.radiusExpanded=Math.min(a.arcWidth,a.arcHeight)/2,a.radius=.95*a.radiusExpanded,a.innerRadiusRatio=c?(a.radius-c)/a.radius:.6,a.innerRadius=a.hasType("donut")||a.hasType("gauge")?a.radius*a.innerRadiusRatio:0},i.updateArc=function(){var a=this;a.svgArc=a.getSvgArc(),a.svgArcExpanded=a.getSvgArcExpanded(),a.svgArcExpandedSub=a.getSvgArcExpanded(.98)},i.updateAngle=function(a){var b,c,d,e,f=this,g=f.config,h=!1,i=0;return g?(f.pie(f.filterTargetsToShow(f.data.targets)).forEach(function(b){h||b.data.id!==a.data.id||(h=!0,a=b,a.index=i),i++}),isNaN(a.startAngle)&&(a.startAngle=0),isNaN(a.endAngle)&&(a.endAngle=a.startAngle),f.isGaugeType(a.data)&&(b=g.gauge_min,c=g.gauge_max,d=Math.PI*(g.gauge_fullCircle?2:1)/(c-b),e=a.value<b?0:a.value<c?a.value-b:c-b,a.startAngle=g.gauge_startingAngle,a.endAngle=a.startAngle+d*e),h?a:null):null},i.getSvgArc=function(){var a=this,b=a.d3.svg.arc().outerRadius(a.radius).innerRadius(a.innerRadius),c=function(c,d){var e;return d?b(c):(e=a.updateAngle(c),e?b(e):"M 0 0")};return c.centroid=b.centroid,c},i.getSvgArcExpanded=function(a){var b=this,c=b.d3.svg.arc().outerRadius(b.radiusExpanded*(a?a:1)).innerRadius(b.innerRadius);return function(a){var d=b.updateAngle(a);return d?c(d):"M 0 0"}},i.getArc=function(a,b,c){return c||this.isArcType(a.data)?this.svgArc(a,b):"M 0 0"},i.transformForArcLabel=function(a){var b,c,d,e,f,g=this,h=g.config,i=g.updateAngle(a),j="";return i&&!g.hasType("gauge")&&(b=this.svgArc.centroid(i),c=isNaN(b[0])?0:b[0],d=isNaN(b[1])?0:b[1],e=Math.sqrt(c*c+d*d),f=g.hasType("donut")&&h.donut_label_ratio?n(h.donut_label_ratio)?h.donut_label_ratio(a,g.radius,e):h.donut_label_ratio:g.hasType("pie")&&h.pie_label_ratio?n(h.pie_label_ratio)?h.pie_label_ratio(a,g.radius,e):h.pie_label_ratio:g.radius&&e?(36/g.radius>.375?1.175-36/g.radius:.8)*g.radius/e:0,j="translate("+c*f+","+d*f+")"),j},i.getArcRatio=function(a){var b=this,c=b.config,d=Math.PI*(b.hasType("gauge")&&!c.gauge_fullCircle?1:2);return a?(a.endAngle-a.startAngle)/d:null},i.convertToArcData=function(a){return this.addName({id:a.data.id,value:a.value,ratio:this.getArcRatio(a),index:a.index})},i.textForArcLabel=function(a){var b,c,d,e,f,g=this;return g.shouldShowArcLabel()?(b=g.updateAngle(a),c=b?b.value:null,d=g.getArcRatio(b),e=a.data.id,g.hasType("gauge")||g.meetsArcLabelThreshold(d)?(f=g.getArcLabelFormat(),f?f(c,d,e):g.defaultArcValueFormat(c,d)):""):""},i.expandArc=function(b){var c,d=this;return d.transiting?void(c=a.setInterval(function(){d.transiting||(a.clearInterval(c),d.legend.selectAll(".c3-legend-item-focused").size()>0&&d.expandArc(b))},10)):(b=d.mapToTargetIds(b),void d.svg.selectAll(d.selectorTargets(b,"."+l.chartArc)).each(function(a){d.shouldExpand(a.data.id)&&d.d3.select(this).selectAll("path").transition().duration(d.expandDuration(a.data.id)).attr("d",d.svgArcExpanded).transition().duration(2*d.expandDuration(a.data.id)).attr("d",d.svgArcExpandedSub).each(function(a){d.isDonutType(a.data)})}))},i.unexpandArc=function(a){var b=this;b.transiting||(a=b.mapToTargetIds(a),b.svg.selectAll(b.selectorTargets(a,"."+l.chartArc)).selectAll("path").transition().duration(function(a){return b.expandDuration(a.data.id)}).attr("d",b.svgArc),b.svg.selectAll("."+l.arc).style("opacity",1))},i.expandDuration=function(a){var b=this,c=b.config;return b.isDonutType(a)?c.donut_expand_duration:b.isGaugeType(a)?c.gauge_expand_duration:b.isPieType(a)?c.pie_expand_duration:50},i.shouldExpand=function(a){var b=this,c=b.config;return b.isDonutType(a)&&c.donut_expand||b.isGaugeType(a)&&c.gauge_expand||b.isPieType(a)&&c.pie_expand},i.shouldShowArcLabel=function(){var a=this,b=a.config,c=!0;return a.hasType("donut")?c=b.donut_label_show:a.hasType("pie")&&(c=b.pie_label_show),c},i.meetsArcLabelThreshold=function(a){var b=this,c=b.config,d=b.hasType("donut")?c.donut_label_threshold:c.pie_label_threshold;return a>=d},i.getArcLabelFormat=function(){var a=this,b=a.config,c=b.pie_label_format;return a.hasType("gauge")?c=b.gauge_label_format:a.hasType("donut")&&(c=b.donut_label_format),c},i.getArcTitle=function(){var a=this;return a.hasType("donut")?a.config.donut_title:""},i.updateTargetsForArc=function(a){var b,c,d=this,e=d.main,f=d.classChartArc.bind(d),g=d.classArcs.bind(d),h=d.classFocus.bind(d);b=e.select("."+l.chartArcs).selectAll("."+l.chartArc).data(d.pie(a)).attr("class",function(a){return f(a)+h(a.data)}),c=b.enter().append("g").attr("class",f),c.append("g").attr("class",g),c.append("text").attr("dy",d.hasType("gauge")?"-.1em":".35em").style("opacity",0).style("text-anchor","middle").style("pointer-events","none")},i.initArc=function(){var a=this;a.arcs=a.main.select("."+l.chart).append("g").attr("class",l.chartArcs).attr("transform",a.getTranslate("arc")),a.arcs.append("text").attr("class",l.chartArcsTitle).style("text-anchor","middle").text(a.getArcTitle())},i.redrawArc=function(a,b,c){var d,e=this,f=e.d3,g=e.config,h=e.main;d=h.selectAll("."+l.arcs).selectAll("."+l.arc).data(e.arcData.bind(e)),d.enter().append("path").attr("class",e.classArc.bind(e)).style("fill",function(a){return e.color(a.data)}).style("cursor",function(a){return g.interaction_enabled&&g.data_selection_isselectable(a)?"pointer":null}).style("opacity",0).each(function(a){e.isGaugeType(a.data)&&(a.startAngle=a.endAngle=g.gauge_startingAngle),this._current=a}),d.attr("transform",function(a){return!e.isGaugeType(a.data)&&c?"scale(0)":""}).style("opacity",function(a){return a===this._current?0:1}).on("mouseover",g.interaction_enabled?function(a){var b,c;e.transiting||(b=e.updateAngle(a),b&&(c=e.convertToArcData(b),e.expandArc(b.data.id),e.api.focus(b.data.id),e.toggleFocusLegend(b.data.id,!0),e.config.data_onmouseover(c,this)))}:null).on("mousemove",g.interaction_enabled?function(a){var b,c,d=e.updateAngle(a);d&&(b=e.convertToArcData(d),c=[b],e.showTooltip(c,this))}:null).on("mouseout",g.interaction_enabled?function(a){var b,c;e.transiting||(b=e.updateAngle(a),b&&(c=e.convertToArcData(b),e.unexpandArc(b.data.id),e.api.revert(),e.revertLegend(),e.hideTooltip(),e.config.data_onmouseout(c,this)))}:null).on("click",g.interaction_enabled?function(a,b){var c,d=e.updateAngle(a);d&&(c=e.convertToArcData(d),e.toggleShape&&e.toggleShape(this,c,b),e.config.data_onclick.call(e.api,c,this))}:null).each(function(){e.transiting=!0}).transition().duration(a).attrTween("d",function(a){var b,c=e.updateAngle(a);return c?(isNaN(this._current.startAngle)&&(this._current.startAngle=0),isNaN(this._current.endAngle)&&(this._current.endAngle=this._current.startAngle),b=f.interpolate(this._current,c),this._current=b(0),function(c){var d=b(c);return d.data=a.data,e.getArc(d,!0)}):function(){return"M 0 0"}}).attr("transform",c?"scale(1)":"").style("fill",function(a){return e.levelColor?e.levelColor(a.data.values[0].value):e.color(a.data.id)}).style("opacity",1).call(e.endall,function(){e.transiting=!1}),d.exit().transition().duration(b).style("opacity",0).remove(),h.selectAll("."+l.chartArc).select("text").style("opacity",0).attr("class",function(a){return e.isGaugeType(a.data)?l.gaugeValue:""}).text(e.textForArcLabel.bind(e)).attr("transform",e.transformForArcLabel.bind(e)).style("font-size",function(a){return e.isGaugeType(a.data)?Math.round(e.radius/5)+"px":""}).transition().duration(a).style("opacity",function(a){return e.isTargetToShow(a.data.id)&&e.isArcType(a.data)?1:0}),h.select("."+l.chartArcsTitle).style("opacity",e.hasType("donut")||e.hasType("gauge")?1:0),e.hasType("gauge")&&(e.arcs.select("."+l.chartArcsBackground).attr("d",function(){var a={data:[{value:g.gauge_max}],startAngle:g.gauge_startingAngle,endAngle:-1*g.gauge_startingAngle};return e.getArc(a,!0,!0)}),e.arcs.select("."+l.chartArcsGaugeUnit).attr("dy",".75em").text(g.gauge_label_show?g.gauge_units:""),e.arcs.select("."+l.chartArcsGaugeMin).attr("dx",-1*(e.innerRadius+(e.radius-e.innerRadius)/(g.gauge_fullCircle?1:2))+"px").attr("dy","1.2em").text(g.gauge_label_show?g.gauge_min:""),e.arcs.select("."+l.chartArcsGaugeMax).attr("dx",e.innerRadius+(e.radius-e.innerRadius)/(g.gauge_fullCircle?1:2)+"px").attr("dy","1.2em").text(g.gauge_label_show?g.gauge_max:""))},i.initGauge=function(){var a=this.arcs;this.hasType("gauge")&&(a.append("path").attr("class",l.chartArcsBackground),a.append("text").attr("class",l.chartArcsGaugeUnit).style("text-anchor","middle").style("pointer-events","none"),a.append("text").attr("class",l.chartArcsGaugeMin).style("text-anchor","middle").style("pointer-events","none"),a.append("text").attr("class",l.chartArcsGaugeMax).style("text-anchor","middle").style("pointer-events","none"))},i.getGaugeLabelHeight=function(){return this.config.gauge_label_show?20:0},i.initRegion=function(){var a=this;a.region=a.main.append("g").attr("clip-path",a.clipPath).attr("class",l.regions)},i.updateRegion=function(a){var b=this,c=b.config;b.region.style("visibility",b.hasArcType()?"hidden":"visible"),b.mainRegion=b.main.select("."+l.regions).selectAll("."+l.region).data(c.regions),b.mainRegion.enter().append("g").append("rect").style("fill-opacity",0),b.mainRegion.attr("class",b.classRegion.bind(b)),b.mainRegion.exit().transition().duration(a).style("opacity",0).remove()},i.redrawRegion=function(a){var b=this,c=b.mainRegion.selectAll("rect").each(function(){var a=b.d3.select(this.parentNode).datum();b.d3.select(this).datum(a)}),d=b.regionX.bind(b),e=b.regionY.bind(b),f=b.regionWidth.bind(b),g=b.regionHeight.bind(b);return[(a?c.transition():c).attr("x",d).attr("y",e).attr("width",f).attr("height",g).style("fill-opacity",function(a){return m(a.opacity)?a.opacity:.1})]},i.regionX=function(a){var b,c=this,d=c.config,e="y"===a.axis?c.y:c.y2;return b="y"===a.axis||"y2"===a.axis?d.axis_rotated&&"start"in a?e(a.start):0:d.axis_rotated?0:"start"in a?c.x(c.isTimeSeries()?c.parseDate(a.start):a.start):0},i.regionY=function(a){var b,c=this,d=c.config,e="y"===a.axis?c.y:c.y2;return b="y"===a.axis||"y2"===a.axis?d.axis_rotated?0:"end"in a?e(a.end):0:d.axis_rotated&&"start"in a?c.x(c.isTimeSeries()?c.parseDate(a.start):a.start):0},i.regionWidth=function(a){var b,c=this,d=c.config,e=c.regionX(a),f="y"===a.axis?c.y:c.y2;return b="y"===a.axis||"y2"===a.axis?d.axis_rotated&&"end"in a?f(a.end):c.width:d.axis_rotated?c.width:"end"in a?c.x(c.isTimeSeries()?c.parseDate(a.end):a.end):c.width,e>b?0:b-e},i.regionHeight=function(a){var b,c=this,d=c.config,e=this.regionY(a),f="y"===a.axis?c.y:c.y2;return b="y"===a.axis||"y2"===a.axis?d.axis_rotated?c.height:"start"in a?f(a.start):c.height:d.axis_rotated&&"end"in a?c.x(c.isTimeSeries()?c.parseDate(a.end):a.end):c.height,e>b?0:b-e},i.isRegionOnX=function(a){return!a.axis||"x"===a.axis},i.drag=function(a){var b,c,d,e,f,g,h,i,j=this,k=j.config,m=j.main,n=j.d3;j.hasArcType()||k.data_selection_enabled&&(k.zoom_enabled&&!j.zoom.altDomain||k.data_selection_multiple&&(b=j.dragStart[0],c=j.dragStart[1],d=a[0],e=a[1],f=Math.min(b,d),g=Math.max(b,d),h=k.data_selection_grouped?j.margin.top:Math.min(c,e),i=k.data_selection_grouped?j.height:Math.max(c,e),m.select("."+l.dragarea).attr("x",f).attr("y",h).attr("width",g-f).attr("height",i-h),m.selectAll("."+l.shapes).selectAll("."+l.shape).filter(function(a){return k.data_selection_isselectable(a)}).each(function(a,b){var c,d,e,k,m,o,p=n.select(this),q=p.classed(l.SELECTED),r=p.classed(l.INCLUDED),s=!1;if(p.classed(l.circle))c=1*p.attr("cx"),d=1*p.attr("cy"),m=j.togglePoint,s=c>f&&g>c&&d>h&&i>d;else{if(!p.classed(l.bar))return;o=z(this),c=o.x,d=o.y,e=o.width,k=o.height,m=j.togglePath,s=!(c>g||f>c+e||d>i||h>d+k)}s^r&&(p.classed(l.INCLUDED,!r),p.classed(l.SELECTED,!q),m.call(j,!q,p,a,b))})))},i.dragstart=function(a){var b=this,c=b.config;b.hasArcType()||c.data_selection_enabled&&(b.dragStart=a,b.main.select("."+l.chart).append("rect").attr("class",l.dragarea).style("opacity",.1),b.dragging=!0)},i.dragend=function(){var a=this,b=a.config;a.hasArcType()||b.data_selection_enabled&&(a.main.select("."+l.dragarea).transition().duration(100).style("opacity",0).remove(),a.main.selectAll("."+l.shape).classed(l.INCLUDED,!1),a.dragging=!1)},i.selectPoint=function(a,b,c){var d=this,e=d.config,f=(e.axis_rotated?d.circleY:d.circleX).bind(d),g=(e.axis_rotated?d.circleX:d.circleY).bind(d),h=d.pointSelectR.bind(d);e.data_onselected.call(d.api,b,a.node()),d.main.select("."+l.selectedCircles+d.getTargetSelectorSuffix(b.id)).selectAll("."+l.selectedCircle+"-"+c).data([b]).enter().append("circle").attr("class",function(){return d.generateClass(l.selectedCircle,c)}).attr("cx",f).attr("cy",g).attr("stroke",function(){return d.color(b)}).attr("r",function(a){return 1.4*d.pointSelectR(a)}).transition().duration(100).attr("r",h)},i.unselectPoint=function(a,b,c){var d=this;d.config.data_onunselected.call(d.api,b,a.node()),d.main.select("."+l.selectedCircles+d.getTargetSelectorSuffix(b.id)).selectAll("."+l.selectedCircle+"-"+c).transition().duration(100).attr("r",0).remove()},i.togglePoint=function(a,b,c,d){a?this.selectPoint(b,c,d):this.unselectPoint(b,c,d)},i.selectPath=function(a,b){var c=this;c.config.data_onselected.call(c,b,a.node()),c.config.interaction_brighten&&a.transition().duration(100).style("fill",function(){return c.d3.rgb(c.color(b)).brighter(.75)})},i.unselectPath=function(a,b){var c=this;c.config.data_onunselected.call(c,b,a.node()),c.config.interaction_brighten&&a.transition().duration(100).style("fill",function(){return c.color(b)})},i.togglePath=function(a,b,c,d){a?this.selectPath(b,c,d):this.unselectPath(b,c,d)},i.getToggle=function(a,b){var c,d=this;return"circle"===a.nodeName?c=d.isStepType(b)?function(){}:d.togglePoint:"path"===a.nodeName&&(c=d.togglePath),c},i.toggleShape=function(a,b,c){var d=this,e=d.d3,f=d.config,g=e.select(a),h=g.classed(l.SELECTED),i=d.getToggle(a,b).bind(d);f.data_selection_enabled&&f.data_selection_isselectable(b)&&(f.data_selection_multiple||d.main.selectAll("."+l.shapes+(f.data_selection_grouped?d.getTargetSelectorSuffix(b.id):"")).selectAll("."+l.shape).each(function(a,b){var c=e.select(this);c.classed(l.SELECTED)&&i(!1,c.classed(l.SELECTED,!1),a,b)}),g.classed(l.SELECTED,!h),i(!h,g,b,c))},i.initBrush=function(){var a=this,b=a.d3;a.brush=b.svg.brush().on("brush",function(){a.redrawForBrush()}),a.brush.update=function(){return a.context&&a.context.select("."+l.brush).call(this),this},a.brush.scale=function(b){return a.config.axis_rotated?this.y(b):this.x(b)}},i.initSubchart=function(){var a=this,b=a.config,c=a.context=a.svg.append("g").attr("transform",a.getTranslate("context")),d=b.subchart_show?"visible":"hidden";c.style("visibility",d),c.append("g").attr("clip-path",a.clipPathForSubchart).attr("class",l.chart),c.select("."+l.chart).append("g").attr("class",l.chartBars),c.select("."+l.chart).append("g").attr("class",l.chartLines),c.append("g").attr("clip-path",a.clipPath).attr("class",l.brush).call(a.brush),a.axes.subx=c.append("g").attr("class",l.axisX).attr("transform",a.getTranslate("subx")).attr("clip-path",b.axis_rotated?"":a.clipPathForXAxis).style("visibility",b.subchart_axis_x_show?d:"hidden")},i.updateTargetsForSubchart=function(a){var b,c,d,e,f=this,g=f.context,h=f.config,i=f.classChartBar.bind(f),j=f.classBars.bind(f),k=f.classChartLine.bind(f),m=f.classLines.bind(f),n=f.classAreas.bind(f);h.subchart_show&&(e=g.select("."+l.chartBars).selectAll("."+l.chartBar).data(a).attr("class",i),d=e.enter().append("g").style("opacity",0).attr("class",i),d.append("g").attr("class",j),c=g.select("."+l.chartLines).selectAll("."+l.chartLine).data(a).attr("class",k),b=c.enter().append("g").style("opacity",0).attr("class",k),b.append("g").attr("class",m),b.append("g").attr("class",n),g.selectAll("."+l.brush+" rect").attr(h.axis_rotated?"width":"height",h.axis_rotated?f.width2:f.height2))},i.updateBarForSubchart=function(a){var b=this;b.contextBar=b.context.selectAll("."+l.bars).selectAll("."+l.bar).data(b.barData.bind(b)),b.contextBar.enter().append("path").attr("class",b.classBar.bind(b)).style("stroke","none").style("fill",b.color),b.contextBar.style("opacity",b.initialOpacity.bind(b)),b.contextBar.exit().transition().duration(a).style("opacity",0).remove()},i.redrawBarForSubchart=function(a,b,c){(b?this.contextBar.transition(Math.random().toString()).duration(c):this.contextBar).attr("d",a).style("opacity",1)},i.updateLineForSubchart=function(a){var b=this;b.contextLine=b.context.selectAll("."+l.lines).selectAll("."+l.line).data(b.lineData.bind(b)),b.contextLine.enter().append("path").attr("class",b.classLine.bind(b)).style("stroke",b.color),b.contextLine.style("opacity",b.initialOpacity.bind(b)),b.contextLine.exit().transition().duration(a).style("opacity",0).remove()},i.redrawLineForSubchart=function(a,b,c){(b?this.contextLine.transition(Math.random().toString()).duration(c):this.contextLine).attr("d",a).style("opacity",1)},i.updateAreaForSubchart=function(a){var b=this,c=b.d3;b.contextArea=b.context.selectAll("."+l.areas).selectAll("."+l.area).data(b.lineData.bind(b)),b.contextArea.enter().append("path").attr("class",b.classArea.bind(b)).style("fill",b.color).style("opacity",function(){return b.orgAreaOpacity=+c.select(this).style("opacity"),0}),b.contextArea.style("opacity",0),b.contextArea.exit().transition().duration(a).style("opacity",0).remove()},i.redrawAreaForSubchart=function(a,b,c){(b?this.contextArea.transition(Math.random().toString()).duration(c):this.contextArea).attr("d",a).style("fill",this.color).style("opacity",this.orgAreaOpacity)},i.redrawSubchart=function(a,b,c,d,e,f,g){var h,i,j,k=this,l=k.d3,m=k.config;k.context.style("visibility",m.subchart_show?"visible":"hidden"),m.subchart_show&&(l.event&&"zoom"===l.event.type&&k.brush.extent(k.x.orgDomain()).update(),a&&(k.brush.empty()||k.brush.extent(k.x.orgDomain()).update(),h=k.generateDrawArea(e,!0),i=k.generateDrawBar(f,!0),j=k.generateDrawLine(g,!0),k.updateBarForSubchart(c),k.updateLineForSubchart(c),k.updateAreaForSubchart(c),k.redrawBarForSubchart(i,c,c),k.redrawLineForSubchart(j,c,c),k.redrawAreaForSubchart(h,c,c)))},i.redrawForBrush=function(){var a=this,b=a.x;a.redraw({withTransition:!1,withY:a.config.zoom_rescale,withSubchart:!1,withUpdateXDomain:!0,withDimension:!1}),a.config.subchart_onbrush.call(a.api,b.orgDomain())},i.transformContext=function(a,b){var c,d=this;b&&b.axisSubX?c=b.axisSubX:(c=d.context.select("."+l.axisX),a&&(c=c.transition())),d.context.attr("transform",d.getTranslate("context")),c.attr("transform",d.getTranslate("subx"))},i.getDefaultExtent=function(){var a=this,b=a.config,c=n(b.axis_x_extent)?b.axis_x_extent(a.getXDomain(a.data.targets)):b.axis_x_extent;return a.isTimeSeries()&&(c=[a.parseDate(c[0]),a.parseDate(c[1])]),c},i.initZoom=function(){var a,b=this,c=b.d3,d=b.config;b.zoom=c.behavior.zoom().on("zoomstart",function(){a=c.event.sourceEvent,b.zoom.altDomain=c.event.sourceEvent.altKey?b.x.orgDomain():null,d.zoom_onzoomstart.call(b.api,c.event.sourceEvent)}).on("zoom",function(){b.redrawForZoom.call(b)}).on("zoomend",function(){var e=c.event.sourceEvent;e&&a.clientX===e.clientX&&a.clientY===e.clientY||(b.redrawEventRect(),b.updateZoom(),d.zoom_onzoomend.call(b.api,b.x.orgDomain()))}),b.zoom.scale=function(a){return d.axis_rotated?this.y(a):this.x(a)},b.zoom.orgScaleExtent=function(){var a=d.zoom_extent?d.zoom_extent:[1,10];return[a[0],Math.max(b.getMaxDataCount()/a[1],a[1])]},b.zoom.updateScaleExtent=function(){var a=t(b.x.orgDomain())/t(b.getZoomDomain()),c=this.orgScaleExtent();return this.scaleExtent([c[0]*a,c[1]*a]),this}},i.getZoomDomain=function(){var a=this,b=a.config,c=a.d3,d=c.min([a.orgXDomain[0],b.zoom_x_min]),e=c.max([a.orgXDomain[1],b.zoom_x_max]);return[d,e]},i.updateZoom=function(){var a=this,b=a.config.zoom_enabled?a.zoom:function(){};a.main.select("."+l.zoomRect).call(b).on("dblclick.zoom",null),a.main.selectAll("."+l.eventRect).call(b).on("dblclick.zoom",null)},i.redrawForZoom=function(){var a=this,b=a.d3,c=a.config,d=a.zoom,e=a.x;if(c.zoom_enabled&&0!==a.filterTargetsToShow(a.data.targets).length){if("mousemove"===b.event.sourceEvent.type&&d.altDomain)return e.domain(d.altDomain),void d.scale(e).updateScaleExtent();a.isCategorized()&&e.orgDomain()[0]===a.orgXDomain[0]&&e.domain([a.orgXDomain[0]-1e-10,e.orgDomain()[1]]),a.redraw({withTransition:!1,withY:c.zoom_rescale,withSubchart:!1,withEventRect:!1,withDimension:!1}),"mousemove"===b.event.sourceEvent.type&&(a.cancelClick=!0),c.zoom_onzoom.call(a.api,e.orgDomain())}},i.generateColor=function(){var a=this,b=a.config,c=a.d3,d=b.data_colors,e=v(b.color_pattern)?b.color_pattern:c.scale.category10().range(),f=b.data_color,g=[];return function(a){var b,c=a.id||a.data&&a.data.id||a;return d[c]instanceof Function?b=d[c](a):d[c]?b=d[c]:(g.indexOf(c)<0&&g.push(c),b=e[g.indexOf(c)%e.length],d[c]=b),f instanceof Function?f(b,a):b}},i.generateLevelColor=function(){var a=this,b=a.config,c=b.color_pattern,d=b.color_threshold,e="value"===d.unit,f=d.values&&d.values.length?d.values:[],g=d.max||100;return v(b.color_threshold)?function(a){var b,d,h=c[c.length-1];for(b=0;b<f.length;b++)if(d=e?a:100*a/g,d<f[b]){h=c[b];break}return h}:null},i.getYFormat=function(a){var b=this,c=a&&!b.hasType("gauge")?b.defaultArcValueFormat:b.yFormat,d=a&&!b.hasType("gauge")?b.defaultArcValueFormat:b.y2Format;return function(a,e,f){var g="y2"===b.axis.getId(f)?d:c;return g.call(b,a,e)}},i.yFormat=function(a){var b=this,c=b.config,d=c.axis_y_tick_format?c.axis_y_tick_format:b.defaultValueFormat;return d(a)},i.y2Format=function(a){var b=this,c=b.config,d=c.axis_y2_tick_format?c.axis_y2_tick_format:b.defaultValueFormat;return d(a)},i.defaultValueFormat=function(a){return m(a)?+a:""},i.defaultArcValueFormat=function(a,b){return(100*b).toFixed(1)+"%"},i.dataLabelFormat=function(a){var b,c=this,d=c.config.data_labels,e=function(a){return m(a)?+a:""};return b="function"==typeof d.format?d.format:"object"==typeof d.format?d.format[a]?d.format[a]===!0?e:d.format[a]:function(){return""}:e},i.hasCaches=function(a){for(var b=0;b<a.length;b++)if(!(a[b]in this.cache))return!1;return!0},i.addCache=function(a,b){this.cache[a]=this.cloneTarget(b)},i.getCaches=function(a){var b,c=[];for(b=0;b<a.length;b++)a[b]in this.cache&&c.push(this.cloneTarget(this.cache[a[b]]));return c};var l=i.CLASS={target:"c3-target",chart:"c3-chart",chartLine:"c3-chart-line",chartLines:"c3-chart-lines",chartBar:"c3-chart-bar",chartBars:"c3-chart-bars",chartText:"c3-chart-text",chartTexts:"c3-chart-texts",chartArc:"c3-chart-arc",chartArcs:"c3-chart-arcs",chartArcsTitle:"c3-chart-arcs-title",chartArcsBackground:"c3-chart-arcs-background",chartArcsGaugeUnit:"c3-chart-arcs-gauge-unit",chartArcsGaugeMax:"c3-chart-arcs-gauge-max",chartArcsGaugeMin:"c3-chart-arcs-gauge-min",selectedCircle:"c3-selected-circle",selectedCircles:"c3-selected-circles",eventRect:"c3-event-rect",eventRects:"c3-event-rects",eventRectsSingle:"c3-event-rects-single",eventRectsMultiple:"c3-event-rects-multiple",zoomRect:"c3-zoom-rect",brush:"c3-brush",focused:"c3-focused",defocused:"c3-defocused",region:"c3-region",regions:"c3-regions",title:"c3-title",tooltipContainer:"c3-tooltip-container",tooltip:"c3-tooltip",tooltipName:"c3-tooltip-name",shape:"c3-shape",shapes:"c3-shapes",line:"c3-line",lines:"c3-lines",bar:"c3-bar",bars:"c3-bars",circle:"c3-circle",circles:"c3-circles",arc:"c3-arc",arcs:"c3-arcs",area:"c3-area",areas:"c3-areas",empty:"c3-empty",text:"c3-text",texts:"c3-texts",gaugeValue:"c3-gauge-value",grid:"c3-grid",gridLines:"c3-grid-lines",xgrid:"c3-xgrid",xgrids:"c3-xgrids",xgridLine:"c3-xgrid-line",xgridLines:"c3-xgrid-lines",xgridFocus:"c3-xgrid-focus",ygrid:"c3-ygrid",ygrids:"c3-ygrids",ygridLine:"c3-ygrid-line",ygridLines:"c3-ygrid-lines",axis:"c3-axis",axisX:"c3-axis-x",axisXLabel:"c3-axis-x-label",axisY:"c3-axis-y",axisYLabel:"c3-axis-y-label",axisY2:"c3-axis-y2",axisY2Label:"c3-axis-y2-label",legendBackground:"c3-legend-background",legendItem:"c3-legend-item",legendItemEvent:"c3-legend-item-event",legendItemTile:"c3-legend-item-tile",legendItemHidden:"c3-legend-item-hidden",legendItemFocused:"c3-legend-item-focused",dragarea:"c3-dragarea",EXPANDED:"_expanded_",SELECTED:"_selected_",INCLUDED:"_included_"};i.generateClass=function(a,b){return" "+a+" "+a+this.getTargetSelectorSuffix(b)},i.classText=function(a){return this.generateClass(l.text,a.index)},i.classTexts=function(a){return this.generateClass(l.texts,a.id)},i.classShape=function(a){return this.generateClass(l.shape,a.index)},i.classShapes=function(a){return this.generateClass(l.shapes,a.id)},i.classLine=function(a){return this.classShape(a)+this.generateClass(l.line,a.id)},i.classLines=function(a){return this.classShapes(a)+this.generateClass(l.lines,a.id)},i.classCircle=function(a){return this.classShape(a)+this.generateClass(l.circle,a.index)},i.classCircles=function(a){return this.classShapes(a)+this.generateClass(l.circles,a.id)},i.classBar=function(a){return this.classShape(a)+this.generateClass(l.bar,a.index)},i.classBars=function(a){return this.classShapes(a)+this.generateClass(l.bars,a.id)},i.classArc=function(a){return this.classShape(a.data)+this.generateClass(l.arc,a.data.id)},i.classArcs=function(a){return this.classShapes(a.data)+this.generateClass(l.arcs,a.data.id)},i.classArea=function(a){return this.classShape(a)+this.generateClass(l.area,a.id)},i.classAreas=function(a){return this.classShapes(a)+this.generateClass(l.areas,a.id)},i.classRegion=function(a,b){return this.generateClass(l.region,b)+" "+("class"in a?a["class"]:"")},i.classEvent=function(a){return this.generateClass(l.eventRect,a.index)},i.classTarget=function(a){var b=this,c=b.config.data_classes[a],d="";return c&&(d=" "+l.target+"-"+c),b.generateClass(l.target,a)+d},i.classFocus=function(a){return this.classFocused(a)+this.classDefocused(a)},i.classFocused=function(a){return" "+(this.focusedTargetIds.indexOf(a.id)>=0?l.focused:"")},i.classDefocused=function(a){return" "+(this.defocusedTargetIds.indexOf(a.id)>=0?l.defocused:"")},i.classChartText=function(a){return l.chartText+this.classTarget(a.id)},i.classChartLine=function(a){return l.chartLine+this.classTarget(a.id)},i.classChartBar=function(a){return l.chartBar+this.classTarget(a.id)},i.classChartArc=function(a){return l.chartArc+this.classTarget(a.data.id)},i.getTargetSelectorSuffix=function(a){return a||0===a?("-"+a).replace(/[\s?!@#$%^&*()_=+,.<>'":;\[\]\/|~`{}\\]/g,"-"):""},i.selectorTarget=function(a,b){return(b||"")+"."+l.target+this.getTargetSelectorSuffix(a)},i.selectorTargets=function(a,b){var c=this;return a=a||[],a.length?a.map(function(a){return c.selectorTarget(a,b)}):null},i.selectorLegend=function(a){return"."+l.legendItem+this.getTargetSelectorSuffix(a)},i.selectorLegends=function(a){var b=this;return a&&a.length?a.map(function(a){return b.selectorLegend(a)}):null};var m=i.isValue=function(a){return a||0===a},n=i.isFunction=function(a){return"function"==typeof a},o=i.isString=function(a){return"string"==typeof a},p=i.isUndefined=function(a){return"undefined"==typeof a},q=i.isDefined=function(a){return"undefined"!=typeof a},r=i.ceil10=function(a){return 10*Math.ceil(a/10)},s=i.asHalfPixel=function(a){return Math.ceil(a)+.5},t=i.diffDomain=function(a){return a[1]-a[0]},u=i.isEmpty=function(a){return"undefined"==typeof a||null===a||o(a)&&0===a.length||"object"==typeof a&&0===Object.keys(a).length},v=i.notEmpty=function(a){return!i.isEmpty(a)},w=i.getOption=function(a,b,c){return q(a[b])?a[b]:c},x=i.hasValue=function(a,b){var c=!1;return Object.keys(a).forEach(function(d){a[d]===b&&(c=!0)}),c},y=i.sanitise=function(a){return"string"==typeof a?a.replace(/</g,"&lt;").replace(/>/g,"&gt;"):a},z=i.getPathBox=function(a){var b=a.getBoundingClientRect(),c=[a.pathSegList.getItem(0),a.pathSegList.getItem(1)],d=c[0].x,e=Math.min(c[0].y,c[1].y);return{x:d,y:e,width:b.width,height:b.height}};h.focus=function(a){var b,c=this.internal;a=c.mapToTargetIds(a),b=c.svg.selectAll(c.selectorTargets(a.filter(c.isTargetToShow,c))),this.revert(),this.defocus(),b.classed(l.focused,!0).classed(l.defocused,!1),
5
- c.hasArcType()&&c.expandArc(a),c.toggleFocusLegend(a,!0),c.focusedTargetIds=a,c.defocusedTargetIds=c.defocusedTargetIds.filter(function(b){return a.indexOf(b)<0})},h.defocus=function(a){var b,c=this.internal;a=c.mapToTargetIds(a),b=c.svg.selectAll(c.selectorTargets(a.filter(c.isTargetToShow,c))),b.classed(l.focused,!1).classed(l.defocused,!0),c.hasArcType()&&c.unexpandArc(a),c.toggleFocusLegend(a,!1),c.focusedTargetIds=c.focusedTargetIds.filter(function(b){return a.indexOf(b)<0}),c.defocusedTargetIds=a},h.revert=function(a){var b,c=this.internal;a=c.mapToTargetIds(a),b=c.svg.selectAll(c.selectorTargets(a)),b.classed(l.focused,!1).classed(l.defocused,!1),c.hasArcType()&&c.unexpandArc(a),c.config.legend_show&&(c.showLegend(a.filter(c.isLegendToShow.bind(c))),c.legend.selectAll(c.selectorLegends(a)).filter(function(){return c.d3.select(this).classed(l.legendItemFocused)}).classed(l.legendItemFocused,!1)),c.focusedTargetIds=[],c.defocusedTargetIds=[]},h.show=function(a,b){var c,d=this.internal;a=d.mapToTargetIds(a),b=b||{},d.removeHiddenTargetIds(a),c=d.svg.selectAll(d.selectorTargets(a)),c.transition().style("opacity",1,"important").call(d.endall,function(){c.style("opacity",null).style("opacity",1)}),b.withLegend&&d.showLegend(a),d.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0,withLegend:!0})},h.hide=function(a,b){var c,d=this.internal;a=d.mapToTargetIds(a),b=b||{},d.addHiddenTargetIds(a),c=d.svg.selectAll(d.selectorTargets(a)),c.transition().style("opacity",0,"important").call(d.endall,function(){c.style("opacity",null).style("opacity",0)}),b.withLegend&&d.hideLegend(a),d.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0,withLegend:!0})},h.toggle=function(a,b){var c=this,d=this.internal;d.mapToTargetIds(a).forEach(function(a){d.isTargetToShow(a)?c.hide(a,b):c.show(a,b)})},h.zoom=function(a){var b=this.internal;return a&&(b.isTimeSeries()&&(a=a.map(function(a){return b.parseDate(a)})),b.brush.extent(a),b.redraw({withUpdateXDomain:!0,withY:b.config.zoom_rescale}),b.config.zoom_onzoom.call(this,b.x.orgDomain())),b.brush.extent()},h.zoom.enable=function(a){var b=this.internal;b.config.zoom_enabled=a,b.updateAndRedraw()},h.unzoom=function(){var a=this.internal;a.brush.clear().update(),a.redraw({withUpdateXDomain:!0})},h.zoom.max=function(a){var b=this.internal,c=b.config,d=b.d3;return 0===a||a?void(c.zoom_x_max=d.max([b.orgXDomain[1],a])):c.zoom_x_max},h.zoom.min=function(a){var b=this.internal,c=b.config,d=b.d3;return 0===a||a?void(c.zoom_x_min=d.min([b.orgXDomain[0],a])):c.zoom_x_min},h.zoom.range=function(a){return arguments.length?(q(a.max)&&this.domain.max(a.max),void(q(a.min)&&this.domain.min(a.min))):{max:this.domain.max(),min:this.domain.min()}},h.load=function(a){var b=this.internal,c=b.config;return a.xs&&b.addXs(a.xs),"names"in a&&h.data.names.bind(this)(a.names),"classes"in a&&Object.keys(a.classes).forEach(function(b){c.data_classes[b]=a.classes[b]}),"categories"in a&&b.isCategorized()&&(c.axis_x_categories=a.categories),"axes"in a&&Object.keys(a.axes).forEach(function(b){c.data_axes[b]=a.axes[b]}),"colors"in a&&Object.keys(a.colors).forEach(function(b){c.data_colors[b]=a.colors[b]}),"cacheIds"in a&&b.hasCaches(a.cacheIds)?void b.load(b.getCaches(a.cacheIds),a.done):void("unload"in a?b.unload(b.mapToTargetIds("boolean"==typeof a.unload&&a.unload?null:a.unload),function(){b.loadFromArgs(a)}):b.loadFromArgs(a))},h.unload=function(a){var b=this.internal;a=a||{},a instanceof Array?a={ids:a}:"string"==typeof a&&(a={ids:[a]}),b.unload(b.mapToTargetIds(a.ids),function(){b.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0,withLegend:!0}),a.done&&a.done()})},h.flow=function(a){var b,c,d,e,f,g,h,i,j=this.internal,k=[],l=j.getMaxDataCount(),n=0,o=0;if(a.json)c=j.convertJsonToData(a.json,a.keys);else if(a.rows)c=j.convertRowsToData(a.rows);else{if(!a.columns)return;c=j.convertColumnsToData(a.columns)}b=j.convertDataToTargets(c,!0),j.data.targets.forEach(function(a){var c,d,e=!1;for(c=0;c<b.length;c++)if(a.id===b[c].id){for(e=!0,a.values[a.values.length-1]&&(o=a.values[a.values.length-1].index+1),n=b[c].values.length,d=0;n>d;d++)b[c].values[d].index=o+d,j.isTimeSeries()||(b[c].values[d].x=o+d);a.values=a.values.concat(b[c].values),b.splice(c,1);break}e||k.push(a.id)}),j.data.targets.forEach(function(a){var b,c;for(b=0;b<k.length;b++)if(a.id===k[b])for(o=a.values[a.values.length-1].index+1,c=0;n>c;c++)a.values.push({id:a.id,index:o+c,x:j.isTimeSeries()?j.getOtherTargetX(o+c):o+c,value:null})}),j.data.targets.length&&b.forEach(function(a){var b,c=[];for(b=j.data.targets[0].values[0].index;o>b;b++)c.push({id:a.id,index:b,x:j.isTimeSeries()?j.getOtherTargetX(b):b,value:null});a.values.forEach(function(a){a.index+=o,j.isTimeSeries()||(a.x+=o)}),a.values=c.concat(a.values)}),j.data.targets=j.data.targets.concat(b),d=j.getMaxDataCount(),f=j.data.targets[0],g=f.values[0],q(a.to)?(n=0,i=j.isTimeSeries()?j.parseDate(a.to):a.to,f.values.forEach(function(a){a.x<i&&n++})):q(a.length)&&(n=a.length),l?1===l&&j.isTimeSeries()&&(h=(f.values[f.values.length-1].x-g.x)/2,e=[new Date(+g.x-h),new Date(+g.x+h)],j.updateXDomain(null,!0,!0,!1,e)):(h=j.isTimeSeries()?f.values.length>1?f.values[f.values.length-1].x-g.x:g.x-j.getXDomain(j.data.targets)[0]:1,e=[g.x-h,g.x],j.updateXDomain(null,!0,!0,!1,e)),j.updateTargets(j.data.targets),j.redraw({flow:{index:g.index,length:n,duration:m(a.duration)?a.duration:j.config.transition_duration,done:a.done,orgDataCount:l},withLegend:!0,withTransition:l>1,withTrimXDomain:!1,withUpdateXAxis:!0})},i.generateFlow=function(a){var b=this,c=b.config,d=b.d3;return function(){var e,f,g,h=a.targets,i=a.flow,j=a.drawBar,k=a.drawLine,m=a.drawArea,n=a.cx,o=a.cy,p=a.xv,q=a.xForText,r=a.yForText,s=a.duration,u=1,v=i.index,w=i.length,x=b.getValueOnIndex(b.data.targets[0].values,v),y=b.getValueOnIndex(b.data.targets[0].values,v+w),z=b.x.domain(),A=i.duration||s,B=i.done||function(){},C=b.generateWait(),D=b.xgrid||d.selectAll([]),E=b.xgridLines||d.selectAll([]),F=b.mainRegion||d.selectAll([]),G=b.mainText||d.selectAll([]),H=b.mainBar||d.selectAll([]),I=b.mainLine||d.selectAll([]),J=b.mainArea||d.selectAll([]),K=b.mainCircle||d.selectAll([]);b.flowing=!0,b.data.targets.forEach(function(a){a.values.splice(0,w)}),g=b.updateXDomain(h,!0,!0),b.updateXGrid&&b.updateXGrid(!0),i.orgDataCount?e=1===i.orgDataCount||(x&&x.x)===(y&&y.x)?b.x(z[0])-b.x(g[0]):b.isTimeSeries()?b.x(z[0])-b.x(g[0]):b.x(x.x)-b.x(y.x):1!==b.data.targets[0].values.length?e=b.x(z[0])-b.x(g[0]):b.isTimeSeries()?(x=b.getValueOnIndex(b.data.targets[0].values,0),y=b.getValueOnIndex(b.data.targets[0].values,b.data.targets[0].values.length-1),e=b.x(x.x)-b.x(y.x)):e=t(g)/2,u=t(z)/t(g),f="translate("+e+",0) scale("+u+",1)",b.hideXGridFocus(),d.transition().ease("linear").duration(A).each(function(){C.add(b.axes.x.transition().call(b.xAxis)),C.add(H.transition().attr("transform",f)),C.add(I.transition().attr("transform",f)),C.add(J.transition().attr("transform",f)),C.add(K.transition().attr("transform",f)),C.add(G.transition().attr("transform",f)),C.add(F.filter(b.isRegionOnX).transition().attr("transform",f)),C.add(D.transition().attr("transform",f)),C.add(E.transition().attr("transform",f))}).call(C,function(){var a,d=[],e=[],f=[];if(w){for(a=0;w>a;a++)d.push("."+l.shape+"-"+(v+a)),e.push("."+l.text+"-"+(v+a)),f.push("."+l.eventRect+"-"+(v+a));b.svg.selectAll("."+l.shapes).selectAll(d).remove(),b.svg.selectAll("."+l.texts).selectAll(e).remove(),b.svg.selectAll("."+l.eventRects).selectAll(f).remove(),b.svg.select("."+l.xgrid).remove()}D.attr("transform",null).attr(b.xgridAttr),E.attr("transform",null),E.select("line").attr("x1",c.axis_rotated?0:p).attr("x2",c.axis_rotated?b.width:p),E.select("text").attr("x",c.axis_rotated?b.width:0).attr("y",p),H.attr("transform",null).attr("d",j),I.attr("transform",null).attr("d",k),J.attr("transform",null).attr("d",m),K.attr("transform",null).attr("cx",n).attr("cy",o),G.attr("transform",null).attr("x",q).attr("y",r).style("fill-opacity",b.opacityForText.bind(b)),F.attr("transform",null),F.select("rect").filter(b.isRegionOnX).attr("x",b.regionX.bind(b)).attr("width",b.regionWidth.bind(b)),c.interaction_enabled&&b.redrawEventRect(),B(),b.flowing=!1})}},h.selected=function(a){var b=this.internal,c=b.d3;return c.merge(b.main.selectAll("."+l.shapes+b.getTargetSelectorSuffix(a)).selectAll("."+l.shape).filter(function(){return c.select(this).classed(l.SELECTED)}).map(function(a){return a.map(function(a){var b=a.__data__;return b.data?b.data:b})}))},h.select=function(a,b,c){var d=this.internal,e=d.d3,f=d.config;f.data_selection_enabled&&d.main.selectAll("."+l.shapes).selectAll("."+l.shape).each(function(g,h){var i=e.select(this),j=g.data?g.data.id:g.id,k=d.getToggle(this,g).bind(d),m=f.data_selection_grouped||!a||a.indexOf(j)>=0,n=!b||b.indexOf(h)>=0,o=i.classed(l.SELECTED);i.classed(l.line)||i.classed(l.area)||(m&&n?f.data_selection_isselectable(g)&&!o&&k(!0,i.classed(l.SELECTED,!0),g,h):q(c)&&c&&o&&k(!1,i.classed(l.SELECTED,!1),g,h))})},h.unselect=function(a,b){var c=this.internal,d=c.d3,e=c.config;e.data_selection_enabled&&c.main.selectAll("."+l.shapes).selectAll("."+l.shape).each(function(f,g){var h=d.select(this),i=f.data?f.data.id:f.id,j=c.getToggle(this,f).bind(c),k=e.data_selection_grouped||!a||a.indexOf(i)>=0,m=!b||b.indexOf(g)>=0,n=h.classed(l.SELECTED);h.classed(l.line)||h.classed(l.area)||k&&m&&e.data_selection_isselectable(f)&&n&&j(!1,h.classed(l.SELECTED,!1),f,g)})},h.transform=function(a,b){var c=this.internal,d=["pie","donut"].indexOf(a)>=0?{withTransform:!0}:null;c.transformTo(b,a,d)},i.transformTo=function(a,b,c){var d=this,e=!d.hasArcType(),f=c||{withTransitionForAxis:e};f.withTransitionForTransform=!1,d.transiting=!1,d.setTargetType(a,b),d.updateTargets(d.data.targets),d.updateAndRedraw(f)},h.groups=function(a){var b=this.internal,c=b.config;return p(a)?c.data_groups:(c.data_groups=a,b.redraw(),c.data_groups)},h.xgrids=function(a){var b=this.internal,c=b.config;return a?(c.grid_x_lines=a,b.redrawWithoutRescale(),c.grid_x_lines):c.grid_x_lines},h.xgrids.add=function(a){var b=this.internal;return this.xgrids(b.config.grid_x_lines.concat(a?a:[]))},h.xgrids.remove=function(a){var b=this.internal;b.removeGridLines(a,!0)},h.ygrids=function(a){var b=this.internal,c=b.config;return a?(c.grid_y_lines=a,b.redrawWithoutRescale(),c.grid_y_lines):c.grid_y_lines},h.ygrids.add=function(a){var b=this.internal;return this.ygrids(b.config.grid_y_lines.concat(a?a:[]))},h.ygrids.remove=function(a){var b=this.internal;b.removeGridLines(a,!1)},h.regions=function(a){var b=this.internal,c=b.config;return a?(c.regions=a,b.redrawWithoutRescale(),c.regions):c.regions},h.regions.add=function(a){var b=this.internal,c=b.config;return a?(c.regions=c.regions.concat(a),b.redrawWithoutRescale(),c.regions):c.regions},h.regions.remove=function(a){var b,c,d,e=this.internal,f=e.config;return a=a||{},b=e.getOption(a,"duration",f.transition_duration),c=e.getOption(a,"classes",[l.region]),d=e.main.select("."+l.regions).selectAll(c.map(function(a){return"."+a})),(b?d.transition().duration(b):d).style("opacity",0).remove(),f.regions=f.regions.filter(function(a){var b=!1;return a["class"]?(a["class"].split(" ").forEach(function(a){c.indexOf(a)>=0&&(b=!0)}),!b):!0}),f.regions},h.data=function(a){var b=this.internal.data.targets;return"undefined"==typeof a?b:b.filter(function(b){return[].concat(a).indexOf(b.id)>=0})},h.data.shown=function(a){return this.internal.filterTargetsToShow(this.data(a))},h.data.values=function(a){var b,c=null;return a&&(b=this.data(a),c=b[0]?b[0].values.map(function(a){return a.value}):null),c},h.data.names=function(a){return this.internal.clearLegendItemTextBoxCache(),this.internal.updateDataAttributes("names",a)},h.data.colors=function(a){return this.internal.updateDataAttributes("colors",a)},h.data.axes=function(a){return this.internal.updateDataAttributes("axes",a)},h.category=function(a,b){var c=this.internal,d=c.config;return arguments.length>1&&(d.axis_x_categories[a]=b,c.redraw()),d.axis_x_categories[a]},h.categories=function(a){var b=this.internal,c=b.config;return arguments.length?(c.axis_x_categories=a,b.redraw(),c.axis_x_categories):c.axis_x_categories},h.color=function(a){var b=this.internal;return b.color(a)},h.x=function(a){var b=this.internal;return arguments.length&&(b.updateTargetX(b.data.targets,a),b.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0})),b.data.xs},h.xs=function(a){var b=this.internal;return arguments.length&&(b.updateTargetXs(b.data.targets,a),b.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0})),b.data.xs},h.axis=function(){},h.axis.labels=function(a){var b=this.internal;arguments.length&&(Object.keys(a).forEach(function(c){b.axis.setLabelText(c,a[c])}),b.axis.updateLabels())},h.axis.max=function(a){var b=this.internal,c=b.config;return arguments.length?("object"==typeof a?(m(a.x)&&(c.axis_x_max=a.x),m(a.y)&&(c.axis_y_max=a.y),m(a.y2)&&(c.axis_y2_max=a.y2)):c.axis_y_max=c.axis_y2_max=a,void b.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0})):{x:c.axis_x_max,y:c.axis_y_max,y2:c.axis_y2_max}},h.axis.min=function(a){var b=this.internal,c=b.config;return arguments.length?("object"==typeof a?(m(a.x)&&(c.axis_x_min=a.x),m(a.y)&&(c.axis_y_min=a.y),m(a.y2)&&(c.axis_y2_min=a.y2)):c.axis_y_min=c.axis_y2_min=a,void b.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0})):{x:c.axis_x_min,y:c.axis_y_min,y2:c.axis_y2_min}},h.axis.range=function(a){return arguments.length?(q(a.max)&&this.axis.max(a.max),void(q(a.min)&&this.axis.min(a.min))):{max:this.axis.max(),min:this.axis.min()}},h.legend=function(){},h.legend.show=function(a){var b=this.internal;b.showLegend(b.mapToTargetIds(a)),b.updateAndRedraw({withLegend:!0})},h.legend.hide=function(a){var b=this.internal;b.hideLegend(b.mapToTargetIds(a)),b.updateAndRedraw({withLegend:!0})},h.resize=function(a){var b=this.internal,c=b.config;c.size_width=a?a.width:null,c.size_height=a?a.height:null,this.flush()},h.flush=function(){var a=this.internal;a.updateAndRedraw({withLegend:!0,withTransition:!1,withTransitionForTransform:!1})},h.destroy=function(){var b=this.internal;if(a.clearInterval(b.intervalForObserveInserted),void 0!==b.resizeTimeout&&a.clearTimeout(b.resizeTimeout),a.detachEvent)a.detachEvent("onresize",b.resizeFunction);else if(a.removeEventListener)a.removeEventListener("resize",b.resizeFunction);else{var c=a.onresize;c&&c.add&&c.remove&&c.remove(b.resizeFunction)}return b.selectChart.classed("c3",!1).html(""),Object.keys(b).forEach(function(a){b[a]=null}),null},h.tooltip=function(){},h.tooltip.show=function(a){var b,c,d=this.internal;a.mouse&&(c=a.mouse),a.data?d.isMultipleX()?(c=[d.x(a.data.x),d.getYScale(a.data.id)(a.data.value)],b=null):b=m(a.data.index)?a.data.index:d.getIndexByX(a.data.x):"undefined"!=typeof a.x?b=d.getIndexByX(a.x):"undefined"!=typeof a.index&&(b=a.index),d.dispatchEvent("mouseover",b,c),d.dispatchEvent("mousemove",b,c),d.config.tooltip_onshow.call(d,a.data)},h.tooltip.hide=function(){this.internal.dispatchEvent("mouseout",0),this.internal.config.tooltip_onhide.call(this)};var A;i.isSafari=function(){var b=a.navigator.userAgent;return b.indexOf("Safari")>=0&&b.indexOf("Chrome")<0},i.isChrome=function(){var b=a.navigator.userAgent;return b.indexOf("Chrome")>=0},Function.prototype.bind||(Function.prototype.bind=function(a){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var b=Array.prototype.slice.call(arguments,1),c=this,d=function(){},e=function(){return c.apply(this instanceof d?this:a,b.concat(Array.prototype.slice.call(arguments)))};return d.prototype=this.prototype,e.prototype=new d,e}),function(){"SVGPathSeg"in a||(a.SVGPathSeg=function(a,b,c){this.pathSegType=a,this.pathSegTypeAsLetter=b,this._owningPathSegList=c},SVGPathSeg.PATHSEG_UNKNOWN=0,SVGPathSeg.PATHSEG_CLOSEPATH=1,SVGPathSeg.PATHSEG_MOVETO_ABS=2,SVGPathSeg.PATHSEG_MOVETO_REL=3,SVGPathSeg.PATHSEG_LINETO_ABS=4,SVGPathSeg.PATHSEG_LINETO_REL=5,SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS=6,SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL=7,SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS=8,SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL=9,SVGPathSeg.PATHSEG_ARC_ABS=10,SVGPathSeg.PATHSEG_ARC_REL=11,SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS=12,SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL=13,SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS=14,SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL=15,SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS=16,SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL=17,SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS=18,SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL=19,SVGPathSeg.prototype._segmentChanged=function(){this._owningPathSegList&&this._owningPathSegList.segmentChanged(this)},a.SVGPathSegClosePath=function(a){SVGPathSeg.call(this,SVGPathSeg.PATHSEG_CLOSEPATH,"z",a)},SVGPathSegClosePath.prototype=Object.create(SVGPathSeg.prototype),SVGPathSegClosePath.prototype.toString=function(){return"[object SVGPathSegClosePath]"},SVGPathSegClosePath.prototype._asPathString=function(){return this.pathSegTypeAsLetter},SVGPathSegClosePath.prototype.clone=function(){return new SVGPathSegClosePath(void 0)},a.SVGPathSegMovetoAbs=function(a,b,c){SVGPathSeg.call(this,SVGPathSeg.PATHSEG_MOVETO_ABS,"M",a),this._x=b,this._y=c},SVGPathSegMovetoAbs.prototype=Object.create(SVGPathSeg.prototype),SVGPathSegMovetoAbs.prototype.toString=function(){return"[object SVGPathSegMovetoAbs]"},SVGPathSegMovetoAbs.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x+" "+this._y},SVGPathSegMovetoAbs.prototype.clone=function(){return new SVGPathSegMovetoAbs(void 0,this._x,this._y)},Object.defineProperty(SVGPathSegMovetoAbs.prototype,"x",{get:function(){return this._x},set:function(a){this._x=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegMovetoAbs.prototype,"y",{get:function(){return this._y},set:function(a){this._y=a,this._segmentChanged()},enumerable:!0}),a.SVGPathSegMovetoRel=function(a,b,c){SVGPathSeg.call(this,SVGPathSeg.PATHSEG_MOVETO_REL,"m",a),this._x=b,this._y=c},SVGPathSegMovetoRel.prototype=Object.create(SVGPathSeg.prototype),SVGPathSegMovetoRel.prototype.toString=function(){return"[object SVGPathSegMovetoRel]"},SVGPathSegMovetoRel.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x+" "+this._y},SVGPathSegMovetoRel.prototype.clone=function(){return new SVGPathSegMovetoRel(void 0,this._x,this._y)},Object.defineProperty(SVGPathSegMovetoRel.prototype,"x",{get:function(){return this._x},set:function(a){this._x=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegMovetoRel.prototype,"y",{get:function(){return this._y},set:function(a){this._y=a,this._segmentChanged()},enumerable:!0}),a.SVGPathSegLinetoAbs=function(a,b,c){SVGPathSeg.call(this,SVGPathSeg.PATHSEG_LINETO_ABS,"L",a),this._x=b,this._y=c},SVGPathSegLinetoAbs.prototype=Object.create(SVGPathSeg.prototype),SVGPathSegLinetoAbs.prototype.toString=function(){return"[object SVGPathSegLinetoAbs]"},SVGPathSegLinetoAbs.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x+" "+this._y},SVGPathSegLinetoAbs.prototype.clone=function(){return new SVGPathSegLinetoAbs(void 0,this._x,this._y)},Object.defineProperty(SVGPathSegLinetoAbs.prototype,"x",{get:function(){return this._x},set:function(a){this._x=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegLinetoAbs.prototype,"y",{get:function(){return this._y},set:function(a){this._y=a,this._segmentChanged()},enumerable:!0}),a.SVGPathSegLinetoRel=function(a,b,c){SVGPathSeg.call(this,SVGPathSeg.PATHSEG_LINETO_REL,"l",a),this._x=b,this._y=c},SVGPathSegLinetoRel.prototype=Object.create(SVGPathSeg.prototype),SVGPathSegLinetoRel.prototype.toString=function(){return"[object SVGPathSegLinetoRel]"},SVGPathSegLinetoRel.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x+" "+this._y},SVGPathSegLinetoRel.prototype.clone=function(){return new SVGPathSegLinetoRel(void 0,this._x,this._y)},Object.defineProperty(SVGPathSegLinetoRel.prototype,"x",{get:function(){return this._x},set:function(a){this._x=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegLinetoRel.prototype,"y",{get:function(){return this._y},set:function(a){this._y=a,this._segmentChanged()},enumerable:!0}),a.SVGPathSegCurvetoCubicAbs=function(a,b,c,d,e,f,g){SVGPathSeg.call(this,SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS,"C",a),this._x=b,this._y=c,this._x1=d,this._y1=e,this._x2=f,this._y2=g},SVGPathSegCurvetoCubicAbs.prototype=Object.create(SVGPathSeg.prototype),SVGPathSegCurvetoCubicAbs.prototype.toString=function(){return"[object SVGPathSegCurvetoCubicAbs]"},SVGPathSegCurvetoCubicAbs.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x1+" "+this._y1+" "+this._x2+" "+this._y2+" "+this._x+" "+this._y},SVGPathSegCurvetoCubicAbs.prototype.clone=function(){return new SVGPathSegCurvetoCubicAbs(void 0,this._x,this._y,this._x1,this._y1,this._x2,this._y2)},Object.defineProperty(SVGPathSegCurvetoCubicAbs.prototype,"x",{get:function(){return this._x},set:function(a){this._x=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoCubicAbs.prototype,"y",{get:function(){return this._y},set:function(a){this._y=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoCubicAbs.prototype,"x1",{get:function(){return this._x1},set:function(a){this._x1=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoCubicAbs.prototype,"y1",{get:function(){return this._y1},set:function(a){this._y1=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoCubicAbs.prototype,"x2",{get:function(){return this._x2},set:function(a){this._x2=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoCubicAbs.prototype,"y2",{get:function(){return this._y2},set:function(a){this._y2=a,this._segmentChanged()},enumerable:!0}),a.SVGPathSegCurvetoCubicRel=function(a,b,c,d,e,f,g){SVGPathSeg.call(this,SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL,"c",a),this._x=b,this._y=c,this._x1=d,this._y1=e,this._x2=f,this._y2=g},SVGPathSegCurvetoCubicRel.prototype=Object.create(SVGPathSeg.prototype),SVGPathSegCurvetoCubicRel.prototype.toString=function(){return"[object SVGPathSegCurvetoCubicRel]"},SVGPathSegCurvetoCubicRel.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x1+" "+this._y1+" "+this._x2+" "+this._y2+" "+this._x+" "+this._y},SVGPathSegCurvetoCubicRel.prototype.clone=function(){return new SVGPathSegCurvetoCubicRel(void 0,this._x,this._y,this._x1,this._y1,this._x2,this._y2)},Object.defineProperty(SVGPathSegCurvetoCubicRel.prototype,"x",{get:function(){return this._x},set:function(a){this._x=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoCubicRel.prototype,"y",{get:function(){return this._y},set:function(a){this._y=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoCubicRel.prototype,"x1",{get:function(){return this._x1},set:function(a){this._x1=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoCubicRel.prototype,"y1",{get:function(){return this._y1},set:function(a){this._y1=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoCubicRel.prototype,"x2",{get:function(){return this._x2},set:function(a){this._x2=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoCubicRel.prototype,"y2",{get:function(){return this._y2},set:function(a){this._y2=a,this._segmentChanged()},enumerable:!0}),a.SVGPathSegCurvetoQuadraticAbs=function(a,b,c,d,e){SVGPathSeg.call(this,SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS,"Q",a),this._x=b,this._y=c,this._x1=d,this._y1=e},SVGPathSegCurvetoQuadraticAbs.prototype=Object.create(SVGPathSeg.prototype),SVGPathSegCurvetoQuadraticAbs.prototype.toString=function(){return"[object SVGPathSegCurvetoQuadraticAbs]"},SVGPathSegCurvetoQuadraticAbs.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x1+" "+this._y1+" "+this._x+" "+this._y},SVGPathSegCurvetoQuadraticAbs.prototype.clone=function(){return new SVGPathSegCurvetoQuadraticAbs(void 0,this._x,this._y,this._x1,this._y1)},Object.defineProperty(SVGPathSegCurvetoQuadraticAbs.prototype,"x",{get:function(){return this._x},set:function(a){this._x=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoQuadraticAbs.prototype,"y",{get:function(){return this._y},set:function(a){this._y=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoQuadraticAbs.prototype,"x1",{get:function(){return this._x1},set:function(a){this._x1=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoQuadraticAbs.prototype,"y1",{get:function(){return this._y1},set:function(a){this._y1=a,this._segmentChanged()},enumerable:!0}),a.SVGPathSegCurvetoQuadraticRel=function(a,b,c,d,e){SVGPathSeg.call(this,SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL,"q",a),this._x=b,this._y=c,this._x1=d,this._y1=e},SVGPathSegCurvetoQuadraticRel.prototype=Object.create(SVGPathSeg.prototype),SVGPathSegCurvetoQuadraticRel.prototype.toString=function(){return"[object SVGPathSegCurvetoQuadraticRel]"},SVGPathSegCurvetoQuadraticRel.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x1+" "+this._y1+" "+this._x+" "+this._y},SVGPathSegCurvetoQuadraticRel.prototype.clone=function(){return new SVGPathSegCurvetoQuadraticRel(void 0,this._x,this._y,this._x1,this._y1)},Object.defineProperty(SVGPathSegCurvetoQuadraticRel.prototype,"x",{get:function(){return this._x},set:function(a){this._x=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoQuadraticRel.prototype,"y",{get:function(){return this._y},set:function(a){this._y=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoQuadraticRel.prototype,"x1",{get:function(){return this._x1},set:function(a){this._x1=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoQuadraticRel.prototype,"y1",{get:function(){return this._y1},set:function(a){this._y1=a,this._segmentChanged()},enumerable:!0}),a.SVGPathSegArcAbs=function(a,b,c,d,e,f,g,h){SVGPathSeg.call(this,SVGPathSeg.PATHSEG_ARC_ABS,"A",a),this._x=b,this._y=c,this._r1=d,this._r2=e,this._angle=f,this._largeArcFlag=g,this._sweepFlag=h},SVGPathSegArcAbs.prototype=Object.create(SVGPathSeg.prototype),SVGPathSegArcAbs.prototype.toString=function(){return"[object SVGPathSegArcAbs]"},SVGPathSegArcAbs.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._r1+" "+this._r2+" "+this._angle+" "+(this._largeArcFlag?"1":"0")+" "+(this._sweepFlag?"1":"0")+" "+this._x+" "+this._y},SVGPathSegArcAbs.prototype.clone=function(){return new SVGPathSegArcAbs(void 0,this._x,this._y,this._r1,this._r2,this._angle,this._largeArcFlag,this._sweepFlag)},Object.defineProperty(SVGPathSegArcAbs.prototype,"x",{get:function(){return this._x},set:function(a){this._x=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegArcAbs.prototype,"y",{get:function(){return this._y},set:function(a){this._y=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegArcAbs.prototype,"r1",{get:function(){return this._r1},set:function(a){this._r1=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegArcAbs.prototype,"r2",{get:function(){return this._r2},set:function(a){this._r2=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegArcAbs.prototype,"angle",{get:function(){return this._angle},set:function(a){this._angle=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegArcAbs.prototype,"largeArcFlag",{get:function(){return this._largeArcFlag},set:function(a){this._largeArcFlag=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegArcAbs.prototype,"sweepFlag",{get:function(){return this._sweepFlag},set:function(a){this._sweepFlag=a,this._segmentChanged()},enumerable:!0}),a.SVGPathSegArcRel=function(a,b,c,d,e,f,g,h){SVGPathSeg.call(this,SVGPathSeg.PATHSEG_ARC_REL,"a",a),this._x=b,this._y=c,this._r1=d,this._r2=e,this._angle=f,this._largeArcFlag=g,this._sweepFlag=h},SVGPathSegArcRel.prototype=Object.create(SVGPathSeg.prototype),SVGPathSegArcRel.prototype.toString=function(){return"[object SVGPathSegArcRel]"},SVGPathSegArcRel.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._r1+" "+this._r2+" "+this._angle+" "+(this._largeArcFlag?"1":"0")+" "+(this._sweepFlag?"1":"0")+" "+this._x+" "+this._y},SVGPathSegArcRel.prototype.clone=function(){return new SVGPathSegArcRel(void 0,this._x,this._y,this._r1,this._r2,this._angle,this._largeArcFlag,this._sweepFlag)},Object.defineProperty(SVGPathSegArcRel.prototype,"x",{get:function(){return this._x},set:function(a){this._x=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegArcRel.prototype,"y",{get:function(){return this._y},set:function(a){this._y=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegArcRel.prototype,"r1",{get:function(){return this._r1},set:function(a){this._r1=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegArcRel.prototype,"r2",{get:function(){return this._r2},set:function(a){this._r2=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegArcRel.prototype,"angle",{get:function(){return this._angle},set:function(a){this._angle=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegArcRel.prototype,"largeArcFlag",{get:function(){return this._largeArcFlag},set:function(a){this._largeArcFlag=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegArcRel.prototype,"sweepFlag",{get:function(){return this._sweepFlag},set:function(a){this._sweepFlag=a,this._segmentChanged()},enumerable:!0}),a.SVGPathSegLinetoHorizontalAbs=function(a,b){SVGPathSeg.call(this,SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS,"H",a),this._x=b},SVGPathSegLinetoHorizontalAbs.prototype=Object.create(SVGPathSeg.prototype),SVGPathSegLinetoHorizontalAbs.prototype.toString=function(){return"[object SVGPathSegLinetoHorizontalAbs]"},SVGPathSegLinetoHorizontalAbs.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x},SVGPathSegLinetoHorizontalAbs.prototype.clone=function(){return new SVGPathSegLinetoHorizontalAbs(void 0,this._x)},Object.defineProperty(SVGPathSegLinetoHorizontalAbs.prototype,"x",{get:function(){return this._x},set:function(a){this._x=a,this._segmentChanged()},enumerable:!0}),a.SVGPathSegLinetoHorizontalRel=function(a,b){SVGPathSeg.call(this,SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL,"h",a),this._x=b},SVGPathSegLinetoHorizontalRel.prototype=Object.create(SVGPathSeg.prototype),SVGPathSegLinetoHorizontalRel.prototype.toString=function(){return"[object SVGPathSegLinetoHorizontalRel]"},SVGPathSegLinetoHorizontalRel.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x},SVGPathSegLinetoHorizontalRel.prototype.clone=function(){return new SVGPathSegLinetoHorizontalRel(void 0,this._x)},Object.defineProperty(SVGPathSegLinetoHorizontalRel.prototype,"x",{get:function(){return this._x},set:function(a){this._x=a,this._segmentChanged()},enumerable:!0}),a.SVGPathSegLinetoVerticalAbs=function(a,b){SVGPathSeg.call(this,SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS,"V",a),this._y=b},SVGPathSegLinetoVerticalAbs.prototype=Object.create(SVGPathSeg.prototype),SVGPathSegLinetoVerticalAbs.prototype.toString=function(){return"[object SVGPathSegLinetoVerticalAbs]"},SVGPathSegLinetoVerticalAbs.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._y},SVGPathSegLinetoVerticalAbs.prototype.clone=function(){return new SVGPathSegLinetoVerticalAbs(void 0,this._y)},Object.defineProperty(SVGPathSegLinetoVerticalAbs.prototype,"y",{get:function(){return this._y},set:function(a){this._y=a,this._segmentChanged()},enumerable:!0}),a.SVGPathSegLinetoVerticalRel=function(a,b){
6
- SVGPathSeg.call(this,SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL,"v",a),this._y=b},SVGPathSegLinetoVerticalRel.prototype=Object.create(SVGPathSeg.prototype),SVGPathSegLinetoVerticalRel.prototype.toString=function(){return"[object SVGPathSegLinetoVerticalRel]"},SVGPathSegLinetoVerticalRel.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._y},SVGPathSegLinetoVerticalRel.prototype.clone=function(){return new SVGPathSegLinetoVerticalRel(void 0,this._y)},Object.defineProperty(SVGPathSegLinetoVerticalRel.prototype,"y",{get:function(){return this._y},set:function(a){this._y=a,this._segmentChanged()},enumerable:!0}),a.SVGPathSegCurvetoCubicSmoothAbs=function(a,b,c,d,e){SVGPathSeg.call(this,SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS,"S",a),this._x=b,this._y=c,this._x2=d,this._y2=e},SVGPathSegCurvetoCubicSmoothAbs.prototype=Object.create(SVGPathSeg.prototype),SVGPathSegCurvetoCubicSmoothAbs.prototype.toString=function(){return"[object SVGPathSegCurvetoCubicSmoothAbs]"},SVGPathSegCurvetoCubicSmoothAbs.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x2+" "+this._y2+" "+this._x+" "+this._y},SVGPathSegCurvetoCubicSmoothAbs.prototype.clone=function(){return new SVGPathSegCurvetoCubicSmoothAbs(void 0,this._x,this._y,this._x2,this._y2)},Object.defineProperty(SVGPathSegCurvetoCubicSmoothAbs.prototype,"x",{get:function(){return this._x},set:function(a){this._x=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoCubicSmoothAbs.prototype,"y",{get:function(){return this._y},set:function(a){this._y=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoCubicSmoothAbs.prototype,"x2",{get:function(){return this._x2},set:function(a){this._x2=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoCubicSmoothAbs.prototype,"y2",{get:function(){return this._y2},set:function(a){this._y2=a,this._segmentChanged()},enumerable:!0}),a.SVGPathSegCurvetoCubicSmoothRel=function(a,b,c,d,e){SVGPathSeg.call(this,SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL,"s",a),this._x=b,this._y=c,this._x2=d,this._y2=e},SVGPathSegCurvetoCubicSmoothRel.prototype=Object.create(SVGPathSeg.prototype),SVGPathSegCurvetoCubicSmoothRel.prototype.toString=function(){return"[object SVGPathSegCurvetoCubicSmoothRel]"},SVGPathSegCurvetoCubicSmoothRel.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x2+" "+this._y2+" "+this._x+" "+this._y},SVGPathSegCurvetoCubicSmoothRel.prototype.clone=function(){return new SVGPathSegCurvetoCubicSmoothRel(void 0,this._x,this._y,this._x2,this._y2)},Object.defineProperty(SVGPathSegCurvetoCubicSmoothRel.prototype,"x",{get:function(){return this._x},set:function(a){this._x=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoCubicSmoothRel.prototype,"y",{get:function(){return this._y},set:function(a){this._y=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoCubicSmoothRel.prototype,"x2",{get:function(){return this._x2},set:function(a){this._x2=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoCubicSmoothRel.prototype,"y2",{get:function(){return this._y2},set:function(a){this._y2=a,this._segmentChanged()},enumerable:!0}),a.SVGPathSegCurvetoQuadraticSmoothAbs=function(a,b,c){SVGPathSeg.call(this,SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS,"T",a),this._x=b,this._y=c},SVGPathSegCurvetoQuadraticSmoothAbs.prototype=Object.create(SVGPathSeg.prototype),SVGPathSegCurvetoQuadraticSmoothAbs.prototype.toString=function(){return"[object SVGPathSegCurvetoQuadraticSmoothAbs]"},SVGPathSegCurvetoQuadraticSmoothAbs.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x+" "+this._y},SVGPathSegCurvetoQuadraticSmoothAbs.prototype.clone=function(){return new SVGPathSegCurvetoQuadraticSmoothAbs(void 0,this._x,this._y)},Object.defineProperty(SVGPathSegCurvetoQuadraticSmoothAbs.prototype,"x",{get:function(){return this._x},set:function(a){this._x=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoQuadraticSmoothAbs.prototype,"y",{get:function(){return this._y},set:function(a){this._y=a,this._segmentChanged()},enumerable:!0}),a.SVGPathSegCurvetoQuadraticSmoothRel=function(a,b,c){SVGPathSeg.call(this,SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL,"t",a),this._x=b,this._y=c},SVGPathSegCurvetoQuadraticSmoothRel.prototype=Object.create(SVGPathSeg.prototype),SVGPathSegCurvetoQuadraticSmoothRel.prototype.toString=function(){return"[object SVGPathSegCurvetoQuadraticSmoothRel]"},SVGPathSegCurvetoQuadraticSmoothRel.prototype._asPathString=function(){return this.pathSegTypeAsLetter+" "+this._x+" "+this._y},SVGPathSegCurvetoQuadraticSmoothRel.prototype.clone=function(){return new SVGPathSegCurvetoQuadraticSmoothRel(void 0,this._x,this._y)},Object.defineProperty(SVGPathSegCurvetoQuadraticSmoothRel.prototype,"x",{get:function(){return this._x},set:function(a){this._x=a,this._segmentChanged()},enumerable:!0}),Object.defineProperty(SVGPathSegCurvetoQuadraticSmoothRel.prototype,"y",{get:function(){return this._y},set:function(a){this._y=a,this._segmentChanged()},enumerable:!0}),SVGPathElement.prototype.createSVGPathSegClosePath=function(){return new SVGPathSegClosePath(void 0)},SVGPathElement.prototype.createSVGPathSegMovetoAbs=function(a,b){return new SVGPathSegMovetoAbs(void 0,a,b)},SVGPathElement.prototype.createSVGPathSegMovetoRel=function(a,b){return new SVGPathSegMovetoRel(void 0,a,b)},SVGPathElement.prototype.createSVGPathSegLinetoAbs=function(a,b){return new SVGPathSegLinetoAbs(void 0,a,b)},SVGPathElement.prototype.createSVGPathSegLinetoRel=function(a,b){return new SVGPathSegLinetoRel(void 0,a,b)},SVGPathElement.prototype.createSVGPathSegCurvetoCubicAbs=function(a,b,c,d,e,f){return new SVGPathSegCurvetoCubicAbs(void 0,a,b,c,d,e,f)},SVGPathElement.prototype.createSVGPathSegCurvetoCubicRel=function(a,b,c,d,e,f){return new SVGPathSegCurvetoCubicRel(void 0,a,b,c,d,e,f)},SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticAbs=function(a,b,c,d){return new SVGPathSegCurvetoQuadraticAbs(void 0,a,b,c,d)},SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticRel=function(a,b,c,d){return new SVGPathSegCurvetoQuadraticRel(void 0,a,b,c,d)},SVGPathElement.prototype.createSVGPathSegArcAbs=function(a,b,c,d,e,f,g){return new SVGPathSegArcAbs(void 0,a,b,c,d,e,f,g)},SVGPathElement.prototype.createSVGPathSegArcRel=function(a,b,c,d,e,f,g){return new SVGPathSegArcRel(void 0,a,b,c,d,e,f,g)},SVGPathElement.prototype.createSVGPathSegLinetoHorizontalAbs=function(a){return new SVGPathSegLinetoHorizontalAbs(void 0,a)},SVGPathElement.prototype.createSVGPathSegLinetoHorizontalRel=function(a){return new SVGPathSegLinetoHorizontalRel(void 0,a)},SVGPathElement.prototype.createSVGPathSegLinetoVerticalAbs=function(a){return new SVGPathSegLinetoVerticalAbs(void 0,a)},SVGPathElement.prototype.createSVGPathSegLinetoVerticalRel=function(a){return new SVGPathSegLinetoVerticalRel(void 0,a)},SVGPathElement.prototype.createSVGPathSegCurvetoCubicSmoothAbs=function(a,b,c,d){return new SVGPathSegCurvetoCubicSmoothAbs(void 0,a,b,c,d)},SVGPathElement.prototype.createSVGPathSegCurvetoCubicSmoothRel=function(a,b,c,d){return new SVGPathSegCurvetoCubicSmoothRel(void 0,a,b,c,d)},SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothAbs=function(a,b){return new SVGPathSegCurvetoQuadraticSmoothAbs(void 0,a,b)},SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothRel=function(a,b){return new SVGPathSegCurvetoQuadraticSmoothRel(void 0,a,b)}),"SVGPathSegList"in a||(a.SVGPathSegList=function(a){this._pathElement=a,this._list=this._parsePath(this._pathElement.getAttribute("d")),this._mutationObserverConfig={attributes:!0,attributeFilter:["d"]},this._pathElementMutationObserver=new MutationObserver(this._updateListFromPathMutations.bind(this)),this._pathElementMutationObserver.observe(this._pathElement,this._mutationObserverConfig)},Object.defineProperty(SVGPathSegList.prototype,"numberOfItems",{get:function(){return this._checkPathSynchronizedToList(),this._list.length},enumerable:!0}),Object.defineProperty(SVGPathElement.prototype,"pathSegList",{get:function(){return this._pathSegList||(this._pathSegList=new SVGPathSegList(this)),this._pathSegList},enumerable:!0}),Object.defineProperty(SVGPathElement.prototype,"normalizedPathSegList",{get:function(){return this.pathSegList},enumerable:!0}),Object.defineProperty(SVGPathElement.prototype,"animatedPathSegList",{get:function(){return this.pathSegList},enumerable:!0}),Object.defineProperty(SVGPathElement.prototype,"animatedNormalizedPathSegList",{get:function(){return this.pathSegList},enumerable:!0}),SVGPathSegList.prototype._checkPathSynchronizedToList=function(){this._updateListFromPathMutations(this._pathElementMutationObserver.takeRecords())},SVGPathSegList.prototype._updateListFromPathMutations=function(a){if(this._pathElement){var b=!1;a.forEach(function(a){"d"==a.attributeName&&(b=!0)}),b&&(this._list=this._parsePath(this._pathElement.getAttribute("d")))}},SVGPathSegList.prototype._writeListToPath=function(){this._pathElementMutationObserver.disconnect(),this._pathElement.setAttribute("d",SVGPathSegList._pathSegArrayAsString(this._list)),this._pathElementMutationObserver.observe(this._pathElement,this._mutationObserverConfig)},SVGPathSegList.prototype.segmentChanged=function(a){this._writeListToPath()},SVGPathSegList.prototype.clear=function(){this._checkPathSynchronizedToList(),this._list.forEach(function(a){a._owningPathSegList=null}),this._list=[],this._writeListToPath()},SVGPathSegList.prototype.initialize=function(a){return this._checkPathSynchronizedToList(),this._list=[a],a._owningPathSegList=this,this._writeListToPath(),a},SVGPathSegList.prototype._checkValidIndex=function(a){if(isNaN(a)||0>a||a>=this.numberOfItems)throw"INDEX_SIZE_ERR"},SVGPathSegList.prototype.getItem=function(a){return this._checkPathSynchronizedToList(),this._checkValidIndex(a),this._list[a]},SVGPathSegList.prototype.insertItemBefore=function(a,b){return this._checkPathSynchronizedToList(),b>this.numberOfItems&&(b=this.numberOfItems),a._owningPathSegList&&(a=a.clone()),this._list.splice(b,0,a),a._owningPathSegList=this,this._writeListToPath(),a},SVGPathSegList.prototype.replaceItem=function(a,b){return this._checkPathSynchronizedToList(),a._owningPathSegList&&(a=a.clone()),this._checkValidIndex(b),this._list[b]=a,a._owningPathSegList=this,this._writeListToPath(),a},SVGPathSegList.prototype.removeItem=function(a){this._checkPathSynchronizedToList(),this._checkValidIndex(a);var b=this._list[a];return this._list.splice(a,1),this._writeListToPath(),b},SVGPathSegList.prototype.appendItem=function(a){return this._checkPathSynchronizedToList(),a._owningPathSegList&&(a=a.clone()),this._list.push(a),a._owningPathSegList=this,this._writeListToPath(),a},SVGPathSegList._pathSegArrayAsString=function(a){var b="",c=!0;return a.forEach(function(a){c?(c=!1,b+=a._asPathString()):b+=" "+a._asPathString()}),b},SVGPathSegList.prototype._parsePath=function(a){if(!a||0==a.length)return[];var b=this,c=function(){this.pathSegList=[]};c.prototype.appendSegment=function(a){this.pathSegList.push(a)};var d=function(a){this._string=a,this._currentIndex=0,this._endIndex=this._string.length,this._previousCommand=SVGPathSeg.PATHSEG_UNKNOWN,this._skipOptionalSpaces()};d.prototype._isCurrentSpace=function(){var a=this._string[this._currentIndex];return" ">=a&&(" "==a||"\n"==a||" "==a||"\r"==a||"\f"==a)},d.prototype._skipOptionalSpaces=function(){for(;this._currentIndex<this._endIndex&&this._isCurrentSpace();)this._currentIndex++;return this._currentIndex<this._endIndex},d.prototype._skipOptionalSpacesOrDelimiter=function(){return this._currentIndex<this._endIndex&&!this._isCurrentSpace()&&","!=this._string.charAt(this._currentIndex)?!1:(this._skipOptionalSpaces()&&this._currentIndex<this._endIndex&&","==this._string.charAt(this._currentIndex)&&(this._currentIndex++,this._skipOptionalSpaces()),this._currentIndex<this._endIndex)},d.prototype.hasMoreData=function(){return this._currentIndex<this._endIndex},d.prototype.peekSegmentType=function(){var a=this._string[this._currentIndex];return this._pathSegTypeFromChar(a)},d.prototype._pathSegTypeFromChar=function(a){switch(a){case"Z":case"z":return SVGPathSeg.PATHSEG_CLOSEPATH;case"M":return SVGPathSeg.PATHSEG_MOVETO_ABS;case"m":return SVGPathSeg.PATHSEG_MOVETO_REL;case"L":return SVGPathSeg.PATHSEG_LINETO_ABS;case"l":return SVGPathSeg.PATHSEG_LINETO_REL;case"C":return SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS;case"c":return SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL;case"Q":return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS;case"q":return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL;case"A":return SVGPathSeg.PATHSEG_ARC_ABS;case"a":return SVGPathSeg.PATHSEG_ARC_REL;case"H":return SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS;case"h":return SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL;case"V":return SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS;case"v":return SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL;case"S":return SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS;case"s":return SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL;case"T":return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS;case"t":return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL;default:return SVGPathSeg.PATHSEG_UNKNOWN}},d.prototype._nextCommandHelper=function(a,b){return("+"==a||"-"==a||"."==a||a>="0"&&"9">=a)&&b!=SVGPathSeg.PATHSEG_CLOSEPATH?b==SVGPathSeg.PATHSEG_MOVETO_ABS?SVGPathSeg.PATHSEG_LINETO_ABS:b==SVGPathSeg.PATHSEG_MOVETO_REL?SVGPathSeg.PATHSEG_LINETO_REL:b:SVGPathSeg.PATHSEG_UNKNOWN},d.prototype.initialCommandIsMoveTo=function(){if(!this.hasMoreData())return!0;var a=this.peekSegmentType();return a==SVGPathSeg.PATHSEG_MOVETO_ABS||a==SVGPathSeg.PATHSEG_MOVETO_REL},d.prototype._parseNumber=function(){var a=0,b=0,c=1,d=0,e=1,f=1,g=this._currentIndex;if(this._skipOptionalSpaces(),this._currentIndex<this._endIndex&&"+"==this._string.charAt(this._currentIndex)?this._currentIndex++:this._currentIndex<this._endIndex&&"-"==this._string.charAt(this._currentIndex)&&(this._currentIndex++,e=-1),!(this._currentIndex==this._endIndex||(this._string.charAt(this._currentIndex)<"0"||this._string.charAt(this._currentIndex)>"9")&&"."!=this._string.charAt(this._currentIndex))){for(var h=this._currentIndex;this._currentIndex<this._endIndex&&this._string.charAt(this._currentIndex)>="0"&&this._string.charAt(this._currentIndex)<="9";)this._currentIndex++;if(this._currentIndex!=h)for(var i=this._currentIndex-1,j=1;i>=h;)b+=j*(this._string.charAt(i--)-"0"),j*=10;if(this._currentIndex<this._endIndex&&"."==this._string.charAt(this._currentIndex)){if(this._currentIndex++,this._currentIndex>=this._endIndex||this._string.charAt(this._currentIndex)<"0"||this._string.charAt(this._currentIndex)>"9")return;for(;this._currentIndex<this._endIndex&&this._string.charAt(this._currentIndex)>="0"&&this._string.charAt(this._currentIndex)<="9";)d+=(this._string.charAt(this._currentIndex++)-"0")*(c*=.1)}if(this._currentIndex!=g&&this._currentIndex+1<this._endIndex&&("e"==this._string.charAt(this._currentIndex)||"E"==this._string.charAt(this._currentIndex))&&"x"!=this._string.charAt(this._currentIndex+1)&&"m"!=this._string.charAt(this._currentIndex+1)){if(this._currentIndex++,"+"==this._string.charAt(this._currentIndex)?this._currentIndex++:"-"==this._string.charAt(this._currentIndex)&&(this._currentIndex++,f=-1),this._currentIndex>=this._endIndex||this._string.charAt(this._currentIndex)<"0"||this._string.charAt(this._currentIndex)>"9")return;for(;this._currentIndex<this._endIndex&&this._string.charAt(this._currentIndex)>="0"&&this._string.charAt(this._currentIndex)<="9";)a*=10,a+=this._string.charAt(this._currentIndex)-"0",this._currentIndex++}var k=b+d;if(k*=e,a&&(k*=Math.pow(10,f*a)),g!=this._currentIndex)return this._skipOptionalSpacesOrDelimiter(),k}},d.prototype._parseArcFlag=function(){if(!(this._currentIndex>=this._endIndex)){var a=!1,b=this._string.charAt(this._currentIndex++);if("0"==b)a=!1;else{if("1"!=b)return;a=!0}return this._skipOptionalSpacesOrDelimiter(),a}},d.prototype.parseSegment=function(){var a=this._string[this._currentIndex],c=this._pathSegTypeFromChar(a);if(c==SVGPathSeg.PATHSEG_UNKNOWN){if(this._previousCommand==SVGPathSeg.PATHSEG_UNKNOWN)return null;if(c=this._nextCommandHelper(a,this._previousCommand),c==SVGPathSeg.PATHSEG_UNKNOWN)return null}else this._currentIndex++;switch(this._previousCommand=c,c){case SVGPathSeg.PATHSEG_MOVETO_REL:return new SVGPathSegMovetoRel(b,this._parseNumber(),this._parseNumber());case SVGPathSeg.PATHSEG_MOVETO_ABS:return new SVGPathSegMovetoAbs(b,this._parseNumber(),this._parseNumber());case SVGPathSeg.PATHSEG_LINETO_REL:return new SVGPathSegLinetoRel(b,this._parseNumber(),this._parseNumber());case SVGPathSeg.PATHSEG_LINETO_ABS:return new SVGPathSegLinetoAbs(b,this._parseNumber(),this._parseNumber());case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL:return new SVGPathSegLinetoHorizontalRel(b,this._parseNumber());case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS:return new SVGPathSegLinetoHorizontalAbs(b,this._parseNumber());case SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL:return new SVGPathSegLinetoVerticalRel(b,this._parseNumber());case SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS:return new SVGPathSegLinetoVerticalAbs(b,this._parseNumber());case SVGPathSeg.PATHSEG_CLOSEPATH:return this._skipOptionalSpaces(),new SVGPathSegClosePath(b);case SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL:var d={x1:this._parseNumber(),y1:this._parseNumber(),x2:this._parseNumber(),y2:this._parseNumber(),x:this._parseNumber(),y:this._parseNumber()};return new SVGPathSegCurvetoCubicRel(b,d.x,d.y,d.x1,d.y1,d.x2,d.y2);case SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS:var d={x1:this._parseNumber(),y1:this._parseNumber(),x2:this._parseNumber(),y2:this._parseNumber(),x:this._parseNumber(),y:this._parseNumber()};return new SVGPathSegCurvetoCubicAbs(b,d.x,d.y,d.x1,d.y1,d.x2,d.y2);case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL:var d={x2:this._parseNumber(),y2:this._parseNumber(),x:this._parseNumber(),y:this._parseNumber()};return new SVGPathSegCurvetoCubicSmoothRel(b,d.x,d.y,d.x2,d.y2);case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:var d={x2:this._parseNumber(),y2:this._parseNumber(),x:this._parseNumber(),y:this._parseNumber()};return new SVGPathSegCurvetoCubicSmoothAbs(b,d.x,d.y,d.x2,d.y2);case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL:var d={x1:this._parseNumber(),y1:this._parseNumber(),x:this._parseNumber(),y:this._parseNumber()};return new SVGPathSegCurvetoQuadraticRel(b,d.x,d.y,d.x1,d.y1);case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS:var d={x1:this._parseNumber(),y1:this._parseNumber(),x:this._parseNumber(),y:this._parseNumber()};return new SVGPathSegCurvetoQuadraticAbs(b,d.x,d.y,d.x1,d.y1);case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:return new SVGPathSegCurvetoQuadraticSmoothRel(b,this._parseNumber(),this._parseNumber());case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:return new SVGPathSegCurvetoQuadraticSmoothAbs(b,this._parseNumber(),this._parseNumber());case SVGPathSeg.PATHSEG_ARC_REL:var d={x1:this._parseNumber(),y1:this._parseNumber(),arcAngle:this._parseNumber(),arcLarge:this._parseArcFlag(),arcSweep:this._parseArcFlag(),x:this._parseNumber(),y:this._parseNumber()};return new SVGPathSegArcRel(b,d.x,d.y,d.x1,d.y1,d.arcAngle,d.arcLarge,d.arcSweep);case SVGPathSeg.PATHSEG_ARC_ABS:var d={x1:this._parseNumber(),y1:this._parseNumber(),arcAngle:this._parseNumber(),arcLarge:this._parseArcFlag(),arcSweep:this._parseArcFlag(),x:this._parseNumber(),y:this._parseNumber()};return new SVGPathSegArcAbs(b,d.x,d.y,d.x1,d.y1,d.arcAngle,d.arcLarge,d.arcSweep);default:throw"Unknown path seg type."}};var e=new c,f=new d(a);if(!f.initialCommandIsMoveTo())return[];for(;f.hasMoreData();){var g=f.parseSegment();if(!g)return[];e.appendSegment(g)}return e.pathSegList})}(),"function"==typeof define&&define.amd?define("c3",["d3"],function(){return k}):"undefined"!=typeof exports&&"undefined"!=typeof module?module.exports=k:a.c3=k}(window);
 
 
 
 
 
 
inc/js/d3.min.js DELETED
@@ -1,5 +0,0 @@
1
- !function(){function n(n){return n&&(n.ownerDocument||n.document||n).documentElement}function t(n){return n&&(n.ownerDocument&&n.ownerDocument.defaultView||n.document&&n||n.defaultView)}function e(n,t){return t>n?-1:n>t?1:n>=t?0:NaN}function r(n){return null===n?NaN:+n}function i(n){return!isNaN(n)}function u(n){return{left:function(t,e,r,i){for(arguments.length<3&&(r=0),arguments.length<4&&(i=t.length);i>r;){var u=r+i>>>1;n(t[u],e)<0?r=u+1:i=u}return r},right:function(t,e,r,i){for(arguments.length<3&&(r=0),arguments.length<4&&(i=t.length);i>r;){var u=r+i>>>1;n(t[u],e)>0?i=u:r=u+1}return r}}}function o(n){return n.length}function a(n){for(var t=1;n*t%1;)t*=10;return t}function l(n,t){for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}function c(){this._=Object.create(null)}function f(n){return(n+="")===bo||n[0]===_o?_o+n:n}function s(n){return(n+="")[0]===_o?n.slice(1):n}function h(n){return f(n)in this._}function p(n){return(n=f(n))in this._&&delete this._[n]}function g(){var n=[];for(var t in this._)n.push(s(t));return n}function v(){var n=0;for(var t in this._)++n;return n}function d(){for(var n in this._)return!1;return!0}function y(){this._=Object.create(null)}function m(n){return n}function M(n,t,e){return function(){var r=e.apply(t,arguments);return r===t?n:r}}function x(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.slice(1);for(var e=0,r=wo.length;r>e;++e){var i=wo[e]+t;if(i in n)return i}}function b(){}function _(){}function w(n){function t(){for(var t,r=e,i=-1,u=r.length;++i<u;)(t=r[i].on)&&t.apply(this,arguments);return n}var e=[],r=new c;return t.on=function(t,i){var u,o=r.get(t);return arguments.length<2?o&&o.on:(o&&(o.on=null,e=e.slice(0,u=e.indexOf(o)).concat(e.slice(u+1)),r.remove(t)),i&&e.push(r.set(t,{on:i})),n)},t}function S(){ao.event.preventDefault()}function k(){for(var n,t=ao.event;n=t.sourceEvent;)t=n;return t}function N(n){for(var t=new _,e=0,r=arguments.length;++e<r;)t[arguments[e]]=w(t);return t.of=function(e,r){return function(i){try{var u=i.sourceEvent=ao.event;i.target=n,ao.event=i,t[i.type].apply(e,r)}finally{ao.event=u}}},t}function E(n){return ko(n,Co),n}function A(n){return"function"==typeof n?n:function(){return No(n,this)}}function C(n){return"function"==typeof n?n:function(){return Eo(n,this)}}function z(n,t){function e(){this.removeAttribute(n)}function r(){this.removeAttributeNS(n.space,n.local)}function i(){this.setAttribute(n,t)}function u(){this.setAttributeNS(n.space,n.local,t)}function o(){var e=t.apply(this,arguments);null==e?this.removeAttribute(n):this.setAttribute(n,e)}function a(){var e=t.apply(this,arguments);null==e?this.removeAttributeNS(n.space,n.local):this.setAttributeNS(n.space,n.local,e)}return n=ao.ns.qualify(n),null==t?n.local?r:e:"function"==typeof t?n.local?a:o:n.local?u:i}function L(n){return n.trim().replace(/\s+/g," ")}function q(n){return new RegExp("(?:^|\\s+)"+ao.requote(n)+"(?:\\s+|$)","g")}function T(n){return(n+"").trim().split(/^|\s+/)}function R(n,t){function e(){for(var e=-1;++e<i;)n[e](this,t)}function r(){for(var e=-1,r=t.apply(this,arguments);++e<i;)n[e](this,r)}n=T(n).map(D);var i=n.length;return"function"==typeof t?r:e}function D(n){var t=q(n);return function(e,r){if(i=e.classList)return r?i.add(n):i.remove(n);var i=e.getAttribute("class")||"";r?(t.lastIndex=0,t.test(i)||e.setAttribute("class",L(i+" "+n))):e.setAttribute("class",L(i.replace(t," ")))}}function P(n,t,e){function r(){this.style.removeProperty(n)}function i(){this.style.setProperty(n,t,e)}function u(){var r=t.apply(this,arguments);null==r?this.style.removeProperty(n):this.style.setProperty(n,r,e)}return null==t?r:"function"==typeof t?u:i}function U(n,t){function e(){delete this[n]}function r(){this[n]=t}function i(){var e=t.apply(this,arguments);null==e?delete this[n]:this[n]=e}return null==t?e:"function"==typeof t?i:r}function j(n){function t(){var t=this.ownerDocument,e=this.namespaceURI;return e===zo&&t.documentElement.namespaceURI===zo?t.createElement(n):t.createElementNS(e,n)}function e(){return this.ownerDocument.createElementNS(n.space,n.local)}return"function"==typeof n?n:(n=ao.ns.qualify(n)).local?e:t}function F(){var n=this.parentNode;n&&n.removeChild(this)}function H(n){return{__data__:n}}function O(n){return function(){return Ao(this,n)}}function I(n){return arguments.length||(n=e),function(t,e){return t&&e?n(t.__data__,e.__data__):!t-!e}}function Y(n,t){for(var e=0,r=n.length;r>e;e++)for(var i,u=n[e],o=0,a=u.length;a>o;o++)(i=u[o])&&t(i,o,e);return n}function Z(n){return ko(n,qo),n}function V(n){var t,e;return function(r,i,u){var o,a=n[u].update,l=a.length;for(u!=e&&(e=u,t=0),i>=t&&(t=i+1);!(o=a[t])&&++t<l;);return o}}function X(n,t,e){function r(){var t=this[o];t&&(this.removeEventListener(n,t,t.$),delete this[o])}function i(){var i=l(t,co(arguments));r.call(this),this.addEventListener(n,this[o]=i,i.$=e),i._=t}function u(){var t,e=new RegExp("^__on([^.]+)"+ao.requote(n)+"$");for(var r in this)if(t=r.match(e)){var i=this[r];this.removeEventListener(t[1],i,i.$),delete this[r]}}var o="__on"+n,a=n.indexOf("."),l=$;a>0&&(n=n.slice(0,a));var c=To.get(n);return c&&(n=c,l=B),a?t?i:r:t?b:u}function $(n,t){return function(e){var r=ao.event;ao.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{ao.event=r}}}function B(n,t){var e=$(n,t);return function(n){var t=this,r=n.relatedTarget;r&&(r===t||8&r.compareDocumentPosition(t))||e.call(t,n)}}function W(e){var r=".dragsuppress-"+ ++Do,i="click"+r,u=ao.select(t(e)).on("touchmove"+r,S).on("dragstart"+r,S).on("selectstart"+r,S);if(null==Ro&&(Ro="onselectstart"in e?!1:x(e.style,"userSelect")),Ro){var o=n(e).style,a=o[Ro];o[Ro]="none"}return function(n){if(u.on(r,null),Ro&&(o[Ro]=a),n){var t=function(){u.on(i,null)};u.on(i,function(){S(),t()},!0),setTimeout(t,0)}}}function J(n,e){e.changedTouches&&(e=e.changedTouches[0]);var r=n.ownerSVGElement||n;if(r.createSVGPoint){var i=r.createSVGPoint();if(0>Po){var u=t(n);if(u.scrollX||u.scrollY){r=ao.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var o=r[0][0].getScreenCTM();Po=!(o.f||o.e),r.remove()}}return Po?(i.x=e.pageX,i.y=e.pageY):(i.x=e.clientX,i.y=e.clientY),i=i.matrixTransform(n.getScreenCTM().inverse()),[i.x,i.y]}var a=n.getBoundingClientRect();return[e.clientX-a.left-n.clientLeft,e.clientY-a.top-n.clientTop]}function G(){return ao.event.changedTouches[0].identifier}function K(n){return n>0?1:0>n?-1:0}function Q(n,t,e){return(t[0]-n[0])*(e[1]-n[1])-(t[1]-n[1])*(e[0]-n[0])}function nn(n){return n>1?0:-1>n?Fo:Math.acos(n)}function tn(n){return n>1?Io:-1>n?-Io:Math.asin(n)}function en(n){return((n=Math.exp(n))-1/n)/2}function rn(n){return((n=Math.exp(n))+1/n)/2}function un(n){return((n=Math.exp(2*n))-1)/(n+1)}function on(n){return(n=Math.sin(n/2))*n}function an(){}function ln(n,t,e){return this instanceof ln?(this.h=+n,this.s=+t,void(this.l=+e)):arguments.length<2?n instanceof ln?new ln(n.h,n.s,n.l):_n(""+n,wn,ln):new ln(n,t,e)}function cn(n,t,e){function r(n){return n>360?n-=360:0>n&&(n+=360),60>n?u+(o-u)*n/60:180>n?o:240>n?u+(o-u)*(240-n)/60:u}function i(n){return Math.round(255*r(n))}var u,o;return n=isNaN(n)?0:(n%=360)<0?n+360:n,t=isNaN(t)?0:0>t?0:t>1?1:t,e=0>e?0:e>1?1:e,o=.5>=e?e*(1+t):e+t-e*t,u=2*e-o,new mn(i(n+120),i(n),i(n-120))}function fn(n,t,e){return this instanceof fn?(this.h=+n,this.c=+t,void(this.l=+e)):arguments.length<2?n instanceof fn?new fn(n.h,n.c,n.l):n instanceof hn?gn(n.l,n.a,n.b):gn((n=Sn((n=ao.rgb(n)).r,n.g,n.b)).l,n.a,n.b):new fn(n,t,e)}function sn(n,t,e){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),new hn(e,Math.cos(n*=Yo)*t,Math.sin(n)*t)}function hn(n,t,e){return this instanceof hn?(this.l=+n,this.a=+t,void(this.b=+e)):arguments.length<2?n instanceof hn?new hn(n.l,n.a,n.b):n instanceof fn?sn(n.h,n.c,n.l):Sn((n=mn(n)).r,n.g,n.b):new hn(n,t,e)}function pn(n,t,e){var r=(n+16)/116,i=r+t/500,u=r-e/200;return i=vn(i)*na,r=vn(r)*ta,u=vn(u)*ea,new mn(yn(3.2404542*i-1.5371385*r-.4985314*u),yn(-.969266*i+1.8760108*r+.041556*u),yn(.0556434*i-.2040259*r+1.0572252*u))}function gn(n,t,e){return n>0?new fn(Math.atan2(e,t)*Zo,Math.sqrt(t*t+e*e),n):new fn(NaN,NaN,n)}function vn(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function dn(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function yn(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function mn(n,t,e){return this instanceof mn?(this.r=~~n,this.g=~~t,void(this.b=~~e)):arguments.length<2?n instanceof mn?new mn(n.r,n.g,n.b):_n(""+n,mn,cn):new mn(n,t,e)}function Mn(n){return new mn(n>>16,n>>8&255,255&n)}function xn(n){return Mn(n)+""}function bn(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function _n(n,t,e){var r,i,u,o=0,a=0,l=0;if(r=/([a-z]+)\((.*)\)/.exec(n=n.toLowerCase()))switch(i=r[2].split(","),r[1]){case"hsl":return e(parseFloat(i[0]),parseFloat(i[1])/100,parseFloat(i[2])/100);case"rgb":return t(Nn(i[0]),Nn(i[1]),Nn(i[2]))}return(u=ua.get(n))?t(u.r,u.g,u.b):(null==n||"#"!==n.charAt(0)||isNaN(u=parseInt(n.slice(1),16))||(4===n.length?(o=(3840&u)>>4,o=o>>4|o,a=240&u,a=a>>4|a,l=15&u,l=l<<4|l):7===n.length&&(o=(16711680&u)>>16,a=(65280&u)>>8,l=255&u)),t(o,a,l))}function wn(n,t,e){var r,i,u=Math.min(n/=255,t/=255,e/=255),o=Math.max(n,t,e),a=o-u,l=(o+u)/2;return a?(i=.5>l?a/(o+u):a/(2-o-u),r=n==o?(t-e)/a+(e>t?6:0):t==o?(e-n)/a+2:(n-t)/a+4,r*=60):(r=NaN,i=l>0&&1>l?0:r),new ln(r,i,l)}function Sn(n,t,e){n=kn(n),t=kn(t),e=kn(e);var r=dn((.4124564*n+.3575761*t+.1804375*e)/na),i=dn((.2126729*n+.7151522*t+.072175*e)/ta),u=dn((.0193339*n+.119192*t+.9503041*e)/ea);return hn(116*i-16,500*(r-i),200*(i-u))}function kn(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function Nn(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function En(n){return"function"==typeof n?n:function(){return n}}function An(n){return function(t,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=null),Cn(t,e,n,r)}}function Cn(n,t,e,r){function i(){var n,t=l.status;if(!t&&Ln(l)||t>=200&&300>t||304===t){try{n=e.call(u,l)}catch(r){return void o.error.call(u,r)}o.load.call(u,n)}else o.error.call(u,l)}var u={},o=ao.dispatch("beforesend","progress","load","error"),a={},l=new XMLHttpRequest,c=null;return!this.XDomainRequest||"withCredentials"in l||!/^(http(s)?:)?\/\//.test(n)||(l=new XDomainRequest),"onload"in l?l.onload=l.onerror=i:l.onreadystatechange=function(){l.readyState>3&&i()},l.onprogress=function(n){var t=ao.event;ao.event=n;try{o.progress.call(u,l)}finally{ao.event=t}},u.header=function(n,t){return n=(n+"").toLowerCase(),arguments.length<2?a[n]:(null==t?delete a[n]:a[n]=t+"",u)},u.mimeType=function(n){return arguments.length?(t=null==n?null:n+"",u):t},u.responseType=function(n){return arguments.length?(c=n,u):c},u.response=function(n){return e=n,u},["get","post"].forEach(function(n){u[n]=function(){return u.send.apply(u,[n].concat(co(arguments)))}}),u.send=function(e,r,i){if(2===arguments.length&&"function"==typeof r&&(i=r,r=null),l.open(e,n,!0),null==t||"accept"in a||(a.accept=t+",*/*"),l.setRequestHeader)for(var f in a)l.setRequestHeader(f,a[f]);return null!=t&&l.overrideMimeType&&l.overrideMimeType(t),null!=c&&(l.responseType=c),null!=i&&u.on("error",i).on("load",function(n){i(null,n)}),o.beforesend.call(u,l),l.send(null==r?null:r),u},u.abort=function(){return l.abort(),u},ao.rebind(u,o,"on"),null==r?u:u.get(zn(r))}function zn(n){return 1===n.length?function(t,e){n(null==t?e:null)}:n}function Ln(n){var t=n.responseType;return t&&"text"!==t?n.response:n.responseText}function qn(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now());var i=e+t,u={c:n,t:i,n:null};return aa?aa.n=u:oa=u,aa=u,la||(ca=clearTimeout(ca),la=1,fa(Tn)),u}function Tn(){var n=Rn(),t=Dn()-n;t>24?(isFinite(t)&&(clearTimeout(ca),ca=setTimeout(Tn,t)),la=0):(la=1,fa(Tn))}function Rn(){for(var n=Date.now(),t=oa;t;)n>=t.t&&t.c(n-t.t)&&(t.c=null),t=t.n;return n}function Dn(){for(var n,t=oa,e=1/0;t;)t.c?(t.t<e&&(e=t.t),t=(n=t).n):t=n?n.n=t.n:oa=t.n;return aa=n,e}function Pn(n,t){return t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}function Un(n,t){var e=Math.pow(10,3*xo(8-t));return{scale:t>8?function(n){return n/e}:function(n){return n*e},symbol:n}}function jn(n){var t=n.decimal,e=n.thousands,r=n.grouping,i=n.currency,u=r&&e?function(n,t){for(var i=n.length,u=[],o=0,a=r[0],l=0;i>0&&a>0&&(l+a+1>t&&(a=Math.max(1,t-l)),u.push(n.substring(i-=a,i+a)),!((l+=a+1)>t));)a=r[o=(o+1)%r.length];return u.reverse().join(e)}:m;return function(n){var e=ha.exec(n),r=e[1]||" ",o=e[2]||">",a=e[3]||"-",l=e[4]||"",c=e[5],f=+e[6],s=e[7],h=e[8],p=e[9],g=1,v="",d="",y=!1,m=!0;switch(h&&(h=+h.substring(1)),(c||"0"===r&&"="===o)&&(c=r="0",o="="),p){case"n":s=!0,p="g";break;case"%":g=100,d="%",p="f";break;case"p":g=100,d="%",p="r";break;case"b":case"o":case"x":case"X":"#"===l&&(v="0"+p.toLowerCase());case"c":m=!1;case"d":y=!0,h=0;break;case"s":g=-1,p="r"}"$"===l&&(v=i[0],d=i[1]),"r"!=p||h||(p="g"),null!=h&&("g"==p?h=Math.max(1,Math.min(21,h)):"e"!=p&&"f"!=p||(h=Math.max(0,Math.min(20,h)))),p=pa.get(p)||Fn;var M=c&&s;return function(n){var e=d;if(y&&n%1)return"";var i=0>n||0===n&&0>1/n?(n=-n,"-"):"-"===a?"":a;if(0>g){var l=ao.formatPrefix(n,h);n=l.scale(n),e=l.symbol+d}else n*=g;n=p(n,h);var x,b,_=n.lastIndexOf(".");if(0>_){var w=m?n.lastIndexOf("e"):-1;0>w?(x=n,b=""):(x=n.substring(0,w),b=n.substring(w))}else x=n.substring(0,_),b=t+n.substring(_+1);!c&&s&&(x=u(x,1/0));var S=v.length+x.length+b.length+(M?0:i.length),k=f>S?new Array(S=f-S+1).join(r):"";return M&&(x=u(k+x,k.length?f-b.length:1/0)),i+=v,n=x+b,("<"===o?i+n+k:">"===o?k+i+n:"^"===o?k.substring(0,S>>=1)+i+n+k.substring(S):i+(M?n:k+n))+e}}}function Fn(n){return n+""}function Hn(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function On(n,t,e){function r(t){var e=n(t),r=u(e,1);return r-t>t-e?e:r}function i(e){return t(e=n(new va(e-1)),1),e}function u(n,e){return t(n=new va(+n),e),n}function o(n,r,u){var o=i(n),a=[];if(u>1)for(;r>o;)e(o)%u||a.push(new Date(+o)),t(o,1);else for(;r>o;)a.push(new Date(+o)),t(o,1);return a}function a(n,t,e){try{va=Hn;var r=new Hn;return r._=n,o(r,t,e)}finally{va=Date}}n.floor=n,n.round=r,n.ceil=i,n.offset=u,n.range=o;var l=n.utc=In(n);return l.floor=l,l.round=In(r),l.ceil=In(i),l.offset=In(u),l.range=a,n}function In(n){return function(t,e){try{va=Hn;var r=new Hn;return r._=t,n(r,e)._}finally{va=Date}}}function Yn(n){function t(n){function t(t){for(var e,i,u,o=[],a=-1,l=0;++a<r;)37===n.charCodeAt(a)&&(o.push(n.slice(l,a)),null!=(i=ya[e=n.charAt(++a)])&&(e=n.charAt(++a)),(u=A[e])&&(e=u(t,null==i?"e"===e?" ":"0":i)),o.push(e),l=a+1);return o.push(n.slice(l,a)),o.join("")}var r=n.length;return t.parse=function(t){var r={y:1900,m:0,d:1,H:0,M:0,S:0,L:0,Z:null},i=e(r,n,t,0);if(i!=t.length)return null;"p"in r&&(r.H=r.H%12+12*r.p);var u=null!=r.Z&&va!==Hn,o=new(u?Hn:va);return"j"in r?o.setFullYear(r.y,0,r.j):"W"in r||"U"in r?("w"in r||(r.w="W"in r?1:0),o.setFullYear(r.y,0,1),o.setFullYear(r.y,0,"W"in r?(r.w+6)%7+7*r.W-(o.getDay()+5)%7:r.w+7*r.U-(o.getDay()+6)%7)):o.setFullYear(r.y,r.m,r.d),o.setHours(r.H+(r.Z/100|0),r.M+r.Z%100,r.S,r.L),u?o._:o},t.toString=function(){return n},t}function e(n,t,e,r){for(var i,u,o,a=0,l=t.length,c=e.length;l>a;){if(r>=c)return-1;if(i=t.charCodeAt(a++),37===i){if(o=t.charAt(a++),u=C[o in ya?t.charAt(a++):o],!u||(r=u(n,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}function r(n,t,e){_.lastIndex=0;var r=_.exec(t.slice(e));return r?(n.w=w.get(r[0].toLowerCase()),e+r[0].length):-1}function i(n,t,e){x.lastIndex=0;var r=x.exec(t.slice(e));return r?(n.w=b.get(r[0].toLowerCase()),e+r[0].length):-1}function u(n,t,e){N.lastIndex=0;var r=N.exec(t.slice(e));return r?(n.m=E.get(r[0].toLowerCase()),e+r[0].length):-1}function o(n,t,e){S.lastIndex=0;var r=S.exec(t.slice(e));return r?(n.m=k.get(r[0].toLowerCase()),e+r[0].length):-1}function a(n,t,r){return e(n,A.c.toString(),t,r)}function l(n,t,r){return e(n,A.x.toString(),t,r)}function c(n,t,r){return e(n,A.X.toString(),t,r)}function f(n,t,e){var r=M.get(t.slice(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}var s=n.dateTime,h=n.date,p=n.time,g=n.periods,v=n.days,d=n.shortDays,y=n.months,m=n.shortMonths;t.utc=function(n){function e(n){try{va=Hn;var t=new va;return t._=n,r(t)}finally{va=Date}}var r=t(n);return e.parse=function(n){try{va=Hn;var t=r.parse(n);return t&&t._}finally{va=Date}},e.toString=r.toString,e},t.multi=t.utc.multi=ct;var M=ao.map(),x=Vn(v),b=Xn(v),_=Vn(d),w=Xn(d),S=Vn(y),k=Xn(y),N=Vn(m),E=Xn(m);g.forEach(function(n,t){M.set(n.toLowerCase(),t)});var A={a:function(n){return d[n.getDay()]},A:function(n){return v[n.getDay()]},b:function(n){return m[n.getMonth()]},B:function(n){return y[n.getMonth()]},c:t(s),d:function(n,t){return Zn(n.getDate(),t,2)},e:function(n,t){return Zn(n.getDate(),t,2)},H:function(n,t){return Zn(n.getHours(),t,2)},I:function(n,t){return Zn(n.getHours()%12||12,t,2)},j:function(n,t){return Zn(1+ga.dayOfYear(n),t,3)},L:function(n,t){return Zn(n.getMilliseconds(),t,3)},m:function(n,t){return Zn(n.getMonth()+1,t,2)},M:function(n,t){return Zn(n.getMinutes(),t,2)},p:function(n){return g[+(n.getHours()>=12)]},S:function(n,t){return Zn(n.getSeconds(),t,2)},U:function(n,t){return Zn(ga.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return Zn(ga.mondayOfYear(n),t,2)},x:t(h),X:t(p),y:function(n,t){return Zn(n.getFullYear()%100,t,2)},Y:function(n,t){return Zn(n.getFullYear()%1e4,t,4)},Z:at,"%":function(){return"%"}},C={a:r,A:i,b:u,B:o,c:a,d:tt,e:tt,H:rt,I:rt,j:et,L:ot,m:nt,M:it,p:f,S:ut,U:Bn,w:$n,W:Wn,x:l,X:c,y:Gn,Y:Jn,Z:Kn,"%":lt};return t}function Zn(n,t,e){var r=0>n?"-":"",i=(r?-n:n)+"",u=i.length;return r+(e>u?new Array(e-u+1).join(t)+i:i)}function Vn(n){return new RegExp("^(?:"+n.map(ao.requote).join("|")+")","i")}function Xn(n){for(var t=new c,e=-1,r=n.length;++e<r;)t.set(n[e].toLowerCase(),e);return t}function $n(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+1));return r?(n.w=+r[0],e+r[0].length):-1}function Bn(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e));return r?(n.U=+r[0],e+r[0].length):-1}function Wn(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e));return r?(n.W=+r[0],e+r[0].length):-1}function Jn(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+4));return r?(n.y=+r[0],e+r[0].length):-1}function Gn(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.y=Qn(+r[0]),e+r[0].length):-1}function Kn(n,t,e){return/^[+-]\d{4}$/.test(t=t.slice(e,e+5))?(n.Z=-t,e+5):-1}function Qn(n){return n+(n>68?1900:2e3)}function nt(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.m=r[0]-1,e+r[0].length):-1}function tt(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.d=+r[0],e+r[0].length):-1}function et(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+3));return r?(n.j=+r[0],e+r[0].length):-1}function rt(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.H=+r[0],e+r[0].length):-1}function it(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.M=+r[0],e+r[0].length):-1}function ut(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.S=+r[0],e+r[0].length):-1}function ot(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+3));return r?(n.L=+r[0],e+r[0].length):-1}function at(n){var t=n.getTimezoneOffset(),e=t>0?"-":"+",r=xo(t)/60|0,i=xo(t)%60;return e+Zn(r,"0",2)+Zn(i,"0",2)}function lt(n,t,e){Ma.lastIndex=0;var r=Ma.exec(t.slice(e,e+1));return r?e+r[0].length:-1}function ct(n){for(var t=n.length,e=-1;++e<t;)n[e][0]=this(n[e][0]);return function(t){for(var e=0,r=n[e];!r[1](t);)r=n[++e];return r[0](t)}}function ft(){}function st(n,t,e){var r=e.s=n+t,i=r-n,u=r-i;e.t=n-u+(t-i)}function ht(n,t){n&&wa.hasOwnProperty(n.type)&&wa[n.type](n,t)}function pt(n,t,e){var r,i=-1,u=n.length-e;for(t.lineStart();++i<u;)r=n[i],t.point(r[0],r[1],r[2]);t.lineEnd()}function gt(n,t){var e=-1,r=n.length;for(t.polygonStart();++e<r;)pt(n[e],t,1);t.polygonEnd()}function vt(){function n(n,t){n*=Yo,t=t*Yo/2+Fo/4;var e=n-r,o=e>=0?1:-1,a=o*e,l=Math.cos(t),c=Math.sin(t),f=u*c,s=i*l+f*Math.cos(a),h=f*o*Math.sin(a);ka.add(Math.atan2(h,s)),r=n,i=l,u=c}var t,e,r,i,u;Na.point=function(o,a){Na.point=n,r=(t=o)*Yo,i=Math.cos(a=(e=a)*Yo/2+Fo/4),u=Math.sin(a)},Na.lineEnd=function(){n(t,e)}}function dt(n){var t=n[0],e=n[1],r=Math.cos(e);return[r*Math.cos(t),r*Math.sin(t),Math.sin(e)]}function yt(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function mt(n,t){return[n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1]-n[1]*t[0]]}function Mt(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function xt(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function bt(n){var t=Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);n[0]/=t,n[1]/=t,n[2]/=t}function _t(n){return[Math.atan2(n[1],n[0]),tn(n[2])]}function wt(n,t){return xo(n[0]-t[0])<Uo&&xo(n[1]-t[1])<Uo}function St(n,t){n*=Yo;var e=Math.cos(t*=Yo);kt(e*Math.cos(n),e*Math.sin(n),Math.sin(t))}function kt(n,t,e){++Ea,Ca+=(n-Ca)/Ea,za+=(t-za)/Ea,La+=(e-La)/Ea}function Nt(){function n(n,i){n*=Yo;var u=Math.cos(i*=Yo),o=u*Math.cos(n),a=u*Math.sin(n),l=Math.sin(i),c=Math.atan2(Math.sqrt((c=e*l-r*a)*c+(c=r*o-t*l)*c+(c=t*a-e*o)*c),t*o+e*a+r*l);Aa+=c,qa+=c*(t+(t=o)),Ta+=c*(e+(e=a)),Ra+=c*(r+(r=l)),kt(t,e,r)}var t,e,r;ja.point=function(i,u){i*=Yo;var o=Math.cos(u*=Yo);t=o*Math.cos(i),e=o*Math.sin(i),r=Math.sin(u),ja.point=n,kt(t,e,r)}}function Et(){ja.point=St}function At(){function n(n,t){n*=Yo;var e=Math.cos(t*=Yo),o=e*Math.cos(n),a=e*Math.sin(n),l=Math.sin(t),c=i*l-u*a,f=u*o-r*l,s=r*a-i*o,h=Math.sqrt(c*c+f*f+s*s),p=r*o+i*a+u*l,g=h&&-nn(p)/h,v=Math.atan2(h,p);Da+=g*c,Pa+=g*f,Ua+=g*s,Aa+=v,qa+=v*(r+(r=o)),Ta+=v*(i+(i=a)),Ra+=v*(u+(u=l)),kt(r,i,u)}var t,e,r,i,u;ja.point=function(o,a){t=o,e=a,ja.point=n,o*=Yo;var l=Math.cos(a*=Yo);r=l*Math.cos(o),i=l*Math.sin(o),u=Math.sin(a),kt(r,i,u)},ja.lineEnd=function(){n(t,e),ja.lineEnd=Et,ja.point=St}}function Ct(n,t){function e(e,r){return e=n(e,r),t(e[0],e[1])}return n.invert&&t.invert&&(e.invert=function(e,r){return e=t.invert(e,r),e&&n.invert(e[0],e[1])}),e}function zt(){return!0}function Lt(n,t,e,r,i){var u=[],o=[];if(n.forEach(function(n){if(!((t=n.length-1)<=0)){var t,e=n[0],r=n[t];if(wt(e,r)){i.lineStart();for(var a=0;t>a;++a)i.point((e=n[a])[0],e[1]);return void i.lineEnd()}var l=new Tt(e,n,null,!0),c=new Tt(e,null,l,!1);l.o=c,u.push(l),o.push(c),l=new Tt(r,n,null,!1),c=new Tt(r,null,l,!0),l.o=c,u.push(l),o.push(c)}}),o.sort(t),qt(u),qt(o),u.length){for(var a=0,l=e,c=o.length;c>a;++a)o[a].e=l=!l;for(var f,s,h=u[0];;){for(var p=h,g=!0;p.v;)if((p=p.n)===h)return;f=p.z,i.lineStart();do{if(p.v=p.o.v=!0,p.e){if(g)for(var a=0,c=f.length;c>a;++a)i.point((s=f[a])[0],s[1]);else r(p.x,p.n.x,1,i);p=p.n}else{if(g){f=p.p.z;for(var a=f.length-1;a>=0;--a)i.point((s=f[a])[0],s[1])}else r(p.x,p.p.x,-1,i);p=p.p}p=p.o,f=p.z,g=!g}while(!p.v);i.lineEnd()}}}function qt(n){if(t=n.length){for(var t,e,r=0,i=n[0];++r<t;)i.n=e=n[r],e.p=i,i=e;i.n=e=n[0],e.p=i}}function Tt(n,t,e,r){this.x=n,this.z=t,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Rt(n,t,e,r){return function(i,u){function o(t,e){var r=i(t,e);n(t=r[0],e=r[1])&&u.point(t,e)}function a(n,t){var e=i(n,t);d.point(e[0],e[1])}function l(){m.point=a,d.lineStart()}function c(){m.point=o,d.lineEnd()}function f(n,t){v.push([n,t]);var e=i(n,t);x.point(e[0],e[1])}function s(){x.lineStart(),v=[]}function h(){f(v[0][0],v[0][1]),x.lineEnd();var n,t=x.clean(),e=M.buffer(),r=e.length;if(v.pop(),g.push(v),v=null,r)if(1&t){n=e[0];var i,r=n.length-1,o=-1;if(r>0){for(b||(u.polygonStart(),b=!0),u.lineStart();++o<r;)u.point((i=n[o])[0],i[1]);u.lineEnd()}}else r>1&&2&t&&e.push(e.pop().concat(e.shift())),p.push(e.filter(Dt))}var p,g,v,d=t(u),y=i.invert(r[0],r[1]),m={point:o,lineStart:l,lineEnd:c,polygonStart:function(){m.point=f,m.lineStart=s,m.lineEnd=h,p=[],g=[]},polygonEnd:function(){m.point=o,m.lineStart=l,m.lineEnd=c,p=ao.merge(p);var n=Ot(y,g);p.length?(b||(u.polygonStart(),b=!0),Lt(p,Ut,n,e,u)):n&&(b||(u.polygonStart(),b=!0),u.lineStart(),e(null,null,1,u),u.lineEnd()),b&&(u.polygonEnd(),b=!1),p=g=null},sphere:function(){u.polygonStart(),u.lineStart(),e(null,null,1,u),u.lineEnd(),u.polygonEnd()}},M=Pt(),x=t(M),b=!1;return m}}function Dt(n){return n.length>1}function Pt(){var n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,e){n.push([t,e])},lineEnd:b,buffer:function(){var e=t;return t=[],n=null,e},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function Ut(n,t){return((n=n.x)[0]<0?n[1]-Io-Uo:Io-n[1])-((t=t.x)[0]<0?t[1]-Io-Uo:Io-t[1])}function jt(n){var t,e=NaN,r=NaN,i=NaN;return{lineStart:function(){n.lineStart(),t=1},point:function(u,o){var a=u>0?Fo:-Fo,l=xo(u-e);xo(l-Fo)<Uo?(n.point(e,r=(r+o)/2>0?Io:-Io),n.point(i,r),n.lineEnd(),n.lineStart(),n.point(a,r),n.point(u,r),t=0):i!==a&&l>=Fo&&(xo(e-i)<Uo&&(e-=i*Uo),xo(u-a)<Uo&&(u-=a*Uo),r=Ft(e,r,u,o),n.point(i,r),n.lineEnd(),n.lineStart(),n.point(a,r),t=0),n.point(e=u,r=o),i=a},lineEnd:function(){n.lineEnd(),e=r=NaN},clean:function(){return 2-t}}}function Ft(n,t,e,r){var i,u,o=Math.sin(n-e);return xo(o)>Uo?Math.atan((Math.sin(t)*(u=Math.cos(r))*Math.sin(e)-Math.sin(r)*(i=Math.cos(t))*Math.sin(n))/(i*u*o)):(t+r)/2}function Ht(n,t,e,r){var i;if(null==n)i=e*Io,r.point(-Fo,i),r.point(0,i),r.point(Fo,i),r.point(Fo,0),r.point(Fo,-i),r.point(0,-i),r.point(-Fo,-i),r.point(-Fo,0),r.point(-Fo,i);else if(xo(n[0]-t[0])>Uo){var u=n[0]<t[0]?Fo:-Fo;i=e*u/2,r.point(-u,i),r.point(0,i),r.point(u,i)}else r.point(t[0],t[1])}function Ot(n,t){var e=n[0],r=n[1],i=[Math.sin(e),-Math.cos(e),0],u=0,o=0;ka.reset();for(var a=0,l=t.length;l>a;++a){var c=t[a],f=c.length;if(f)for(var s=c[0],h=s[0],p=s[1]/2+Fo/4,g=Math.sin(p),v=Math.cos(p),d=1;;){d===f&&(d=0),n=c[d];var y=n[0],m=n[1]/2+Fo/4,M=Math.sin(m),x=Math.cos(m),b=y-h,_=b>=0?1:-1,w=_*b,S=w>Fo,k=g*M;if(ka.add(Math.atan2(k*_*Math.sin(w),v*x+k*Math.cos(w))),u+=S?b+_*Ho:b,S^h>=e^y>=e){var N=mt(dt(s),dt(n));bt(N);var E=mt(i,N);bt(E);var A=(S^b>=0?-1:1)*tn(E[2]);(r>A||r===A&&(N[0]||N[1]))&&(o+=S^b>=0?1:-1)}if(!d++)break;h=y,g=M,v=x,s=n}}return(-Uo>u||Uo>u&&-Uo>ka)^1&o}function It(n){function t(n,t){return Math.cos(n)*Math.cos(t)>u}function e(n){var e,u,l,c,f;return{lineStart:function(){c=l=!1,f=1},point:function(s,h){var p,g=[s,h],v=t(s,h),d=o?v?0:i(s,h):v?i(s+(0>s?Fo:-Fo),h):0;if(!e&&(c=l=v)&&n.lineStart(),v!==l&&(p=r(e,g),(wt(e,p)||wt(g,p))&&(g[0]+=Uo,g[1]+=Uo,v=t(g[0],g[1]))),v!==l)f=0,v?(n.lineStart(),p=r(g,e),n.point(p[0],p[1])):(p=r(e,g),n.point(p[0],p[1]),n.lineEnd()),e=p;else if(a&&e&&o^v){var y;d&u||!(y=r(g,e,!0))||(f=0,o?(n.lineStart(),n.point(y[0][0],y[0][1]),n.point(y[1][0],y[1][1]),n.lineEnd()):(n.point(y[1][0],y[1][1]),n.lineEnd(),n.lineStart(),n.point(y[0][0],y[0][1])))}!v||e&&wt(e,g)||n.point(g[0],g[1]),e=g,l=v,u=d},lineEnd:function(){l&&n.lineEnd(),e=null},clean:function(){return f|(c&&l)<<1}}}function r(n,t,e){var r=dt(n),i=dt(t),o=[1,0,0],a=mt(r,i),l=yt(a,a),c=a[0],f=l-c*c;if(!f)return!e&&n;var s=u*l/f,h=-u*c/f,p=mt(o,a),g=xt(o,s),v=xt(a,h);Mt(g,v);var d=p,y=yt(g,d),m=yt(d,d),M=y*y-m*(yt(g,g)-1);if(!(0>M)){var x=Math.sqrt(M),b=xt(d,(-y-x)/m);if(Mt(b,g),b=_t(b),!e)return b;var _,w=n[0],S=t[0],k=n[1],N=t[1];w>S&&(_=w,w=S,S=_);var E=S-w,A=xo(E-Fo)<Uo,C=A||Uo>E;if(!A&&k>N&&(_=k,k=N,N=_),C?A?k+N>0^b[1]<(xo(b[0]-w)<Uo?k:N):k<=b[1]&&b[1]<=N:E>Fo^(w<=b[0]&&b[0]<=S)){var z=xt(d,(-y+x)/m);return Mt(z,g),[b,_t(z)]}}}function i(t,e){var r=o?n:Fo-n,i=0;return-r>t?i|=1:t>r&&(i|=2),-r>e?i|=4:e>r&&(i|=8),i}var u=Math.cos(n),o=u>0,a=xo(u)>Uo,l=ve(n,6*Yo);return Rt(t,e,l,o?[0,-n]:[-Fo,n-Fo])}function Yt(n,t,e,r){return function(i){var u,o=i.a,a=i.b,l=o.x,c=o.y,f=a.x,s=a.y,h=0,p=1,g=f-l,v=s-c;if(u=n-l,g||!(u>0)){if(u/=g,0>g){if(h>u)return;p>u&&(p=u)}else if(g>0){if(u>p)return;u>h&&(h=u)}if(u=e-l,g||!(0>u)){if(u/=g,0>g){if(u>p)return;u>h&&(h=u)}else if(g>0){if(h>u)return;p>u&&(p=u)}if(u=t-c,v||!(u>0)){if(u/=v,0>v){if(h>u)return;p>u&&(p=u)}else if(v>0){if(u>p)return;u>h&&(h=u)}if(u=r-c,v||!(0>u)){if(u/=v,0>v){if(u>p)return;u>h&&(h=u)}else if(v>0){if(h>u)return;p>u&&(p=u)}return h>0&&(i.a={x:l+h*g,y:c+h*v}),1>p&&(i.b={x:l+p*g,y:c+p*v}),i}}}}}}function Zt(n,t,e,r){function i(r,i){return xo(r[0]-n)<Uo?i>0?0:3:xo(r[0]-e)<Uo?i>0?2:1:xo(r[1]-t)<Uo?i>0?1:0:i>0?3:2}function u(n,t){return o(n.x,t.x)}function o(n,t){var e=i(n,1),r=i(t,1);return e!==r?e-r:0===e?t[1]-n[1]:1===e?n[0]-t[0]:2===e?n[1]-t[1]:t[0]-n[0]}return function(a){function l(n){for(var t=0,e=d.length,r=n[1],i=0;e>i;++i)for(var u,o=1,a=d[i],l=a.length,c=a[0];l>o;++o)u=a[o],c[1]<=r?u[1]>r&&Q(c,u,n)>0&&++t:u[1]<=r&&Q(c,u,n)<0&&--t,c=u;return 0!==t}function c(u,a,l,c){var f=0,s=0;if(null==u||(f=i(u,l))!==(s=i(a,l))||o(u,a)<0^l>0){do c.point(0===f||3===f?n:e,f>1?r:t);while((f=(f+l+4)%4)!==s)}else c.point(a[0],a[1])}function f(i,u){return i>=n&&e>=i&&u>=t&&r>=u}function s(n,t){f(n,t)&&a.point(n,t)}function h(){C.point=g,d&&d.push(y=[]),S=!0,w=!1,b=_=NaN}function p(){v&&(g(m,M),x&&w&&E.rejoin(),v.push(E.buffer())),C.point=s,w&&a.lineEnd()}function g(n,t){n=Math.max(-Ha,Math.min(Ha,n)),t=Math.max(-Ha,Math.min(Ha,t));var e=f(n,t);if(d&&y.push([n,t]),S)m=n,M=t,x=e,S=!1,e&&(a.lineStart(),a.point(n,t));else if(e&&w)a.point(n,t);else{var r={a:{x:b,y:_},b:{x:n,y:t}};A(r)?(w||(a.lineStart(),a.point(r.a.x,r.a.y)),a.point(r.b.x,r.b.y),e||a.lineEnd(),k=!1):e&&(a.lineStart(),a.point(n,t),k=!1)}b=n,_=t,w=e}var v,d,y,m,M,x,b,_,w,S,k,N=a,E=Pt(),A=Yt(n,t,e,r),C={point:s,lineStart:h,lineEnd:p,polygonStart:function(){a=E,v=[],d=[],k=!0},polygonEnd:function(){a=N,v=ao.merge(v);var t=l([n,r]),e=k&&t,i=v.length;(e||i)&&(a.polygonStart(),e&&(a.lineStart(),c(null,null,1,a),a.lineEnd()),i&&Lt(v,u,t,c,a),a.polygonEnd()),v=d=y=null}};return C}}function Vt(n){var t=0,e=Fo/3,r=ae(n),i=r(t,e);return i.parallels=function(n){return arguments.length?r(t=n[0]*Fo/180,e=n[1]*Fo/180):[t/Fo*180,e/Fo*180]},i}function Xt(n,t){function e(n,t){var e=Math.sqrt(u-2*i*Math.sin(t))/i;return[e*Math.sin(n*=i),o-e*Math.cos(n)]}var r=Math.sin(n),i=(r+Math.sin(t))/2,u=1+r*(2*i-r),o=Math.sqrt(u)/i;return e.invert=function(n,t){var e=o-t;return[Math.atan2(n,e)/i,tn((u-(n*n+e*e)*i*i)/(2*i))]},e}function $t(){function n(n,t){Ia+=i*n-r*t,r=n,i=t}var t,e,r,i;$a.point=function(u,o){$a.point=n,t=r=u,e=i=o},$a.lineEnd=function(){n(t,e)}}function Bt(n,t){Ya>n&&(Ya=n),n>Va&&(Va=n),Za>t&&(Za=t),t>Xa&&(Xa=t)}function Wt(){function n(n,t){o.push("M",n,",",t,u)}function t(n,t){o.push("M",n,",",t),a.point=e}function e(n,t){o.push("L",n,",",t)}function r(){a.point=n}function i(){o.push("Z")}var u=Jt(4.5),o=[],a={point:n,lineStart:function(){a.point=t},lineEnd:r,polygonStart:function(){a.lineEnd=i},polygonEnd:function(){a.lineEnd=r,a.point=n},pointRadius:function(n){return u=Jt(n),a},result:function(){if(o.length){var n=o.join("");return o=[],n}}};return a}function Jt(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function Gt(n,t){Ca+=n,za+=t,++La}function Kt(){function n(n,r){var i=n-t,u=r-e,o=Math.sqrt(i*i+u*u);qa+=o*(t+n)/2,Ta+=o*(e+r)/2,Ra+=o,Gt(t=n,e=r)}var t,e;Wa.point=function(r,i){Wa.point=n,Gt(t=r,e=i)}}function Qt(){Wa.point=Gt}function ne(){function n(n,t){var e=n-r,u=t-i,o=Math.sqrt(e*e+u*u);qa+=o*(r+n)/2,Ta+=o*(i+t)/2,Ra+=o,o=i*n-r*t,Da+=o*(r+n),Pa+=o*(i+t),Ua+=3*o,Gt(r=n,i=t)}var t,e,r,i;Wa.point=function(u,o){Wa.point=n,Gt(t=r=u,e=i=o)},Wa.lineEnd=function(){n(t,e)}}function te(n){function t(t,e){n.moveTo(t+o,e),n.arc(t,e,o,0,Ho)}function e(t,e){n.moveTo(t,e),a.point=r}function r(t,e){n.lineTo(t,e)}function i(){a.point=t}function u(){n.closePath()}var o=4.5,a={point:t,lineStart:function(){a.point=e},lineEnd:i,polygonStart:function(){a.lineEnd=u},polygonEnd:function(){a.lineEnd=i,a.point=t},pointRadius:function(n){return o=n,a},result:b};return a}function ee(n){function t(n){return(a?r:e)(n)}function e(t){return ue(t,function(e,r){e=n(e,r),t.point(e[0],e[1])})}function r(t){function e(e,r){e=n(e,r),t.point(e[0],e[1])}function r(){M=NaN,S.point=u,t.lineStart()}function u(e,r){var u=dt([e,r]),o=n(e,r);i(M,x,m,b,_,w,M=o[0],x=o[1],m=e,b=u[0],_=u[1],w=u[2],a,t),t.point(M,x)}function o(){S.point=e,t.lineEnd()}function l(){
2
- r(),S.point=c,S.lineEnd=f}function c(n,t){u(s=n,h=t),p=M,g=x,v=b,d=_,y=w,S.point=u}function f(){i(M,x,m,b,_,w,p,g,s,v,d,y,a,t),S.lineEnd=o,o()}var s,h,p,g,v,d,y,m,M,x,b,_,w,S={point:e,lineStart:r,lineEnd:o,polygonStart:function(){t.polygonStart(),S.lineStart=l},polygonEnd:function(){t.polygonEnd(),S.lineStart=r}};return S}function i(t,e,r,a,l,c,f,s,h,p,g,v,d,y){var m=f-t,M=s-e,x=m*m+M*M;if(x>4*u&&d--){var b=a+p,_=l+g,w=c+v,S=Math.sqrt(b*b+_*_+w*w),k=Math.asin(w/=S),N=xo(xo(w)-1)<Uo||xo(r-h)<Uo?(r+h)/2:Math.atan2(_,b),E=n(N,k),A=E[0],C=E[1],z=A-t,L=C-e,q=M*z-m*L;(q*q/x>u||xo((m*z+M*L)/x-.5)>.3||o>a*p+l*g+c*v)&&(i(t,e,r,a,l,c,A,C,N,b/=S,_/=S,w,d,y),y.point(A,C),i(A,C,N,b,_,w,f,s,h,p,g,v,d,y))}}var u=.5,o=Math.cos(30*Yo),a=16;return t.precision=function(n){return arguments.length?(a=(u=n*n)>0&&16,t):Math.sqrt(u)},t}function re(n){var t=ee(function(t,e){return n([t*Zo,e*Zo])});return function(n){return le(t(n))}}function ie(n){this.stream=n}function ue(n,t){return{point:t,sphere:function(){n.sphere()},lineStart:function(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}function oe(n){return ae(function(){return n})()}function ae(n){function t(n){return n=a(n[0]*Yo,n[1]*Yo),[n[0]*h+l,c-n[1]*h]}function e(n){return n=a.invert((n[0]-l)/h,(c-n[1])/h),n&&[n[0]*Zo,n[1]*Zo]}function r(){a=Ct(o=se(y,M,x),u);var n=u(v,d);return l=p-n[0]*h,c=g+n[1]*h,i()}function i(){return f&&(f.valid=!1,f=null),t}var u,o,a,l,c,f,s=ee(function(n,t){return n=u(n,t),[n[0]*h+l,c-n[1]*h]}),h=150,p=480,g=250,v=0,d=0,y=0,M=0,x=0,b=Fa,_=m,w=null,S=null;return t.stream=function(n){return f&&(f.valid=!1),f=le(b(o,s(_(n)))),f.valid=!0,f},t.clipAngle=function(n){return arguments.length?(b=null==n?(w=n,Fa):It((w=+n)*Yo),i()):w},t.clipExtent=function(n){return arguments.length?(S=n,_=n?Zt(n[0][0],n[0][1],n[1][0],n[1][1]):m,i()):S},t.scale=function(n){return arguments.length?(h=+n,r()):h},t.translate=function(n){return arguments.length?(p=+n[0],g=+n[1],r()):[p,g]},t.center=function(n){return arguments.length?(v=n[0]%360*Yo,d=n[1]%360*Yo,r()):[v*Zo,d*Zo]},t.rotate=function(n){return arguments.length?(y=n[0]%360*Yo,M=n[1]%360*Yo,x=n.length>2?n[2]%360*Yo:0,r()):[y*Zo,M*Zo,x*Zo]},ao.rebind(t,s,"precision"),function(){return u=n.apply(this,arguments),t.invert=u.invert&&e,r()}}function le(n){return ue(n,function(t,e){n.point(t*Yo,e*Yo)})}function ce(n,t){return[n,t]}function fe(n,t){return[n>Fo?n-Ho:-Fo>n?n+Ho:n,t]}function se(n,t,e){return n?t||e?Ct(pe(n),ge(t,e)):pe(n):t||e?ge(t,e):fe}function he(n){return function(t,e){return t+=n,[t>Fo?t-Ho:-Fo>t?t+Ho:t,e]}}function pe(n){var t=he(n);return t.invert=he(-n),t}function ge(n,t){function e(n,t){var e=Math.cos(t),a=Math.cos(n)*e,l=Math.sin(n)*e,c=Math.sin(t),f=c*r+a*i;return[Math.atan2(l*u-f*o,a*r-c*i),tn(f*u+l*o)]}var r=Math.cos(n),i=Math.sin(n),u=Math.cos(t),o=Math.sin(t);return e.invert=function(n,t){var e=Math.cos(t),a=Math.cos(n)*e,l=Math.sin(n)*e,c=Math.sin(t),f=c*u-l*o;return[Math.atan2(l*u+c*o,a*r+f*i),tn(f*r-a*i)]},e}function ve(n,t){var e=Math.cos(n),r=Math.sin(n);return function(i,u,o,a){var l=o*t;null!=i?(i=de(e,i),u=de(e,u),(o>0?u>i:i>u)&&(i+=o*Ho)):(i=n+o*Ho,u=n-.5*l);for(var c,f=i;o>0?f>u:u>f;f-=l)a.point((c=_t([e,-r*Math.cos(f),-r*Math.sin(f)]))[0],c[1])}}function de(n,t){var e=dt(t);e[0]-=n,bt(e);var r=nn(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-Uo)%(2*Math.PI)}function ye(n,t,e){var r=ao.range(n,t-Uo,e).concat(t);return function(n){return r.map(function(t){return[n,t]})}}function me(n,t,e){var r=ao.range(n,t-Uo,e).concat(t);return function(n){return r.map(function(t){return[t,n]})}}function Me(n){return n.source}function xe(n){return n.target}function be(n,t,e,r){var i=Math.cos(t),u=Math.sin(t),o=Math.cos(r),a=Math.sin(r),l=i*Math.cos(n),c=i*Math.sin(n),f=o*Math.cos(e),s=o*Math.sin(e),h=2*Math.asin(Math.sqrt(on(r-t)+i*o*on(e-n))),p=1/Math.sin(h),g=h?function(n){var t=Math.sin(n*=h)*p,e=Math.sin(h-n)*p,r=e*l+t*f,i=e*c+t*s,o=e*u+t*a;return[Math.atan2(i,r)*Zo,Math.atan2(o,Math.sqrt(r*r+i*i))*Zo]}:function(){return[n*Zo,t*Zo]};return g.distance=h,g}function _e(){function n(n,i){var u=Math.sin(i*=Yo),o=Math.cos(i),a=xo((n*=Yo)-t),l=Math.cos(a);Ja+=Math.atan2(Math.sqrt((a=o*Math.sin(a))*a+(a=r*u-e*o*l)*a),e*u+r*o*l),t=n,e=u,r=o}var t,e,r;Ga.point=function(i,u){t=i*Yo,e=Math.sin(u*=Yo),r=Math.cos(u),Ga.point=n},Ga.lineEnd=function(){Ga.point=Ga.lineEnd=b}}function we(n,t){function e(t,e){var r=Math.cos(t),i=Math.cos(e),u=n(r*i);return[u*i*Math.sin(t),u*Math.sin(e)]}return e.invert=function(n,e){var r=Math.sqrt(n*n+e*e),i=t(r),u=Math.sin(i),o=Math.cos(i);return[Math.atan2(n*u,r*o),Math.asin(r&&e*u/r)]},e}function Se(n,t){function e(n,t){o>0?-Io+Uo>t&&(t=-Io+Uo):t>Io-Uo&&(t=Io-Uo);var e=o/Math.pow(i(t),u);return[e*Math.sin(u*n),o-e*Math.cos(u*n)]}var r=Math.cos(n),i=function(n){return Math.tan(Fo/4+n/2)},u=n===t?Math.sin(n):Math.log(r/Math.cos(t))/Math.log(i(t)/i(n)),o=r*Math.pow(i(n),u)/u;return u?(e.invert=function(n,t){var e=o-t,r=K(u)*Math.sqrt(n*n+e*e);return[Math.atan2(n,e)/u,2*Math.atan(Math.pow(o/r,1/u))-Io]},e):Ne}function ke(n,t){function e(n,t){var e=u-t;return[e*Math.sin(i*n),u-e*Math.cos(i*n)]}var r=Math.cos(n),i=n===t?Math.sin(n):(r-Math.cos(t))/(t-n),u=r/i+n;return xo(i)<Uo?ce:(e.invert=function(n,t){var e=u-t;return[Math.atan2(n,e)/i,u-K(i)*Math.sqrt(n*n+e*e)]},e)}function Ne(n,t){return[n,Math.log(Math.tan(Fo/4+t/2))]}function Ee(n){var t,e=oe(n),r=e.scale,i=e.translate,u=e.clipExtent;return e.scale=function(){var n=r.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.translate=function(){var n=i.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.clipExtent=function(n){var o=u.apply(e,arguments);if(o===e){if(t=null==n){var a=Fo*r(),l=i();u([[l[0]-a,l[1]-a],[l[0]+a,l[1]+a]])}}else t&&(o=null);return o},e.clipExtent(null)}function Ae(n,t){return[Math.log(Math.tan(Fo/4+t/2)),-n]}function Ce(n){return n[0]}function ze(n){return n[1]}function Le(n){for(var t=n.length,e=[0,1],r=2,i=2;t>i;i++){for(;r>1&&Q(n[e[r-2]],n[e[r-1]],n[i])<=0;)--r;e[r++]=i}return e.slice(0,r)}function qe(n,t){return n[0]-t[0]||n[1]-t[1]}function Te(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}function Re(n,t,e,r){var i=n[0],u=e[0],o=t[0]-i,a=r[0]-u,l=n[1],c=e[1],f=t[1]-l,s=r[1]-c,h=(a*(l-c)-s*(i-u))/(s*o-a*f);return[i+h*o,l+h*f]}function De(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}function Pe(){rr(this),this.edge=this.site=this.circle=null}function Ue(n){var t=cl.pop()||new Pe;return t.site=n,t}function je(n){Be(n),ol.remove(n),cl.push(n),rr(n)}function Fe(n){var t=n.circle,e=t.x,r=t.cy,i={x:e,y:r},u=n.P,o=n.N,a=[n];je(n);for(var l=u;l.circle&&xo(e-l.circle.x)<Uo&&xo(r-l.circle.cy)<Uo;)u=l.P,a.unshift(l),je(l),l=u;a.unshift(l),Be(l);for(var c=o;c.circle&&xo(e-c.circle.x)<Uo&&xo(r-c.circle.cy)<Uo;)o=c.N,a.push(c),je(c),c=o;a.push(c),Be(c);var f,s=a.length;for(f=1;s>f;++f)c=a[f],l=a[f-1],nr(c.edge,l.site,c.site,i);l=a[0],c=a[s-1],c.edge=Ke(l.site,c.site,null,i),$e(l),$e(c)}function He(n){for(var t,e,r,i,u=n.x,o=n.y,a=ol._;a;)if(r=Oe(a,o)-u,r>Uo)a=a.L;else{if(i=u-Ie(a,o),!(i>Uo)){r>-Uo?(t=a.P,e=a):i>-Uo?(t=a,e=a.N):t=e=a;break}if(!a.R){t=a;break}a=a.R}var l=Ue(n);if(ol.insert(t,l),t||e){if(t===e)return Be(t),e=Ue(t.site),ol.insert(l,e),l.edge=e.edge=Ke(t.site,l.site),$e(t),void $e(e);if(!e)return void(l.edge=Ke(t.site,l.site));Be(t),Be(e);var c=t.site,f=c.x,s=c.y,h=n.x-f,p=n.y-s,g=e.site,v=g.x-f,d=g.y-s,y=2*(h*d-p*v),m=h*h+p*p,M=v*v+d*d,x={x:(d*m-p*M)/y+f,y:(h*M-v*m)/y+s};nr(e.edge,c,g,x),l.edge=Ke(c,n,null,x),e.edge=Ke(n,g,null,x),$e(t),$e(e)}}function Oe(n,t){var e=n.site,r=e.x,i=e.y,u=i-t;if(!u)return r;var o=n.P;if(!o)return-(1/0);e=o.site;var a=e.x,l=e.y,c=l-t;if(!c)return a;var f=a-r,s=1/u-1/c,h=f/c;return s?(-h+Math.sqrt(h*h-2*s*(f*f/(-2*c)-l+c/2+i-u/2)))/s+r:(r+a)/2}function Ie(n,t){var e=n.N;if(e)return Oe(e,t);var r=n.site;return r.y===t?r.x:1/0}function Ye(n){this.site=n,this.edges=[]}function Ze(n){for(var t,e,r,i,u,o,a,l,c,f,s=n[0][0],h=n[1][0],p=n[0][1],g=n[1][1],v=ul,d=v.length;d--;)if(u=v[d],u&&u.prepare())for(a=u.edges,l=a.length,o=0;l>o;)f=a[o].end(),r=f.x,i=f.y,c=a[++o%l].start(),t=c.x,e=c.y,(xo(r-t)>Uo||xo(i-e)>Uo)&&(a.splice(o,0,new tr(Qe(u.site,f,xo(r-s)<Uo&&g-i>Uo?{x:s,y:xo(t-s)<Uo?e:g}:xo(i-g)<Uo&&h-r>Uo?{x:xo(e-g)<Uo?t:h,y:g}:xo(r-h)<Uo&&i-p>Uo?{x:h,y:xo(t-h)<Uo?e:p}:xo(i-p)<Uo&&r-s>Uo?{x:xo(e-p)<Uo?t:s,y:p}:null),u.site,null)),++l)}function Ve(n,t){return t.angle-n.angle}function Xe(){rr(this),this.x=this.y=this.arc=this.site=this.cy=null}function $e(n){var t=n.P,e=n.N;if(t&&e){var r=t.site,i=n.site,u=e.site;if(r!==u){var o=i.x,a=i.y,l=r.x-o,c=r.y-a,f=u.x-o,s=u.y-a,h=2*(l*s-c*f);if(!(h>=-jo)){var p=l*l+c*c,g=f*f+s*s,v=(s*p-c*g)/h,d=(l*g-f*p)/h,s=d+a,y=fl.pop()||new Xe;y.arc=n,y.site=i,y.x=v+o,y.y=s+Math.sqrt(v*v+d*d),y.cy=s,n.circle=y;for(var m=null,M=ll._;M;)if(y.y<M.y||y.y===M.y&&y.x<=M.x){if(!M.L){m=M.P;break}M=M.L}else{if(!M.R){m=M;break}M=M.R}ll.insert(m,y),m||(al=y)}}}}function Be(n){var t=n.circle;t&&(t.P||(al=t.N),ll.remove(t),fl.push(t),rr(t),n.circle=null)}function We(n){for(var t,e=il,r=Yt(n[0][0],n[0][1],n[1][0],n[1][1]),i=e.length;i--;)t=e[i],(!Je(t,n)||!r(t)||xo(t.a.x-t.b.x)<Uo&&xo(t.a.y-t.b.y)<Uo)&&(t.a=t.b=null,e.splice(i,1))}function Je(n,t){var e=n.b;if(e)return!0;var r,i,u=n.a,o=t[0][0],a=t[1][0],l=t[0][1],c=t[1][1],f=n.l,s=n.r,h=f.x,p=f.y,g=s.x,v=s.y,d=(h+g)/2,y=(p+v)/2;if(v===p){if(o>d||d>=a)return;if(h>g){if(u){if(u.y>=c)return}else u={x:d,y:l};e={x:d,y:c}}else{if(u){if(u.y<l)return}else u={x:d,y:c};e={x:d,y:l}}}else if(r=(h-g)/(v-p),i=y-r*d,-1>r||r>1)if(h>g){if(u){if(u.y>=c)return}else u={x:(l-i)/r,y:l};e={x:(c-i)/r,y:c}}else{if(u){if(u.y<l)return}else u={x:(c-i)/r,y:c};e={x:(l-i)/r,y:l}}else if(v>p){if(u){if(u.x>=a)return}else u={x:o,y:r*o+i};e={x:a,y:r*a+i}}else{if(u){if(u.x<o)return}else u={x:a,y:r*a+i};e={x:o,y:r*o+i}}return n.a=u,n.b=e,!0}function Ge(n,t){this.l=n,this.r=t,this.a=this.b=null}function Ke(n,t,e,r){var i=new Ge(n,t);return il.push(i),e&&nr(i,n,t,e),r&&nr(i,t,n,r),ul[n.i].edges.push(new tr(i,n,t)),ul[t.i].edges.push(new tr(i,t,n)),i}function Qe(n,t,e){var r=new Ge(n,null);return r.a=t,r.b=e,il.push(r),r}function nr(n,t,e,r){n.a||n.b?n.l===e?n.b=r:n.a=r:(n.a=r,n.l=t,n.r=e)}function tr(n,t,e){var r=n.a,i=n.b;this.edge=n,this.site=t,this.angle=e?Math.atan2(e.y-t.y,e.x-t.x):n.l===t?Math.atan2(i.x-r.x,r.y-i.y):Math.atan2(r.x-i.x,i.y-r.y)}function er(){this._=null}function rr(n){n.U=n.C=n.L=n.R=n.P=n.N=null}function ir(n,t){var e=t,r=t.R,i=e.U;i?i.L===e?i.L=r:i.R=r:n._=r,r.U=i,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function ur(n,t){var e=t,r=t.L,i=e.U;i?i.L===e?i.L=r:i.R=r:n._=r,r.U=i,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function or(n){for(;n.L;)n=n.L;return n}function ar(n,t){var e,r,i,u=n.sort(lr).pop();for(il=[],ul=new Array(n.length),ol=new er,ll=new er;;)if(i=al,u&&(!i||u.y<i.y||u.y===i.y&&u.x<i.x))u.x===e&&u.y===r||(ul[u.i]=new Ye(u),He(u),e=u.x,r=u.y),u=n.pop();else{if(!i)break;Fe(i.arc)}t&&(We(t),Ze(t));var o={cells:ul,edges:il};return ol=ll=il=ul=null,o}function lr(n,t){return t.y-n.y||t.x-n.x}function cr(n,t,e){return(n.x-e.x)*(t.y-n.y)-(n.x-t.x)*(e.y-n.y)}function fr(n){return n.x}function sr(n){return n.y}function hr(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function pr(n,t,e,r,i,u){if(!n(t,e,r,i,u)){var o=.5*(e+i),a=.5*(r+u),l=t.nodes;l[0]&&pr(n,l[0],e,r,o,a),l[1]&&pr(n,l[1],o,r,i,a),l[2]&&pr(n,l[2],e,a,o,u),l[3]&&pr(n,l[3],o,a,i,u)}}function gr(n,t,e,r,i,u,o){var a,l=1/0;return function c(n,f,s,h,p){if(!(f>u||s>o||r>h||i>p)){if(g=n.point){var g,v=t-n.x,d=e-n.y,y=v*v+d*d;if(l>y){var m=Math.sqrt(l=y);r=t-m,i=e-m,u=t+m,o=e+m,a=g}}for(var M=n.nodes,x=.5*(f+h),b=.5*(s+p),_=t>=x,w=e>=b,S=w<<1|_,k=S+4;k>S;++S)if(n=M[3&S])switch(3&S){case 0:c(n,f,s,x,b);break;case 1:c(n,x,s,h,b);break;case 2:c(n,f,b,x,p);break;case 3:c(n,x,b,h,p)}}}(n,r,i,u,o),a}function vr(n,t){n=ao.rgb(n),t=ao.rgb(t);var e=n.r,r=n.g,i=n.b,u=t.r-e,o=t.g-r,a=t.b-i;return function(n){return"#"+bn(Math.round(e+u*n))+bn(Math.round(r+o*n))+bn(Math.round(i+a*n))}}function dr(n,t){var e,r={},i={};for(e in n)e in t?r[e]=Mr(n[e],t[e]):i[e]=n[e];for(e in t)e in n||(i[e]=t[e]);return function(n){for(e in r)i[e]=r[e](n);return i}}function yr(n,t){return n=+n,t=+t,function(e){return n*(1-e)+t*e}}function mr(n,t){var e,r,i,u=hl.lastIndex=pl.lastIndex=0,o=-1,a=[],l=[];for(n+="",t+="";(e=hl.exec(n))&&(r=pl.exec(t));)(i=r.index)>u&&(i=t.slice(u,i),a[o]?a[o]+=i:a[++o]=i),(e=e[0])===(r=r[0])?a[o]?a[o]+=r:a[++o]=r:(a[++o]=null,l.push({i:o,x:yr(e,r)})),u=pl.lastIndex;return u<t.length&&(i=t.slice(u),a[o]?a[o]+=i:a[++o]=i),a.length<2?l[0]?(t=l[0].x,function(n){return t(n)+""}):function(){return t}:(t=l.length,function(n){for(var e,r=0;t>r;++r)a[(e=l[r]).i]=e.x(n);return a.join("")})}function Mr(n,t){for(var e,r=ao.interpolators.length;--r>=0&&!(e=ao.interpolators[r](n,t)););return e}function xr(n,t){var e,r=[],i=[],u=n.length,o=t.length,a=Math.min(n.length,t.length);for(e=0;a>e;++e)r.push(Mr(n[e],t[e]));for(;u>e;++e)i[e]=n[e];for(;o>e;++e)i[e]=t[e];return function(n){for(e=0;a>e;++e)i[e]=r[e](n);return i}}function br(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function _r(n){return function(t){return 1-n(1-t)}}function wr(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function Sr(n){return n*n}function kr(n){return n*n*n}function Nr(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,e=t*n;return 4*(.5>n?e:3*(n-t)+e-.75)}function Er(n){return function(t){return Math.pow(t,n)}}function Ar(n){return 1-Math.cos(n*Io)}function Cr(n){return Math.pow(2,10*(n-1))}function zr(n){return 1-Math.sqrt(1-n*n)}function Lr(n,t){var e;return arguments.length<2&&(t=.45),arguments.length?e=t/Ho*Math.asin(1/n):(n=1,e=t/4),function(r){return 1+n*Math.pow(2,-10*r)*Math.sin((r-e)*Ho/t)}}function qr(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function Tr(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375}function Rr(n,t){n=ao.hcl(n),t=ao.hcl(t);var e=n.h,r=n.c,i=n.l,u=t.h-e,o=t.c-r,a=t.l-i;return isNaN(o)&&(o=0,r=isNaN(r)?t.c:r),isNaN(u)?(u=0,e=isNaN(e)?t.h:e):u>180?u-=360:-180>u&&(u+=360),function(n){return sn(e+u*n,r+o*n,i+a*n)+""}}function Dr(n,t){n=ao.hsl(n),t=ao.hsl(t);var e=n.h,r=n.s,i=n.l,u=t.h-e,o=t.s-r,a=t.l-i;return isNaN(o)&&(o=0,r=isNaN(r)?t.s:r),isNaN(u)?(u=0,e=isNaN(e)?t.h:e):u>180?u-=360:-180>u&&(u+=360),function(n){return cn(e+u*n,r+o*n,i+a*n)+""}}function Pr(n,t){n=ao.lab(n),t=ao.lab(t);var e=n.l,r=n.a,i=n.b,u=t.l-e,o=t.a-r,a=t.b-i;return function(n){return pn(e+u*n,r+o*n,i+a*n)+""}}function Ur(n,t){return t-=n,function(e){return Math.round(n+t*e)}}function jr(n){var t=[n.a,n.b],e=[n.c,n.d],r=Hr(t),i=Fr(t,e),u=Hr(Or(e,t,-i))||0;t[0]*e[1]<e[0]*t[1]&&(t[0]*=-1,t[1]*=-1,r*=-1,i*=-1),this.rotate=(r?Math.atan2(t[1],t[0]):Math.atan2(-e[0],e[1]))*Zo,this.translate=[n.e,n.f],this.scale=[r,u],this.skew=u?Math.atan2(i,u)*Zo:0}function Fr(n,t){return n[0]*t[0]+n[1]*t[1]}function Hr(n){var t=Math.sqrt(Fr(n,n));return t&&(n[0]/=t,n[1]/=t),t}function Or(n,t,e){return n[0]+=e*t[0],n[1]+=e*t[1],n}function Ir(n){return n.length?n.pop()+",":""}function Yr(n,t,e,r){if(n[0]!==t[0]||n[1]!==t[1]){var i=e.push("translate(",null,",",null,")");r.push({i:i-4,x:yr(n[0],t[0])},{i:i-2,x:yr(n[1],t[1])})}else(t[0]||t[1])&&e.push("translate("+t+")")}function Zr(n,t,e,r){n!==t?(n-t>180?t+=360:t-n>180&&(n+=360),r.push({i:e.push(Ir(e)+"rotate(",null,")")-2,x:yr(n,t)})):t&&e.push(Ir(e)+"rotate("+t+")")}function Vr(n,t,e,r){n!==t?r.push({i:e.push(Ir(e)+"skewX(",null,")")-2,x:yr(n,t)}):t&&e.push(Ir(e)+"skewX("+t+")")}function Xr(n,t,e,r){if(n[0]!==t[0]||n[1]!==t[1]){var i=e.push(Ir(e)+"scale(",null,",",null,")");r.push({i:i-4,x:yr(n[0],t[0])},{i:i-2,x:yr(n[1],t[1])})}else 1===t[0]&&1===t[1]||e.push(Ir(e)+"scale("+t+")")}function $r(n,t){var e=[],r=[];return n=ao.transform(n),t=ao.transform(t),Yr(n.translate,t.translate,e,r),Zr(n.rotate,t.rotate,e,r),Vr(n.skew,t.skew,e,r),Xr(n.scale,t.scale,e,r),n=t=null,function(n){for(var t,i=-1,u=r.length;++i<u;)e[(t=r[i]).i]=t.x(n);return e.join("")}}function Br(n,t){return t=(t-=n=+n)||1/t,function(e){return(e-n)/t}}function Wr(n,t){return t=(t-=n=+n)||1/t,function(e){return Math.max(0,Math.min(1,(e-n)/t))}}function Jr(n){for(var t=n.source,e=n.target,r=Kr(t,e),i=[t];t!==r;)t=t.parent,i.push(t);for(var u=i.length;e!==r;)i.splice(u,0,e),e=e.parent;return i}function Gr(n){for(var t=[],e=n.parent;null!=e;)t.push(n),n=e,e=e.parent;return t.push(n),t}function Kr(n,t){if(n===t)return n;for(var e=Gr(n),r=Gr(t),i=e.pop(),u=r.pop(),o=null;i===u;)o=i,i=e.pop(),u=r.pop();return o}function Qr(n){n.fixed|=2}function ni(n){n.fixed&=-7}function ti(n){n.fixed|=4,n.px=n.x,n.py=n.y}function ei(n){n.fixed&=-5}function ri(n,t,e){var r=0,i=0;if(n.charge=0,!n.leaf)for(var u,o=n.nodes,a=o.length,l=-1;++l<a;)u=o[l],null!=u&&(ri(u,t,e),n.charge+=u.charge,r+=u.charge*u.cx,i+=u.charge*u.cy);if(n.point){n.leaf||(n.point.x+=Math.random()-.5,n.point.y+=Math.random()-.5);var c=t*e[n.point.index];n.charge+=n.pointCharge=c,r+=c*n.point.x,i+=c*n.point.y}n.cx=r/n.charge,n.cy=i/n.charge}function ii(n,t){return ao.rebind(n,t,"sort","children","value"),n.nodes=n,n.links=fi,n}function ui(n,t){for(var e=[n];null!=(n=e.pop());)if(t(n),(i=n.children)&&(r=i.length))for(var r,i;--r>=0;)e.push(i[r])}function oi(n,t){for(var e=[n],r=[];null!=(n=e.pop());)if(r.push(n),(u=n.children)&&(i=u.length))for(var i,u,o=-1;++o<i;)e.push(u[o]);for(;null!=(n=r.pop());)t(n)}function ai(n){return n.children}function li(n){return n.value}function ci(n,t){return t.value-n.value}function fi(n){return ao.merge(n.map(function(n){return(n.children||[]).map(function(t){return{source:n,target:t}})}))}function si(n){return n.x}function hi(n){return n.y}function pi(n,t,e){n.y0=t,n.y=e}function gi(n){return ao.range(n.length)}function vi(n){for(var t=-1,e=n[0].length,r=[];++t<e;)r[t]=0;return r}function di(n){for(var t,e=1,r=0,i=n[0][1],u=n.length;u>e;++e)(t=n[e][1])>i&&(r=e,i=t);return r}function yi(n){return n.reduce(mi,0)}function mi(n,t){return n+t[1]}function Mi(n,t){return xi(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function xi(n,t){for(var e=-1,r=+n[0],i=(n[1]-r)/t,u=[];++e<=t;)u[e]=i*e+r;return u}function bi(n){return[ao.min(n),ao.max(n)]}function _i(n,t){return n.value-t.value}function wi(n,t){var e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function Si(n,t){n._pack_next=t,t._pack_prev=n}function ki(n,t){var e=t.x-n.x,r=t.y-n.y,i=n.r+t.r;return.999*i*i>e*e+r*r}function Ni(n){function t(n){f=Math.min(n.x-n.r,f),s=Math.max(n.x+n.r,s),h=Math.min(n.y-n.r,h),p=Math.max(n.y+n.r,p)}if((e=n.children)&&(c=e.length)){var e,r,i,u,o,a,l,c,f=1/0,s=-(1/0),h=1/0,p=-(1/0);if(e.forEach(Ei),r=e[0],r.x=-r.r,r.y=0,t(r),c>1&&(i=e[1],i.x=i.r,i.y=0,t(i),c>2))for(u=e[2],zi(r,i,u),t(u),wi(r,u),r._pack_prev=u,wi(u,i),i=r._pack_next,o=3;c>o;o++){zi(r,i,u=e[o]);var g=0,v=1,d=1;for(a=i._pack_next;a!==i;a=a._pack_next,v++)if(ki(a,u)){g=1;break}if(1==g)for(l=r._pack_prev;l!==a._pack_prev&&!ki(l,u);l=l._pack_prev,d++);g?(d>v||v==d&&i.r<r.r?Si(r,i=a):Si(r=l,i),o--):(wi(r,u),i=u,t(u))}var y=(f+s)/2,m=(h+p)/2,M=0;for(o=0;c>o;o++)u=e[o],u.x-=y,u.y-=m,M=Math.max(M,u.r+Math.sqrt(u.x*u.x+u.y*u.y));n.r=M,e.forEach(Ai)}}function Ei(n){n._pack_next=n._pack_prev=n}function Ai(n){delete n._pack_next,delete n._pack_prev}function Ci(n,t,e,r){var i=n.children;if(n.x=t+=r*n.x,n.y=e+=r*n.y,n.r*=r,i)for(var u=-1,o=i.length;++u<o;)Ci(i[u],t,e,r)}function zi(n,t,e){var r=n.r+e.r,i=t.x-n.x,u=t.y-n.y;if(r&&(i||u)){var o=t.r+e.r,a=i*i+u*u;o*=o,r*=r;var l=.5+(r-o)/(2*a),c=Math.sqrt(Math.max(0,2*o*(r+a)-(r-=a)*r-o*o))/(2*a);e.x=n.x+l*i+c*u,e.y=n.y+l*u-c*i}else e.x=n.x+r,e.y=n.y}function Li(n,t){return n.parent==t.parent?1:2}function qi(n){var t=n.children;return t.length?t[0]:n.t}function Ti(n){var t,e=n.children;return(t=e.length)?e[t-1]:n.t}function Ri(n,t,e){var r=e/(t.i-n.i);t.c-=r,t.s+=e,n.c+=r,t.z+=e,t.m+=e}function Di(n){for(var t,e=0,r=0,i=n.children,u=i.length;--u>=0;)t=i[u],t.z+=e,t.m+=e,e+=t.s+(r+=t.c)}function Pi(n,t,e){return n.a.parent===t.parent?n.a:e}function Ui(n){return 1+ao.max(n,function(n){return n.y})}function ji(n){return n.reduce(function(n,t){return n+t.x},0)/n.length}function Fi(n){var t=n.children;return t&&t.length?Fi(t[0]):n}function Hi(n){var t,e=n.children;return e&&(t=e.length)?Hi(e[t-1]):n}function Oi(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}function Ii(n,t){var e=n.x+t[3],r=n.y+t[0],i=n.dx-t[1]-t[3],u=n.dy-t[0]-t[2];return 0>i&&(e+=i/2,i=0),0>u&&(r+=u/2,u=0),{x:e,y:r,dx:i,dy:u}}function Yi(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function Zi(n){return n.rangeExtent?n.rangeExtent():Yi(n.range())}function Vi(n,t,e,r){var i=e(n[0],n[1]),u=r(t[0],t[1]);return function(n){return u(i(n))}}function Xi(n,t){var e,r=0,i=n.length-1,u=n[r],o=n[i];return u>o&&(e=r,r=i,i=e,e=u,u=o,o=e),n[r]=t.floor(u),n[i]=t.ceil(o),n}function $i(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:Sl}function Bi(n,t,e,r){var i=[],u=[],o=0,a=Math.min(n.length,t.length)-1;for(n[a]<n[0]&&(n=n.slice().reverse(),t=t.slice().reverse());++o<=a;)i.push(e(n[o-1],n[o])),u.push(r(t[o-1],t[o]));return function(t){var e=ao.bisect(n,t,1,a)-1;return u[e](i[e](t))}}function Wi(n,t,e,r){function i(){var i=Math.min(n.length,t.length)>2?Bi:Vi,l=r?Wr:Br;return o=i(n,t,l,e),a=i(t,n,l,Mr),u}function u(n){return o(n)}var o,a;return u.invert=function(n){return a(n)},u.domain=function(t){return arguments.length?(n=t.map(Number),i()):n},u.range=function(n){return arguments.length?(t=n,i()):t},u.rangeRound=function(n){return u.range(n).interpolate(Ur)},u.clamp=function(n){return arguments.length?(r=n,i()):r},u.interpolate=function(n){return arguments.length?(e=n,i()):e},u.ticks=function(t){return Qi(n,t)},u.tickFormat=function(t,e){return nu(n,t,e)},u.nice=function(t){return Gi(n,t),i()},u.copy=function(){return Wi(n,t,e,r)},i()}function Ji(n,t){return ao.rebind(n,t,"range","rangeRound","interpolate","clamp")}function Gi(n,t){return Xi(n,$i(Ki(n,t)[2])),Xi(n,$i(Ki(n,t)[2])),n}function Ki(n,t){null==t&&(t=10);var e=Yi(n),r=e[1]-e[0],i=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),u=t/r*i;return.15>=u?i*=10:.35>=u?i*=5:.75>=u&&(i*=2),e[0]=Math.ceil(e[0]/i)*i,e[1]=Math.floor(e[1]/i)*i+.5*i,e[2]=i,e}function Qi(n,t){return ao.range.apply(ao,Ki(n,t))}function nu(n,t,e){var r=Ki(n,t);if(e){var i=ha.exec(e);if(i.shift(),"s"===i[8]){var u=ao.formatPrefix(Math.max(xo(r[0]),xo(r[1])));return i[7]||(i[7]="."+tu(u.scale(r[2]))),i[8]="f",e=ao.format(i.join("")),function(n){return e(u.scale(n))+u.symbol}}i[7]||(i[7]="."+eu(i[8],r)),e=i.join("")}else e=",."+tu(r[2])+"f";return ao.format(e)}function tu(n){return-Math.floor(Math.log(n)/Math.LN10+.01)}function eu(n,t){var e=tu(t[2]);return n in kl?Math.abs(e-tu(Math.max(xo(t[0]),xo(t[1]))))+ +("e"!==n):e-2*("%"===n)}function ru(n,t,e,r){function i(n){return(e?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function u(n){return e?Math.pow(t,n):-Math.pow(t,-n)}function o(t){return n(i(t))}return o.invert=function(t){return u(n.invert(t))},o.domain=function(t){return arguments.length?(e=t[0]>=0,n.domain((r=t.map(Number)).map(i)),o):r},o.base=function(e){return arguments.length?(t=+e,n.domain(r.map(i)),o):t},o.nice=function(){var t=Xi(r.map(i),e?Math:El);return n.domain(t),r=t.map(u),o},o.ticks=function(){var n=Yi(r),o=[],a=n[0],l=n[1],c=Math.floor(i(a)),f=Math.ceil(i(l)),s=t%1?2:t;if(isFinite(f-c)){if(e){for(;f>c;c++)for(var h=1;s>h;h++)o.push(u(c)*h);o.push(u(c))}else for(o.push(u(c));c++<f;)for(var h=s-1;h>0;h--)o.push(u(c)*h);for(c=0;o[c]<a;c++);for(f=o.length;o[f-1]>l;f--);o=o.slice(c,f)}return o},o.tickFormat=function(n,e){if(!arguments.length)return Nl;arguments.length<2?e=Nl:"function"!=typeof e&&(e=ao.format(e));var r=Math.max(1,t*n/o.ticks().length);return function(n){var o=n/u(Math.round(i(n)));return t-.5>o*t&&(o*=t),r>=o?e(n):""}},o.copy=function(){return ru(n.copy(),t,e,r)},Ji(o,n)}function iu(n,t,e){function r(t){return n(i(t))}var i=uu(t),u=uu(1/t);return r.invert=function(t){return u(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain((e=t.map(Number)).map(i)),r):e},r.ticks=function(n){return Qi(e,n)},r.tickFormat=function(n,t){return nu(e,n,t)},r.nice=function(n){return r.domain(Gi(e,n))},r.exponent=function(o){return arguments.length?(i=uu(t=o),u=uu(1/t),n.domain(e.map(i)),r):t},r.copy=function(){return iu(n.copy(),t,e)},Ji(r,n)}function uu(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function ou(n,t){function e(e){return u[((i.get(e)||("range"===t.t?i.set(e,n.push(e)):NaN))-1)%u.length]}function r(t,e){return ao.range(n.length).map(function(n){return t+e*n})}var i,u,o;return e.domain=function(r){if(!arguments.length)return n;n=[],i=new c;for(var u,o=-1,a=r.length;++o<a;)i.has(u=r[o])||i.set(u,n.push(u));return e[t.t].apply(e,t.a)},e.range=function(n){return arguments.length?(u=n,o=0,t={t:"range",a:arguments},e):u},e.rangePoints=function(i,a){arguments.length<2&&(a=0);var l=i[0],c=i[1],f=n.length<2?(l=(l+c)/2,0):(c-l)/(n.length-1+a);return u=r(l+f*a/2,f),o=0,t={t:"rangePoints",a:arguments},e},e.rangeRoundPoints=function(i,a){arguments.length<2&&(a=0);var l=i[0],c=i[1],f=n.length<2?(l=c=Math.round((l+c)/2),0):(c-l)/(n.length-1+a)|0;return u=r(l+Math.round(f*a/2+(c-l-(n.length-1+a)*f)/2),f),o=0,t={t:"rangeRoundPoints",a:arguments},e},e.rangeBands=function(i,a,l){arguments.length<2&&(a=0),arguments.length<3&&(l=a);var c=i[1]<i[0],f=i[c-0],s=i[1-c],h=(s-f)/(n.length-a+2*l);return u=r(f+h*l,h),c&&u.reverse(),o=h*(1-a),t={t:"rangeBands",a:arguments},e},e.rangeRoundBands=function(i,a,l){arguments.length<2&&(a=0),arguments.length<3&&(l=a);var c=i[1]<i[0],f=i[c-0],s=i[1-c],h=Math.floor((s-f)/(n.length-a+2*l));return u=r(f+Math.round((s-f-(n.length-a)*h)/2),h),c&&u.reverse(),o=Math.round(h*(1-a)),t={t:"rangeRoundBands",a:arguments},e},e.rangeBand=function(){return o},e.rangeExtent=function(){return Yi(t.a[0])},e.copy=function(){return ou(n,t)},e.domain(n)}function au(n,t){function u(){var e=0,r=t.length;for(a=[];++e<r;)a[e-1]=ao.quantile(n,e/r);return o}function o(n){return isNaN(n=+n)?void 0:t[ao.bisect(a,n)]}var a;return o.domain=function(t){return arguments.length?(n=t.map(r).filter(i).sort(e),u()):n},o.range=function(n){return arguments.length?(t=n,u()):t},o.quantiles=function(){return a},o.invertExtent=function(e){return e=t.indexOf(e),0>e?[NaN,NaN]:[e>0?a[e-1]:n[0],e<a.length?a[e]:n[n.length-1]]},o.copy=function(){return au(n,t)},u()}function lu(n,t,e){function r(t){return e[Math.max(0,Math.min(o,Math.floor(u*(t-n))))]}function i(){return u=e.length/(t-n),o=e.length-1,r}var u,o;return r.domain=function(e){return arguments.length?(n=+e[0],t=+e[e.length-1],i()):[n,t]},r.range=function(n){return arguments.length?(e=n,i()):e},r.invertExtent=function(t){return t=e.indexOf(t),t=0>t?NaN:t/u+n,[t,t+1/u]},r.copy=function(){return lu(n,t,e)},i()}function cu(n,t){function e(e){return e>=e?t[ao.bisect(n,e)]:void 0}return e.domain=function(t){return arguments.length?(n=t,e):n},e.range=function(n){return arguments.length?(t=n,e):t},e.invertExtent=function(e){return e=t.indexOf(e),[n[e-1],n[e]]},e.copy=function(){return cu(n,t)},e}function fu(n){function t(n){return+n}return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=e.map(t),t):n},t.ticks=function(t){return Qi(n,t)},t.tickFormat=function(t,e){return nu(n,t,e)},t.copy=function(){return fu(n)},t}function su(){return 0}function hu(n){return n.innerRadius}function pu(n){return n.outerRadius}function gu(n){return n.startAngle}function vu(n){return n.endAngle}function du(n){return n&&n.padAngle}function yu(n,t,e,r){return(n-e)*t-(t-r)*n>0?0:1}function mu(n,t,e,r,i){var u=n[0]-t[0],o=n[1]-t[1],a=(i?r:-r)/Math.sqrt(u*u+o*o),l=a*o,c=-a*u,f=n[0]+l,s=n[1]+c,h=t[0]+l,p=t[1]+c,g=(f+h)/2,v=(s+p)/2,d=h-f,y=p-s,m=d*d+y*y,M=e-r,x=f*p-h*s,b=(0>y?-1:1)*Math.sqrt(Math.max(0,M*M*m-x*x)),_=(x*y-d*b)/m,w=(-x*d-y*b)/m,S=(x*y+d*b)/m,k=(-x*d+y*b)/m,N=_-g,E=w-v,A=S-g,C=k-v;return N*N+E*E>A*A+C*C&&(_=S,w=k),[[_-l,w-c],[_*e/M,w*e/M]]}function Mu(n){function t(t){function o(){c.push("M",u(n(f),a))}for(var l,c=[],f=[],s=-1,h=t.length,p=En(e),g=En(r);++s<h;)i.call(this,l=t[s],s)?f.push([+p.call(this,l,s),+g.call(this,l,s)]):f.length&&(o(),f=[]);return f.length&&o(),c.length?c.join(""):null}var e=Ce,r=ze,i=zt,u=xu,o=u.key,a=.7;return t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t.defined=function(n){return arguments.length?(i=n,t):i},t.interpolate=function(n){return arguments.length?(o="function"==typeof n?u=n:(u=Tl.get(n)||xu).key,t):o},t.tension=function(n){return arguments.length?(a=n,t):a},t}function xu(n){return n.length>1?n.join("L"):n+"Z"}function bu(n){return n.join("L")+"Z"}function _u(n){for(var t=0,e=n.length,r=n[0],i=[r[0],",",r[1]];++t<e;)i.push("H",(r[0]+(r=n[t])[0])/2,"V",r[1]);return e>1&&i.push("H",r[0]),i.join("")}function wu(n){for(var t=0,e=n.length,r=n[0],i=[r[0],",",r[1]];++t<e;)i.push("V",(r=n[t])[1],"H",r[0]);return i.join("")}function Su(n){for(var t=0,e=n.length,r=n[0],i=[r[0],",",r[1]];++t<e;)i.push("H",(r=n[t])[0],"V",r[1]);return i.join("")}function ku(n,t){return n.length<4?xu(n):n[1]+Au(n.slice(1,-1),Cu(n,t))}function Nu(n,t){return n.length<3?bu(n):n[0]+Au((n.push(n[0]),n),Cu([n[n.length-2]].concat(n,[n[1]]),t))}function Eu(n,t){return n.length<3?xu(n):n[0]+Au(n,Cu(n,t))}function Au(n,t){if(t.length<1||n.length!=t.length&&n.length!=t.length+2)return xu(n);var e=n.length!=t.length,r="",i=n[0],u=n[1],o=t[0],a=o,l=1;if(e&&(r+="Q"+(u[0]-2*o[0]/3)+","+(u[1]-2*o[1]/3)+","+u[0]+","+u[1],i=n[1],l=2),t.length>1){a=t[1],u=n[l],l++,r+="C"+(i[0]+o[0])+","+(i[1]+o[1])+","+(u[0]-a[0])+","+(u[1]-a[1])+","+u[0]+","+u[1];for(var c=2;c<t.length;c++,l++)u=n[l],a=t[c],r+="S"+(u[0]-a[0])+","+(u[1]-a[1])+","+u[0]+","+u[1]}if(e){var f=n[l];r+="Q"+(u[0]+2*a[0]/3)+","+(u[1]+2*a[1]/3)+","+f[0]+","+f[1]}return r}function Cu(n,t){for(var e,r=[],i=(1-t)/2,u=n[0],o=n[1],a=1,l=n.length;++a<l;)e=u,u=o,o=n[a],r.push([i*(o[0]-e[0]),i*(o[1]-e[1])]);return r}function zu(n){if(n.length<3)return xu(n);var t=1,e=n.length,r=n[0],i=r[0],u=r[1],o=[i,i,i,(r=n[1])[0]],a=[u,u,u,r[1]],l=[i,",",u,"L",Ru(Pl,o),",",Ru(Pl,a)];for(n.push(n[e-1]);++t<=e;)r=n[t],o.shift(),o.push(r[0]),a.shift(),a.push(r[1]),Du(l,o,a);return n.pop(),l.push("L",r),l.join("")}function Lu(n){if(n.length<4)return xu(n);for(var t,e=[],r=-1,i=n.length,u=[0],o=[0];++r<3;)t=n[r],u.push(t[0]),o.push(t[1]);for(e.push(Ru(Pl,u)+","+Ru(Pl,o)),--r;++r<i;)t=n[r],u.shift(),u.push(t[0]),o.shift(),o.push(t[1]),Du(e,u,o);return e.join("")}function qu(n){for(var t,e,r=-1,i=n.length,u=i+4,o=[],a=[];++r<4;)e=n[r%i],o.push(e[0]),a.push(e[1]);for(t=[Ru(Pl,o),",",Ru(Pl,a)],--r;++r<u;)e=n[r%i],o.shift(),o.push(e[0]),a.shift(),a.push(e[1]),Du(t,o,a);return t.join("")}function Tu(n,t){var e=n.length-1;if(e)for(var r,i,u=n[0][0],o=n[0][1],a=n[e][0]-u,l=n[e][1]-o,c=-1;++c<=e;)r=n[c],i=c/e,r[0]=t*r[0]+(1-t)*(u+i*a),r[1]=t*r[1]+(1-t)*(o+i*l);return zu(n)}function Ru(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]+n[3]*t[3]}function Du(n,t,e){n.push("C",Ru(Rl,t),",",Ru(Rl,e),",",Ru(Dl,t),",",Ru(Dl,e),",",Ru(Pl,t),",",Ru(Pl,e))}function Pu(n,t){return(t[1]-n[1])/(t[0]-n[0])}function Uu(n){for(var t=0,e=n.length-1,r=[],i=n[0],u=n[1],o=r[0]=Pu(i,u);++t<e;)r[t]=(o+(o=Pu(i=u,u=n[t+1])))/2;return r[t]=o,r}function ju(n){for(var t,e,r,i,u=[],o=Uu(n),a=-1,l=n.length-1;++a<l;)t=Pu(n[a],n[a+1]),xo(t)<Uo?o[a]=o[a+1]=0:(e=o[a]/t,r=o[a+1]/t,i=e*e+r*r,i>9&&(i=3*t/Math.sqrt(i),o[a]=i*e,o[a+1]=i*r));for(a=-1;++a<=l;)i=(n[Math.min(l,a+1)][0]-n[Math.max(0,a-1)][0])/(6*(1+o[a]*o[a])),u.push([i||0,o[a]*i||0]);return u}function Fu(n){return n.length<3?xu(n):n[0]+Au(n,ju(n))}function Hu(n){for(var t,e,r,i=-1,u=n.length;++i<u;)t=n[i],e=t[0],r=t[1]-Io,t[0]=e*Math.cos(r),t[1]=e*Math.sin(r);return n}function Ou(n){function t(t){function l(){v.push("M",a(n(y),s),f,c(n(d.reverse()),s),"Z")}for(var h,p,g,v=[],d=[],y=[],m=-1,M=t.length,x=En(e),b=En(i),_=e===r?function(){
3
- return p}:En(r),w=i===u?function(){return g}:En(u);++m<M;)o.call(this,h=t[m],m)?(d.push([p=+x.call(this,h,m),g=+b.call(this,h,m)]),y.push([+_.call(this,h,m),+w.call(this,h,m)])):d.length&&(l(),d=[],y=[]);return d.length&&l(),v.length?v.join(""):null}var e=Ce,r=Ce,i=0,u=ze,o=zt,a=xu,l=a.key,c=a,f="L",s=.7;return t.x=function(n){return arguments.length?(e=r=n,t):r},t.x0=function(n){return arguments.length?(e=n,t):e},t.x1=function(n){return arguments.length?(r=n,t):r},t.y=function(n){return arguments.length?(i=u=n,t):u},t.y0=function(n){return arguments.length?(i=n,t):i},t.y1=function(n){return arguments.length?(u=n,t):u},t.defined=function(n){return arguments.length?(o=n,t):o},t.interpolate=function(n){return arguments.length?(l="function"==typeof n?a=n:(a=Tl.get(n)||xu).key,c=a.reverse||a,f=a.closed?"M":"L",t):l},t.tension=function(n){return arguments.length?(s=n,t):s},t}function Iu(n){return n.radius}function Yu(n){return[n.x,n.y]}function Zu(n){return function(){var t=n.apply(this,arguments),e=t[0],r=t[1]-Io;return[e*Math.cos(r),e*Math.sin(r)]}}function Vu(){return 64}function Xu(){return"circle"}function $u(n){var t=Math.sqrt(n/Fo);return"M0,"+t+"A"+t+","+t+" 0 1,1 0,"+-t+"A"+t+","+t+" 0 1,1 0,"+t+"Z"}function Bu(n){return function(){var t,e,r;(t=this[n])&&(r=t[e=t.active])&&(r.timer.c=null,r.timer.t=NaN,--t.count?delete t[e]:delete this[n],t.active+=.5,r.event&&r.event.interrupt.call(this,this.__data__,r.index))}}function Wu(n,t,e){return ko(n,Yl),n.namespace=t,n.id=e,n}function Ju(n,t,e,r){var i=n.id,u=n.namespace;return Y(n,"function"==typeof e?function(n,o,a){n[u][i].tween.set(t,r(e.call(n,n.__data__,o,a)))}:(e=r(e),function(n){n[u][i].tween.set(t,e)}))}function Gu(n){return null==n&&(n=""),function(){this.textContent=n}}function Ku(n){return null==n?"__transition__":"__transition_"+n+"__"}function Qu(n,t,e,r,i){function u(n){var t=v.delay;return f.t=t+l,n>=t?o(n-t):void(f.c=o)}function o(e){var i=g.active,u=g[i];u&&(u.timer.c=null,u.timer.t=NaN,--g.count,delete g[i],u.event&&u.event.interrupt.call(n,n.__data__,u.index));for(var o in g)if(r>+o){var c=g[o];c.timer.c=null,c.timer.t=NaN,--g.count,delete g[o]}f.c=a,qn(function(){return f.c&&a(e||1)&&(f.c=null,f.t=NaN),1},0,l),g.active=r,v.event&&v.event.start.call(n,n.__data__,t),p=[],v.tween.forEach(function(e,r){(r=r.call(n,n.__data__,t))&&p.push(r)}),h=v.ease,s=v.duration}function a(i){for(var u=i/s,o=h(u),a=p.length;a>0;)p[--a].call(n,o);return u>=1?(v.event&&v.event.end.call(n,n.__data__,t),--g.count?delete g[r]:delete n[e],1):void 0}var l,f,s,h,p,g=n[e]||(n[e]={active:0,count:0}),v=g[r];v||(l=i.time,f=qn(u,0,l),v=g[r]={tween:new c,time:l,timer:f,delay:i.delay,duration:i.duration,ease:i.ease,index:t},i=null,++g.count)}function no(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate("+(isFinite(r)?r:e(n))+",0)"})}function to(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate(0,"+(isFinite(r)?r:e(n))+")"})}function eo(n){return n.toISOString()}function ro(n,t,e){function r(t){return n(t)}function i(n,e){var r=n[1]-n[0],i=r/e,u=ao.bisect(Kl,i);return u==Kl.length?[t.year,Ki(n.map(function(n){return n/31536e6}),e)[2]]:u?t[i/Kl[u-1]<Kl[u]/i?u-1:u]:[tc,Ki(n,e)[2]]}return r.invert=function(t){return io(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain(t),r):n.domain().map(io)},r.nice=function(n,t){function e(e){return!isNaN(e)&&!n.range(e,io(+e+1),t).length}var u=r.domain(),o=Yi(u),a=null==n?i(o,10):"number"==typeof n&&i(o,n);return a&&(n=a[0],t=a[1]),r.domain(Xi(u,t>1?{floor:function(t){for(;e(t=n.floor(t));)t=io(t-1);return t},ceil:function(t){for(;e(t=n.ceil(t));)t=io(+t+1);return t}}:n))},r.ticks=function(n,t){var e=Yi(r.domain()),u=null==n?i(e,10):"number"==typeof n?i(e,n):!n.range&&[{range:n},t];return u&&(n=u[0],t=u[1]),n.range(e[0],io(+e[1]+1),1>t?1:t)},r.tickFormat=function(){return e},r.copy=function(){return ro(n.copy(),t,e)},Ji(r,n)}function io(n){return new Date(n)}function uo(n){return JSON.parse(n.responseText)}function oo(n){var t=fo.createRange();return t.selectNode(fo.body),t.createContextualFragment(n.responseText)}var ao={version:"3.5.17"},lo=[].slice,co=function(n){return lo.call(n)},fo=this.document;if(fo)try{co(fo.documentElement.childNodes)[0].nodeType}catch(so){co=function(n){for(var t=n.length,e=new Array(t);t--;)e[t]=n[t];return e}}if(Date.now||(Date.now=function(){return+new Date}),fo)try{fo.createElement("DIV").style.setProperty("opacity",0,"")}catch(ho){var po=this.Element.prototype,go=po.setAttribute,vo=po.setAttributeNS,yo=this.CSSStyleDeclaration.prototype,mo=yo.setProperty;po.setAttribute=function(n,t){go.call(this,n,t+"")},po.setAttributeNS=function(n,t,e){vo.call(this,n,t,e+"")},yo.setProperty=function(n,t,e){mo.call(this,n,t+"",e)}}ao.ascending=e,ao.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:NaN},ao.min=function(n,t){var e,r,i=-1,u=n.length;if(1===arguments.length){for(;++i<u;)if(null!=(r=n[i])&&r>=r){e=r;break}for(;++i<u;)null!=(r=n[i])&&e>r&&(e=r)}else{for(;++i<u;)if(null!=(r=t.call(n,n[i],i))&&r>=r){e=r;break}for(;++i<u;)null!=(r=t.call(n,n[i],i))&&e>r&&(e=r)}return e},ao.max=function(n,t){var e,r,i=-1,u=n.length;if(1===arguments.length){for(;++i<u;)if(null!=(r=n[i])&&r>=r){e=r;break}for(;++i<u;)null!=(r=n[i])&&r>e&&(e=r)}else{for(;++i<u;)if(null!=(r=t.call(n,n[i],i))&&r>=r){e=r;break}for(;++i<u;)null!=(r=t.call(n,n[i],i))&&r>e&&(e=r)}return e},ao.extent=function(n,t){var e,r,i,u=-1,o=n.length;if(1===arguments.length){for(;++u<o;)if(null!=(r=n[u])&&r>=r){e=i=r;break}for(;++u<o;)null!=(r=n[u])&&(e>r&&(e=r),r>i&&(i=r))}else{for(;++u<o;)if(null!=(r=t.call(n,n[u],u))&&r>=r){e=i=r;break}for(;++u<o;)null!=(r=t.call(n,n[u],u))&&(e>r&&(e=r),r>i&&(i=r))}return[e,i]},ao.sum=function(n,t){var e,r=0,u=n.length,o=-1;if(1===arguments.length)for(;++o<u;)i(e=+n[o])&&(r+=e);else for(;++o<u;)i(e=+t.call(n,n[o],o))&&(r+=e);return r},ao.mean=function(n,t){var e,u=0,o=n.length,a=-1,l=o;if(1===arguments.length)for(;++a<o;)i(e=r(n[a]))?u+=e:--l;else for(;++a<o;)i(e=r(t.call(n,n[a],a)))?u+=e:--l;return l?u/l:void 0},ao.quantile=function(n,t){var e=(n.length-1)*t+1,r=Math.floor(e),i=+n[r-1],u=e-r;return u?i+u*(n[r]-i):i},ao.median=function(n,t){var u,o=[],a=n.length,l=-1;if(1===arguments.length)for(;++l<a;)i(u=r(n[l]))&&o.push(u);else for(;++l<a;)i(u=r(t.call(n,n[l],l)))&&o.push(u);return o.length?ao.quantile(o.sort(e),.5):void 0},ao.variance=function(n,t){var e,u,o=n.length,a=0,l=0,c=-1,f=0;if(1===arguments.length)for(;++c<o;)i(e=r(n[c]))&&(u=e-a,a+=u/++f,l+=u*(e-a));else for(;++c<o;)i(e=r(t.call(n,n[c],c)))&&(u=e-a,a+=u/++f,l+=u*(e-a));return f>1?l/(f-1):void 0},ao.deviation=function(){var n=ao.variance.apply(this,arguments);return n?Math.sqrt(n):n};var Mo=u(e);ao.bisectLeft=Mo.left,ao.bisect=ao.bisectRight=Mo.right,ao.bisector=function(n){return u(1===n.length?function(t,r){return e(n(t),r)}:n)},ao.shuffle=function(n,t,e){(u=arguments.length)<3&&(e=n.length,2>u&&(t=0));for(var r,i,u=e-t;u;)i=Math.random()*u--|0,r=n[u+t],n[u+t]=n[i+t],n[i+t]=r;return n},ao.permute=function(n,t){for(var e=t.length,r=new Array(e);e--;)r[e]=n[t[e]];return r},ao.pairs=function(n){for(var t,e=0,r=n.length-1,i=n[0],u=new Array(0>r?0:r);r>e;)u[e]=[t=i,i=n[++e]];return u},ao.transpose=function(n){if(!(i=n.length))return[];for(var t=-1,e=ao.min(n,o),r=new Array(e);++t<e;)for(var i,u=-1,a=r[t]=new Array(i);++u<i;)a[u]=n[u][t];return r},ao.zip=function(){return ao.transpose(arguments)},ao.keys=function(n){var t=[];for(var e in n)t.push(e);return t},ao.values=function(n){var t=[];for(var e in n)t.push(n[e]);return t},ao.entries=function(n){var t=[];for(var e in n)t.push({key:e,value:n[e]});return t},ao.merge=function(n){for(var t,e,r,i=n.length,u=-1,o=0;++u<i;)o+=n[u].length;for(e=new Array(o);--i>=0;)for(r=n[i],t=r.length;--t>=0;)e[--o]=r[t];return e};var xo=Math.abs;ao.range=function(n,t,e){if(arguments.length<3&&(e=1,arguments.length<2&&(t=n,n=0)),(t-n)/e===1/0)throw new Error("infinite range");var r,i=[],u=a(xo(e)),o=-1;if(n*=u,t*=u,e*=u,0>e)for(;(r=n+e*++o)>t;)i.push(r/u);else for(;(r=n+e*++o)<t;)i.push(r/u);return i},ao.map=function(n,t){var e=new c;if(n instanceof c)n.forEach(function(n,t){e.set(n,t)});else if(Array.isArray(n)){var r,i=-1,u=n.length;if(1===arguments.length)for(;++i<u;)e.set(i,n[i]);else for(;++i<u;)e.set(t.call(n,r=n[i],i),r)}else for(var o in n)e.set(o,n[o]);return e};var bo="__proto__",_o="\x00";l(c,{has:h,get:function(n){return this._[f(n)]},set:function(n,t){return this._[f(n)]=t},remove:p,keys:g,values:function(){var n=[];for(var t in this._)n.push(this._[t]);return n},entries:function(){var n=[];for(var t in this._)n.push({key:s(t),value:this._[t]});return n},size:v,empty:d,forEach:function(n){for(var t in this._)n.call(this,s(t),this._[t])}}),ao.nest=function(){function n(t,o,a){if(a>=u.length)return r?r.call(i,o):e?o.sort(e):o;for(var l,f,s,h,p=-1,g=o.length,v=u[a++],d=new c;++p<g;)(h=d.get(l=v(f=o[p])))?h.push(f):d.set(l,[f]);return t?(f=t(),s=function(e,r){f.set(e,n(t,r,a))}):(f={},s=function(e,r){f[e]=n(t,r,a)}),d.forEach(s),f}function t(n,e){if(e>=u.length)return n;var r=[],i=o[e++];return n.forEach(function(n,i){r.push({key:n,values:t(i,e)})}),i?r.sort(function(n,t){return i(n.key,t.key)}):r}var e,r,i={},u=[],o=[];return i.map=function(t,e){return n(e,t,0)},i.entries=function(e){return t(n(ao.map,e,0),0)},i.key=function(n){return u.push(n),i},i.sortKeys=function(n){return o[u.length-1]=n,i},i.sortValues=function(n){return e=n,i},i.rollup=function(n){return r=n,i},i},ao.set=function(n){var t=new y;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},l(y,{has:h,add:function(n){return this._[f(n+="")]=!0,n},remove:p,values:g,size:v,empty:d,forEach:function(n){for(var t in this._)n.call(this,s(t))}}),ao.behavior={},ao.rebind=function(n,t){for(var e,r=1,i=arguments.length;++r<i;)n[e=arguments[r]]=M(n,t,t[e]);return n};var wo=["webkit","ms","moz","Moz","o","O"];ao.dispatch=function(){for(var n=new _,t=-1,e=arguments.length;++t<e;)n[arguments[t]]=w(n);return n},_.prototype.on=function(n,t){var e=n.indexOf("."),r="";if(e>=0&&(r=n.slice(e+1),n=n.slice(0,e)),n)return arguments.length<2?this[n].on(r):this[n].on(r,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(r,null);return this}},ao.event=null,ao.requote=function(n){return n.replace(So,"\\$&")};var So=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,ko={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},No=function(n,t){return t.querySelector(n)},Eo=function(n,t){return t.querySelectorAll(n)},Ao=function(n,t){var e=n.matches||n[x(n,"matchesSelector")];return(Ao=function(n,t){return e.call(n,t)})(n,t)};"function"==typeof Sizzle&&(No=function(n,t){return Sizzle(n,t)[0]||null},Eo=Sizzle,Ao=Sizzle.matchesSelector),ao.selection=function(){return ao.select(fo.documentElement)};var Co=ao.selection.prototype=[];Co.select=function(n){var t,e,r,i,u=[];n=A(n);for(var o=-1,a=this.length;++o<a;){u.push(t=[]),t.parentNode=(r=this[o]).parentNode;for(var l=-1,c=r.length;++l<c;)(i=r[l])?(t.push(e=n.call(i,i.__data__,l,o)),e&&"__data__"in i&&(e.__data__=i.__data__)):t.push(null)}return E(u)},Co.selectAll=function(n){var t,e,r=[];n=C(n);for(var i=-1,u=this.length;++i<u;)for(var o=this[i],a=-1,l=o.length;++a<l;)(e=o[a])&&(r.push(t=co(n.call(e,e.__data__,a,i))),t.parentNode=e);return E(r)};var zo="http://www.w3.org/1999/xhtml",Lo={svg:"http://www.w3.org/2000/svg",xhtml:zo,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};ao.ns={prefix:Lo,qualify:function(n){var t=n.indexOf(":"),e=n;return t>=0&&"xmlns"!==(e=n.slice(0,t))&&(n=n.slice(t+1)),Lo.hasOwnProperty(e)?{space:Lo[e],local:n}:n}},Co.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node();return n=ao.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in n)this.each(z(t,n[t]));return this}return this.each(z(n,t))},Co.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node(),r=(n=T(n)).length,i=-1;if(t=e.classList){for(;++i<r;)if(!t.contains(n[i]))return!1}else for(t=e.getAttribute("class");++i<r;)if(!q(n[i]).test(t))return!1;return!0}for(t in n)this.each(R(t,n[t]));return this}return this.each(R(n,t))},Co.style=function(n,e,r){var i=arguments.length;if(3>i){if("string"!=typeof n){2>i&&(e="");for(r in n)this.each(P(r,n[r],e));return this}if(2>i){var u=this.node();return t(u).getComputedStyle(u,null).getPropertyValue(n)}r=""}return this.each(P(n,e,r))},Co.property=function(n,t){if(arguments.length<2){if("string"==typeof n)return this.node()[n];for(t in n)this.each(U(t,n[t]));return this}return this.each(U(n,t))},Co.text=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.textContent=null==t?"":t}:null==n?function(){this.textContent=""}:function(){this.textContent=n}):this.node().textContent},Co.html=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.innerHTML=null==t?"":t}:null==n?function(){this.innerHTML=""}:function(){this.innerHTML=n}):this.node().innerHTML},Co.append=function(n){return n=j(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},Co.insert=function(n,t){return n=j(n),t=A(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments)||null)})},Co.remove=function(){return this.each(F)},Co.data=function(n,t){function e(n,e){var r,i,u,o=n.length,s=e.length,h=Math.min(o,s),p=new Array(s),g=new Array(s),v=new Array(o);if(t){var d,y=new c,m=new Array(o);for(r=-1;++r<o;)(i=n[r])&&(y.has(d=t.call(i,i.__data__,r))?v[r]=i:y.set(d,i),m[r]=d);for(r=-1;++r<s;)(i=y.get(d=t.call(e,u=e[r],r)))?i!==!0&&(p[r]=i,i.__data__=u):g[r]=H(u),y.set(d,!0);for(r=-1;++r<o;)r in m&&y.get(m[r])!==!0&&(v[r]=n[r])}else{for(r=-1;++r<h;)i=n[r],u=e[r],i?(i.__data__=u,p[r]=i):g[r]=H(u);for(;s>r;++r)g[r]=H(e[r]);for(;o>r;++r)v[r]=n[r]}g.update=p,g.parentNode=p.parentNode=v.parentNode=n.parentNode,a.push(g),l.push(p),f.push(v)}var r,i,u=-1,o=this.length;if(!arguments.length){for(n=new Array(o=(r=this[0]).length);++u<o;)(i=r[u])&&(n[u]=i.__data__);return n}var a=Z([]),l=E([]),f=E([]);if("function"==typeof n)for(;++u<o;)e(r=this[u],n.call(r,r.parentNode.__data__,u));else for(;++u<o;)e(r=this[u],n);return l.enter=function(){return a},l.exit=function(){return f},l},Co.datum=function(n){return arguments.length?this.property("__data__",n):this.property("__data__")},Co.filter=function(n){var t,e,r,i=[];"function"!=typeof n&&(n=O(n));for(var u=0,o=this.length;o>u;u++){i.push(t=[]),t.parentNode=(e=this[u]).parentNode;for(var a=0,l=e.length;l>a;a++)(r=e[a])&&n.call(r,r.__data__,a,u)&&t.push(r)}return E(i)},Co.order=function(){for(var n=-1,t=this.length;++n<t;)for(var e,r=this[n],i=r.length-1,u=r[i];--i>=0;)(e=r[i])&&(u&&u!==e.nextSibling&&u.parentNode.insertBefore(e,u),u=e);return this},Co.sort=function(n){n=I.apply(this,arguments);for(var t=-1,e=this.length;++t<e;)this[t].sort(n);return this.order()},Co.each=function(n){return Y(this,function(t,e,r){n.call(t,t.__data__,e,r)})},Co.call=function(n){var t=co(arguments);return n.apply(t[0]=this,t),this},Co.empty=function(){return!this.node()},Co.node=function(){for(var n=0,t=this.length;t>n;n++)for(var e=this[n],r=0,i=e.length;i>r;r++){var u=e[r];if(u)return u}return null},Co.size=function(){var n=0;return Y(this,function(){++n}),n};var qo=[];ao.selection.enter=Z,ao.selection.enter.prototype=qo,qo.append=Co.append,qo.empty=Co.empty,qo.node=Co.node,qo.call=Co.call,qo.size=Co.size,qo.select=function(n){for(var t,e,r,i,u,o=[],a=-1,l=this.length;++a<l;){r=(i=this[a]).update,o.push(t=[]),t.parentNode=i.parentNode;for(var c=-1,f=i.length;++c<f;)(u=i[c])?(t.push(r[c]=e=n.call(i.parentNode,u.__data__,c,a)),e.__data__=u.__data__):t.push(null)}return E(o)},qo.insert=function(n,t){return arguments.length<2&&(t=V(this)),Co.insert.call(this,n,t)},ao.select=function(t){var e;return"string"==typeof t?(e=[No(t,fo)],e.parentNode=fo.documentElement):(e=[t],e.parentNode=n(t)),E([e])},ao.selectAll=function(n){var t;return"string"==typeof n?(t=co(Eo(n,fo)),t.parentNode=fo.documentElement):(t=co(n),t.parentNode=null),E([t])},Co.on=function(n,t,e){var r=arguments.length;if(3>r){if("string"!=typeof n){2>r&&(t=!1);for(e in n)this.each(X(e,n[e],t));return this}if(2>r)return(r=this.node()["__on"+n])&&r._;e=!1}return this.each(X(n,t,e))};var To=ao.map({mouseenter:"mouseover",mouseleave:"mouseout"});fo&&To.forEach(function(n){"on"+n in fo&&To.remove(n)});var Ro,Do=0;ao.mouse=function(n){return J(n,k())};var Po=this.navigator&&/WebKit/.test(this.navigator.userAgent)?-1:0;ao.touch=function(n,t,e){if(arguments.length<3&&(e=t,t=k().changedTouches),t)for(var r,i=0,u=t.length;u>i;++i)if((r=t[i]).identifier===e)return J(n,r)},ao.behavior.drag=function(){function n(){this.on("mousedown.drag",u).on("touchstart.drag",o)}function e(n,t,e,u,o){return function(){function a(){var n,e,r=t(h,v);r&&(n=r[0]-M[0],e=r[1]-M[1],g|=n|e,M=r,p({type:"drag",x:r[0]+c[0],y:r[1]+c[1],dx:n,dy:e}))}function l(){t(h,v)&&(y.on(u+d,null).on(o+d,null),m(g),p({type:"dragend"}))}var c,f=this,s=ao.event.target.correspondingElement||ao.event.target,h=f.parentNode,p=r.of(f,arguments),g=0,v=n(),d=".drag"+(null==v?"":"-"+v),y=ao.select(e(s)).on(u+d,a).on(o+d,l),m=W(s),M=t(h,v);i?(c=i.apply(f,arguments),c=[c.x-M[0],c.y-M[1]]):c=[0,0],p({type:"dragstart"})}}var r=N(n,"drag","dragstart","dragend"),i=null,u=e(b,ao.mouse,t,"mousemove","mouseup"),o=e(G,ao.touch,m,"touchmove","touchend");return n.origin=function(t){return arguments.length?(i=t,n):i},ao.rebind(n,r,"on")},ao.touches=function(n,t){return arguments.length<2&&(t=k().touches),t?co(t).map(function(t){var e=J(n,t);return e.identifier=t.identifier,e}):[]};var Uo=1e-6,jo=Uo*Uo,Fo=Math.PI,Ho=2*Fo,Oo=Ho-Uo,Io=Fo/2,Yo=Fo/180,Zo=180/Fo,Vo=Math.SQRT2,Xo=2,$o=4;ao.interpolateZoom=function(n,t){var e,r,i=n[0],u=n[1],o=n[2],a=t[0],l=t[1],c=t[2],f=a-i,s=l-u,h=f*f+s*s;if(jo>h)r=Math.log(c/o)/Vo,e=function(n){return[i+n*f,u+n*s,o*Math.exp(Vo*n*r)]};else{var p=Math.sqrt(h),g=(c*c-o*o+$o*h)/(2*o*Xo*p),v=(c*c-o*o-$o*h)/(2*c*Xo*p),d=Math.log(Math.sqrt(g*g+1)-g),y=Math.log(Math.sqrt(v*v+1)-v);r=(y-d)/Vo,e=function(n){var t=n*r,e=rn(d),a=o/(Xo*p)*(e*un(Vo*t+d)-en(d));return[i+a*f,u+a*s,o*e/rn(Vo*t+d)]}}return e.duration=1e3*r,e},ao.behavior.zoom=function(){function n(n){n.on(L,s).on(Wo+".zoom",p).on("dblclick.zoom",g).on(R,h)}function e(n){return[(n[0]-k.x)/k.k,(n[1]-k.y)/k.k]}function r(n){return[n[0]*k.k+k.x,n[1]*k.k+k.y]}function i(n){k.k=Math.max(A[0],Math.min(A[1],n))}function u(n,t){t=r(t),k.x+=n[0]-t[0],k.y+=n[1]-t[1]}function o(t,e,r,o){t.__chart__={x:k.x,y:k.y,k:k.k},i(Math.pow(2,o)),u(d=e,r),t=ao.select(t),C>0&&(t=t.transition().duration(C)),t.call(n.event)}function a(){b&&b.domain(x.range().map(function(n){return(n-k.x)/k.k}).map(x.invert)),w&&w.domain(_.range().map(function(n){return(n-k.y)/k.k}).map(_.invert))}function l(n){z++||n({type:"zoomstart"})}function c(n){a(),n({type:"zoom",scale:k.k,translate:[k.x,k.y]})}function f(n){--z||(n({type:"zoomend"}),d=null)}function s(){function n(){a=1,u(ao.mouse(i),h),c(o)}function r(){s.on(q,null).on(T,null),p(a),f(o)}var i=this,o=D.of(i,arguments),a=0,s=ao.select(t(i)).on(q,n).on(T,r),h=e(ao.mouse(i)),p=W(i);Il.call(i),l(o)}function h(){function n(){var n=ao.touches(g);return p=k.k,n.forEach(function(n){n.identifier in d&&(d[n.identifier]=e(n))}),n}function t(){var t=ao.event.target;ao.select(t).on(x,r).on(b,a),_.push(t);for(var e=ao.event.changedTouches,i=0,u=e.length;u>i;++i)d[e[i].identifier]=null;var l=n(),c=Date.now();if(1===l.length){if(500>c-M){var f=l[0];o(g,f,d[f.identifier],Math.floor(Math.log(k.k)/Math.LN2)+1),S()}M=c}else if(l.length>1){var f=l[0],s=l[1],h=f[0]-s[0],p=f[1]-s[1];y=h*h+p*p}}function r(){var n,t,e,r,o=ao.touches(g);Il.call(g);for(var a=0,l=o.length;l>a;++a,r=null)if(e=o[a],r=d[e.identifier]){if(t)break;n=e,t=r}if(r){var f=(f=e[0]-n[0])*f+(f=e[1]-n[1])*f,s=y&&Math.sqrt(f/y);n=[(n[0]+e[0])/2,(n[1]+e[1])/2],t=[(t[0]+r[0])/2,(t[1]+r[1])/2],i(s*p)}M=null,u(n,t),c(v)}function a(){if(ao.event.touches.length){for(var t=ao.event.changedTouches,e=0,r=t.length;r>e;++e)delete d[t[e].identifier];for(var i in d)return void n()}ao.selectAll(_).on(m,null),w.on(L,s).on(R,h),N(),f(v)}var p,g=this,v=D.of(g,arguments),d={},y=0,m=".zoom-"+ao.event.changedTouches[0].identifier,x="touchmove"+m,b="touchend"+m,_=[],w=ao.select(g),N=W(g);t(),l(v),w.on(L,null).on(R,t)}function p(){var n=D.of(this,arguments);m?clearTimeout(m):(Il.call(this),v=e(d=y||ao.mouse(this)),l(n)),m=setTimeout(function(){m=null,f(n)},50),S(),i(Math.pow(2,.002*Bo())*k.k),u(d,v),c(n)}function g(){var n=ao.mouse(this),t=Math.log(k.k)/Math.LN2;o(this,n,e(n),ao.event.shiftKey?Math.ceil(t)-1:Math.floor(t)+1)}var v,d,y,m,M,x,b,_,w,k={x:0,y:0,k:1},E=[960,500],A=Jo,C=250,z=0,L="mousedown.zoom",q="mousemove.zoom",T="mouseup.zoom",R="touchstart.zoom",D=N(n,"zoomstart","zoom","zoomend");return Wo||(Wo="onwheel"in fo?(Bo=function(){return-ao.event.deltaY*(ao.event.deltaMode?120:1)},"wheel"):"onmousewheel"in fo?(Bo=function(){return ao.event.wheelDelta},"mousewheel"):(Bo=function(){return-ao.event.detail},"MozMousePixelScroll")),n.event=function(n){n.each(function(){var n=D.of(this,arguments),t=k;Hl?ao.select(this).transition().each("start.zoom",function(){k=this.__chart__||{x:0,y:0,k:1},l(n)}).tween("zoom:zoom",function(){var e=E[0],r=E[1],i=d?d[0]:e/2,u=d?d[1]:r/2,o=ao.interpolateZoom([(i-k.x)/k.k,(u-k.y)/k.k,e/k.k],[(i-t.x)/t.k,(u-t.y)/t.k,e/t.k]);return function(t){var r=o(t),a=e/r[2];this.__chart__=k={x:i-r[0]*a,y:u-r[1]*a,k:a},c(n)}}).each("interrupt.zoom",function(){f(n)}).each("end.zoom",function(){f(n)}):(this.__chart__=k,l(n),c(n),f(n))})},n.translate=function(t){return arguments.length?(k={x:+t[0],y:+t[1],k:k.k},a(),n):[k.x,k.y]},n.scale=function(t){return arguments.length?(k={x:k.x,y:k.y,k:null},i(+t),a(),n):k.k},n.scaleExtent=function(t){return arguments.length?(A=null==t?Jo:[+t[0],+t[1]],n):A},n.center=function(t){return arguments.length?(y=t&&[+t[0],+t[1]],n):y},n.size=function(t){return arguments.length?(E=t&&[+t[0],+t[1]],n):E},n.duration=function(t){return arguments.length?(C=+t,n):C},n.x=function(t){return arguments.length?(b=t,x=t.copy(),k={x:0,y:0,k:1},n):b},n.y=function(t){return arguments.length?(w=t,_=t.copy(),k={x:0,y:0,k:1},n):w},ao.rebind(n,D,"on")};var Bo,Wo,Jo=[0,1/0];ao.color=an,an.prototype.toString=function(){return this.rgb()+""},ao.hsl=ln;var Go=ln.prototype=new an;Go.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),new ln(this.h,this.s,this.l/n)},Go.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new ln(this.h,this.s,n*this.l)},Go.rgb=function(){return cn(this.h,this.s,this.l)},ao.hcl=fn;var Ko=fn.prototype=new an;Ko.brighter=function(n){return new fn(this.h,this.c,Math.min(100,this.l+Qo*(arguments.length?n:1)))},Ko.darker=function(n){return new fn(this.h,this.c,Math.max(0,this.l-Qo*(arguments.length?n:1)))},Ko.rgb=function(){return sn(this.h,this.c,this.l).rgb()},ao.lab=hn;var Qo=18,na=.95047,ta=1,ea=1.08883,ra=hn.prototype=new an;ra.brighter=function(n){return new hn(Math.min(100,this.l+Qo*(arguments.length?n:1)),this.a,this.b)},ra.darker=function(n){return new hn(Math.max(0,this.l-Qo*(arguments.length?n:1)),this.a,this.b)},ra.rgb=function(){return pn(this.l,this.a,this.b)},ao.rgb=mn;var ia=mn.prototype=new an;ia.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,e=this.g,r=this.b,i=30;return t||e||r?(t&&i>t&&(t=i),e&&i>e&&(e=i),r&&i>r&&(r=i),new mn(Math.min(255,t/n),Math.min(255,e/n),Math.min(255,r/n))):new mn(i,i,i)},ia.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new mn(n*this.r,n*this.g,n*this.b)},ia.hsl=function(){return wn(this.r,this.g,this.b)},ia.toString=function(){return"#"+bn(this.r)+bn(this.g)+bn(this.b)};var ua=ao.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});ua.forEach(function(n,t){ua.set(n,Mn(t))}),ao.functor=En,ao.xhr=An(m),ao.dsv=function(n,t){function e(n,e,u){arguments.length<3&&(u=e,e=null);var o=Cn(n,t,null==e?r:i(e),u);return o.row=function(n){return arguments.length?o.response(null==(e=n)?r:i(n)):e},o}function r(n){return e.parse(n.responseText)}function i(n){return function(t){return e.parse(t.responseText,n)}}function u(t){return t.map(o).join(n)}function o(n){return a.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var a=new RegExp('["'+n+"\n]"),l=n.charCodeAt(0);return e.parse=function(n,t){var r;return e.parseRows(n,function(n,e){if(r)return r(n,e-1);var i=new Function("d","return {"+n.map(function(n,t){return JSON.stringify(n)+": d["+t+"]"}).join(",")+"}");r=t?function(n,e){return t(i(n),e)}:i})},e.parseRows=function(n,t){function e(){if(f>=c)return o;if(i)return i=!1,u;var t=f;if(34===n.charCodeAt(t)){for(var e=t;e++<c;)if(34===n.charCodeAt(e)){if(34!==n.charCodeAt(e+1))break;++e}f=e+2;var r=n.charCodeAt(e+1);return 13===r?(i=!0,10===n.charCodeAt(e+2)&&++f):10===r&&(i=!0),n.slice(t+1,e).replace(/""/g,'"')}for(;c>f;){var r=n.charCodeAt(f++),a=1;if(10===r)i=!0;else if(13===r)i=!0,10===n.charCodeAt(f)&&(++f,++a);else if(r!==l)continue;return n.slice(t,f-a)}return n.slice(t)}for(var r,i,u={},o={},a=[],c=n.length,f=0,s=0;(r=e())!==o;){for(var h=[];r!==u&&r!==o;)h.push(r),r=e();t&&null==(h=t(h,s++))||a.push(h)}return a},e.format=function(t){if(Array.isArray(t[0]))return e.formatRows(t);var r=new y,i=[];return t.forEach(function(n){for(var t in n)r.has(t)||i.push(r.add(t))}),[i.map(o).join(n)].concat(t.map(function(t){return i.map(function(n){return o(t[n])}).join(n)})).join("\n")},e.formatRows=function(n){return n.map(u).join("\n")},e},ao.csv=ao.dsv(",","text/csv"),ao.tsv=ao.dsv(" ","text/tab-separated-values");var oa,aa,la,ca,fa=this[x(this,"requestAnimationFrame")]||function(n){setTimeout(n,17)};ao.timer=function(){qn.apply(this,arguments)},ao.timer.flush=function(){Rn(),Dn()},ao.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)};var sa=["y","z","a","f","p","n","\xb5","m","","k","M","G","T","P","E","Z","Y"].map(Un);ao.formatPrefix=function(n,t){var e=0;return(n=+n)&&(0>n&&(n*=-1),t&&(n=ao.round(n,Pn(n,t))),e=1+Math.floor(1e-12+Math.log(n)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((e-1)/3)))),sa[8+e/3]};var ha=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,pa=ao.map({b:function(n){return n.toString(2)},c:function(n){return String.fromCharCode(n)},o:function(n){return n.toString(8)},x:function(n){return n.toString(16)},X:function(n){return n.toString(16).toUpperCase()},g:function(n,t){return n.toPrecision(t)},e:function(n,t){return n.toExponential(t)},f:function(n,t){return n.toFixed(t)},r:function(n,t){return(n=ao.round(n,Pn(n,t))).toFixed(Math.max(0,Math.min(20,Pn(n*(1+1e-15),t))))}}),ga=ao.time={},va=Date;Hn.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){da.setUTCDate.apply(this._,arguments)},setDay:function(){da.setUTCDay.apply(this._,arguments)},setFullYear:function(){da.setUTCFullYear.apply(this._,arguments)},setHours:function(){da.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){da.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){da.setUTCMinutes.apply(this._,arguments)},setMonth:function(){da.setUTCMonth.apply(this._,arguments)},setSeconds:function(){da.setUTCSeconds.apply(this._,arguments)},setTime:function(){da.setTime.apply(this._,arguments)}};var da=Date.prototype;ga.year=On(function(n){return n=ga.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),ga.years=ga.year.range,ga.years.utc=ga.year.utc.range,ga.day=On(function(n){var t=new va(2e3,0);return t.setFullYear(n.getFullYear(),n.getMonth(),n.getDate()),t},function(n,t){n.setDate(n.getDate()+t)},function(n){return n.getDate()-1}),ga.days=ga.day.range,ga.days.utc=ga.day.utc.range,ga.dayOfYear=function(n){var t=ga.year(n);return Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},["sunday","monday","tuesday","wednesday","thursday","friday","saturday"].forEach(function(n,t){t=7-t;var e=ga[n]=On(function(n){return(n=ga.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},function(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var e=ga.year(n).getDay();return Math.floor((ga.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});ga[n+"s"]=e.range,ga[n+"s"].utc=e.utc.range,ga[n+"OfYear"]=function(n){var e=ga.year(n).getDay();return Math.floor((ga.dayOfYear(n)+(e+t)%7)/7)}}),ga.week=ga.sunday,ga.weeks=ga.sunday.range,ga.weeks.utc=ga.sunday.utc.range,ga.weekOfYear=ga.sundayOfYear;var ya={"-":"",_:" ",0:"0"},ma=/^\s*\d+/,Ma=/^%/;ao.locale=function(n){return{numberFormat:jn(n),timeFormat:Yn(n)}};var xa=ao.locale({decimal:".",thousands:",",grouping:[3],currency:["$",""],dateTime:"%a %b %e %X %Y",date:"%m/%d/%Y",time:"%H:%M:%S",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],
4
- shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});ao.format=xa.numberFormat,ao.geo={},ft.prototype={s:0,t:0,add:function(n){st(n,this.t,ba),st(ba.s,this.s,this),this.s?this.t+=ba.t:this.s=ba.t},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var ba=new ft;ao.geo.stream=function(n,t){n&&_a.hasOwnProperty(n.type)?_a[n.type](n,t):ht(n,t)};var _a={Feature:function(n,t){ht(n.geometry,t)},FeatureCollection:function(n,t){for(var e=n.features,r=-1,i=e.length;++r<i;)ht(e[r].geometry,t)}},wa={Sphere:function(n,t){t.sphere()},Point:function(n,t){n=n.coordinates,t.point(n[0],n[1],n[2])},MultiPoint:function(n,t){for(var e=n.coordinates,r=-1,i=e.length;++r<i;)n=e[r],t.point(n[0],n[1],n[2])},LineString:function(n,t){pt(n.coordinates,t,0)},MultiLineString:function(n,t){for(var e=n.coordinates,r=-1,i=e.length;++r<i;)pt(e[r],t,0)},Polygon:function(n,t){gt(n.coordinates,t)},MultiPolygon:function(n,t){for(var e=n.coordinates,r=-1,i=e.length;++r<i;)gt(e[r],t)},GeometryCollection:function(n,t){for(var e=n.geometries,r=-1,i=e.length;++r<i;)ht(e[r],t)}};ao.geo.area=function(n){return Sa=0,ao.geo.stream(n,Na),Sa};var Sa,ka=new ft,Na={sphere:function(){Sa+=4*Fo},point:b,lineStart:b,lineEnd:b,polygonStart:function(){ka.reset(),Na.lineStart=vt},polygonEnd:function(){var n=2*ka;Sa+=0>n?4*Fo+n:n,Na.lineStart=Na.lineEnd=Na.point=b}};ao.geo.bounds=function(){function n(n,t){M.push(x=[f=n,h=n]),s>t&&(s=t),t>p&&(p=t)}function t(t,e){var r=dt([t*Yo,e*Yo]);if(y){var i=mt(y,r),u=[i[1],-i[0],0],o=mt(u,i);bt(o),o=_t(o);var l=t-g,c=l>0?1:-1,v=o[0]*Zo*c,d=xo(l)>180;if(d^(v>c*g&&c*t>v)){var m=o[1]*Zo;m>p&&(p=m)}else if(v=(v+360)%360-180,d^(v>c*g&&c*t>v)){var m=-o[1]*Zo;s>m&&(s=m)}else s>e&&(s=e),e>p&&(p=e);d?g>t?a(f,t)>a(f,h)&&(h=t):a(t,h)>a(f,h)&&(f=t):h>=f?(f>t&&(f=t),t>h&&(h=t)):t>g?a(f,t)>a(f,h)&&(h=t):a(t,h)>a(f,h)&&(f=t)}else n(t,e);y=r,g=t}function e(){b.point=t}function r(){x[0]=f,x[1]=h,b.point=n,y=null}function i(n,e){if(y){var r=n-g;m+=xo(r)>180?r+(r>0?360:-360):r}else v=n,d=e;Na.point(n,e),t(n,e)}function u(){Na.lineStart()}function o(){i(v,d),Na.lineEnd(),xo(m)>Uo&&(f=-(h=180)),x[0]=f,x[1]=h,y=null}function a(n,t){return(t-=n)<0?t+360:t}function l(n,t){return n[0]-t[0]}function c(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var f,s,h,p,g,v,d,y,m,M,x,b={point:n,lineStart:e,lineEnd:r,polygonStart:function(){b.point=i,b.lineStart=u,b.lineEnd=o,m=0,Na.polygonStart()},polygonEnd:function(){Na.polygonEnd(),b.point=n,b.lineStart=e,b.lineEnd=r,0>ka?(f=-(h=180),s=-(p=90)):m>Uo?p=90:-Uo>m&&(s=-90),x[0]=f,x[1]=h}};return function(n){p=h=-(f=s=1/0),M=[],ao.geo.stream(n,b);var t=M.length;if(t){M.sort(l);for(var e,r=1,i=M[0],u=[i];t>r;++r)e=M[r],c(e[0],i)||c(e[1],i)?(a(i[0],e[1])>a(i[0],i[1])&&(i[1]=e[1]),a(e[0],i[1])>a(i[0],i[1])&&(i[0]=e[0])):u.push(i=e);for(var o,e,g=-(1/0),t=u.length-1,r=0,i=u[t];t>=r;i=e,++r)e=u[r],(o=a(i[1],e[0]))>g&&(g=o,f=e[0],h=i[1])}return M=x=null,f===1/0||s===1/0?[[NaN,NaN],[NaN,NaN]]:[[f,s],[h,p]]}}(),ao.geo.centroid=function(n){Ea=Aa=Ca=za=La=qa=Ta=Ra=Da=Pa=Ua=0,ao.geo.stream(n,ja);var t=Da,e=Pa,r=Ua,i=t*t+e*e+r*r;return jo>i&&(t=qa,e=Ta,r=Ra,Uo>Aa&&(t=Ca,e=za,r=La),i=t*t+e*e+r*r,jo>i)?[NaN,NaN]:[Math.atan2(e,t)*Zo,tn(r/Math.sqrt(i))*Zo]};var Ea,Aa,Ca,za,La,qa,Ta,Ra,Da,Pa,Ua,ja={sphere:b,point:St,lineStart:Nt,lineEnd:Et,polygonStart:function(){ja.lineStart=At},polygonEnd:function(){ja.lineStart=Nt}},Fa=Rt(zt,jt,Ht,[-Fo,-Fo/2]),Ha=1e9;ao.geo.clipExtent=function(){var n,t,e,r,i,u,o={stream:function(n){return i&&(i.valid=!1),i=u(n),i.valid=!0,i},extent:function(a){return arguments.length?(u=Zt(n=+a[0][0],t=+a[0][1],e=+a[1][0],r=+a[1][1]),i&&(i.valid=!1,i=null),o):[[n,t],[e,r]]}};return o.extent([[0,0],[960,500]])},(ao.geo.conicEqualArea=function(){return Vt(Xt)}).raw=Xt,ao.geo.albers=function(){return ao.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},ao.geo.albersUsa=function(){function n(n){var u=n[0],o=n[1];return t=null,e(u,o),t||(r(u,o),t)||i(u,o),t}var t,e,r,i,u=ao.geo.albers(),o=ao.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),a=ao.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),l={point:function(n,e){t=[n,e]}};return n.invert=function(n){var t=u.scale(),e=u.translate(),r=(n[0]-e[0])/t,i=(n[1]-e[1])/t;return(i>=.12&&.234>i&&r>=-.425&&-.214>r?o:i>=.166&&.234>i&&r>=-.214&&-.115>r?a:u).invert(n)},n.stream=function(n){var t=u.stream(n),e=o.stream(n),r=a.stream(n);return{point:function(n,i){t.point(n,i),e.point(n,i),r.point(n,i)},sphere:function(){t.sphere(),e.sphere(),r.sphere()},lineStart:function(){t.lineStart(),e.lineStart(),r.lineStart()},lineEnd:function(){t.lineEnd(),e.lineEnd(),r.lineEnd()},polygonStart:function(){t.polygonStart(),e.polygonStart(),r.polygonStart()},polygonEnd:function(){t.polygonEnd(),e.polygonEnd(),r.polygonEnd()}}},n.precision=function(t){return arguments.length?(u.precision(t),o.precision(t),a.precision(t),n):u.precision()},n.scale=function(t){return arguments.length?(u.scale(t),o.scale(.35*t),a.scale(t),n.translate(u.translate())):u.scale()},n.translate=function(t){if(!arguments.length)return u.translate();var c=u.scale(),f=+t[0],s=+t[1];return e=u.translate(t).clipExtent([[f-.455*c,s-.238*c],[f+.455*c,s+.238*c]]).stream(l).point,r=o.translate([f-.307*c,s+.201*c]).clipExtent([[f-.425*c+Uo,s+.12*c+Uo],[f-.214*c-Uo,s+.234*c-Uo]]).stream(l).point,i=a.translate([f-.205*c,s+.212*c]).clipExtent([[f-.214*c+Uo,s+.166*c+Uo],[f-.115*c-Uo,s+.234*c-Uo]]).stream(l).point,n},n.scale(1070)};var Oa,Ia,Ya,Za,Va,Xa,$a={point:b,lineStart:b,lineEnd:b,polygonStart:function(){Ia=0,$a.lineStart=$t},polygonEnd:function(){$a.lineStart=$a.lineEnd=$a.point=b,Oa+=xo(Ia/2)}},Ba={point:Bt,lineStart:b,lineEnd:b,polygonStart:b,polygonEnd:b},Wa={point:Gt,lineStart:Kt,lineEnd:Qt,polygonStart:function(){Wa.lineStart=ne},polygonEnd:function(){Wa.point=Gt,Wa.lineStart=Kt,Wa.lineEnd=Qt}};ao.geo.path=function(){function n(n){return n&&("function"==typeof a&&u.pointRadius(+a.apply(this,arguments)),o&&o.valid||(o=i(u)),ao.geo.stream(n,o)),u.result()}function t(){return o=null,n}var e,r,i,u,o,a=4.5;return n.area=function(n){return Oa=0,ao.geo.stream(n,i($a)),Oa},n.centroid=function(n){return Ca=za=La=qa=Ta=Ra=Da=Pa=Ua=0,ao.geo.stream(n,i(Wa)),Ua?[Da/Ua,Pa/Ua]:Ra?[qa/Ra,Ta/Ra]:La?[Ca/La,za/La]:[NaN,NaN]},n.bounds=function(n){return Va=Xa=-(Ya=Za=1/0),ao.geo.stream(n,i(Ba)),[[Ya,Za],[Va,Xa]]},n.projection=function(n){return arguments.length?(i=(e=n)?n.stream||re(n):m,t()):e},n.context=function(n){return arguments.length?(u=null==(r=n)?new Wt:new te(n),"function"!=typeof a&&u.pointRadius(a),t()):r},n.pointRadius=function(t){return arguments.length?(a="function"==typeof t?t:(u.pointRadius(+t),+t),n):a},n.projection(ao.geo.albersUsa()).context(null)},ao.geo.transform=function(n){return{stream:function(t){var e=new ie(t);for(var r in n)e[r]=n[r];return e}}},ie.prototype={point:function(n,t){this.stream.point(n,t)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}},ao.geo.projection=oe,ao.geo.projectionMutator=ae,(ao.geo.equirectangular=function(){return oe(ce)}).raw=ce.invert=ce,ao.geo.rotation=function(n){function t(t){return t=n(t[0]*Yo,t[1]*Yo),t[0]*=Zo,t[1]*=Zo,t}return n=se(n[0]%360*Yo,n[1]*Yo,n.length>2?n[2]*Yo:0),t.invert=function(t){return t=n.invert(t[0]*Yo,t[1]*Yo),t[0]*=Zo,t[1]*=Zo,t},t},fe.invert=ce,ao.geo.circle=function(){function n(){var n="function"==typeof r?r.apply(this,arguments):r,t=se(-n[0]*Yo,-n[1]*Yo,0).invert,i=[];return e(null,null,1,{point:function(n,e){i.push(n=t(n,e)),n[0]*=Zo,n[1]*=Zo}}),{type:"Polygon",coordinates:[i]}}var t,e,r=[0,0],i=6;return n.origin=function(t){return arguments.length?(r=t,n):r},n.angle=function(r){return arguments.length?(e=ve((t=+r)*Yo,i*Yo),n):t},n.precision=function(r){return arguments.length?(e=ve(t*Yo,(i=+r)*Yo),n):i},n.angle(90)},ao.geo.distance=function(n,t){var e,r=(t[0]-n[0])*Yo,i=n[1]*Yo,u=t[1]*Yo,o=Math.sin(r),a=Math.cos(r),l=Math.sin(i),c=Math.cos(i),f=Math.sin(u),s=Math.cos(u);return Math.atan2(Math.sqrt((e=s*o)*e+(e=c*f-l*s*a)*e),l*f+c*s*a)},ao.geo.graticule=function(){function n(){return{type:"MultiLineString",coordinates:t()}}function t(){return ao.range(Math.ceil(u/d)*d,i,d).map(h).concat(ao.range(Math.ceil(c/y)*y,l,y).map(p)).concat(ao.range(Math.ceil(r/g)*g,e,g).filter(function(n){return xo(n%d)>Uo}).map(f)).concat(ao.range(Math.ceil(a/v)*v,o,v).filter(function(n){return xo(n%y)>Uo}).map(s))}var e,r,i,u,o,a,l,c,f,s,h,p,g=10,v=g,d=90,y=360,m=2.5;return n.lines=function(){return t().map(function(n){return{type:"LineString",coordinates:n}})},n.outline=function(){return{type:"Polygon",coordinates:[h(u).concat(p(l).slice(1),h(i).reverse().slice(1),p(c).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return arguments.length?(u=+t[0][0],i=+t[1][0],c=+t[0][1],l=+t[1][1],u>i&&(t=u,u=i,i=t),c>l&&(t=c,c=l,l=t),n.precision(m)):[[u,c],[i,l]]},n.minorExtent=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],a=+t[0][1],o=+t[1][1],r>e&&(t=r,r=e,e=t),a>o&&(t=a,a=o,o=t),n.precision(m)):[[r,a],[e,o]]},n.step=function(t){return arguments.length?n.majorStep(t).minorStep(t):n.minorStep()},n.majorStep=function(t){return arguments.length?(d=+t[0],y=+t[1],n):[d,y]},n.minorStep=function(t){return arguments.length?(g=+t[0],v=+t[1],n):[g,v]},n.precision=function(t){return arguments.length?(m=+t,f=ye(a,o,90),s=me(r,e,m),h=ye(c,l,90),p=me(u,i,m),n):m},n.majorExtent([[-180,-90+Uo],[180,90-Uo]]).minorExtent([[-180,-80-Uo],[180,80+Uo]])},ao.geo.greatArc=function(){function n(){return{type:"LineString",coordinates:[t||r.apply(this,arguments),e||i.apply(this,arguments)]}}var t,e,r=Me,i=xe;return n.distance=function(){return ao.geo.distance(t||r.apply(this,arguments),e||i.apply(this,arguments))},n.source=function(e){return arguments.length?(r=e,t="function"==typeof e?null:e,n):r},n.target=function(t){return arguments.length?(i=t,e="function"==typeof t?null:t,n):i},n.precision=function(){return arguments.length?n:0},n},ao.geo.interpolate=function(n,t){return be(n[0]*Yo,n[1]*Yo,t[0]*Yo,t[1]*Yo)},ao.geo.length=function(n){return Ja=0,ao.geo.stream(n,Ga),Ja};var Ja,Ga={sphere:b,point:b,lineStart:_e,lineEnd:b,polygonStart:b,polygonEnd:b},Ka=we(function(n){return Math.sqrt(2/(1+n))},function(n){return 2*Math.asin(n/2)});(ao.geo.azimuthalEqualArea=function(){return oe(Ka)}).raw=Ka;var Qa=we(function(n){var t=Math.acos(n);return t&&t/Math.sin(t)},m);(ao.geo.azimuthalEquidistant=function(){return oe(Qa)}).raw=Qa,(ao.geo.conicConformal=function(){return Vt(Se)}).raw=Se,(ao.geo.conicEquidistant=function(){return Vt(ke)}).raw=ke;var nl=we(function(n){return 1/n},Math.atan);(ao.geo.gnomonic=function(){return oe(nl)}).raw=nl,Ne.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Io]},(ao.geo.mercator=function(){return Ee(Ne)}).raw=Ne;var tl=we(function(){return 1},Math.asin);(ao.geo.orthographic=function(){return oe(tl)}).raw=tl;var el=we(function(n){return 1/(1+n)},function(n){return 2*Math.atan(n)});(ao.geo.stereographic=function(){return oe(el)}).raw=el,Ae.invert=function(n,t){return[-t,2*Math.atan(Math.exp(n))-Io]},(ao.geo.transverseMercator=function(){var n=Ee(Ae),t=n.center,e=n.rotate;return n.center=function(n){return n?t([-n[1],n[0]]):(n=t(),[n[1],-n[0]])},n.rotate=function(n){return n?e([n[0],n[1],n.length>2?n[2]+90:90]):(n=e(),[n[0],n[1],n[2]-90])},e([0,0,90])}).raw=Ae,ao.geom={},ao.geom.hull=function(n){function t(n){if(n.length<3)return[];var t,i=En(e),u=En(r),o=n.length,a=[],l=[];for(t=0;o>t;t++)a.push([+i.call(this,n[t],t),+u.call(this,n[t],t),t]);for(a.sort(qe),t=0;o>t;t++)l.push([a[t][0],-a[t][1]]);var c=Le(a),f=Le(l),s=f[0]===c[0],h=f[f.length-1]===c[c.length-1],p=[];for(t=c.length-1;t>=0;--t)p.push(n[a[c[t]][2]]);for(t=+s;t<f.length-h;++t)p.push(n[a[f[t]][2]]);return p}var e=Ce,r=ze;return arguments.length?t(n):(t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t)},ao.geom.polygon=function(n){return ko(n,rl),n};var rl=ao.geom.polygon.prototype=[];rl.area=function(){for(var n,t=-1,e=this.length,r=this[e-1],i=0;++t<e;)n=r,r=this[t],i+=n[1]*r[0]-n[0]*r[1];return.5*i},rl.centroid=function(n){var t,e,r=-1,i=this.length,u=0,o=0,a=this[i-1];for(arguments.length||(n=-1/(6*this.area()));++r<i;)t=a,a=this[r],e=t[0]*a[1]-a[0]*t[1],u+=(t[0]+a[0])*e,o+=(t[1]+a[1])*e;return[u*n,o*n]},rl.clip=function(n){for(var t,e,r,i,u,o,a=De(n),l=-1,c=this.length-De(this),f=this[c-1];++l<c;){for(t=n.slice(),n.length=0,i=this[l],u=t[(r=t.length-a)-1],e=-1;++e<r;)o=t[e],Te(o,f,i)?(Te(u,f,i)||n.push(Re(u,o,f,i)),n.push(o)):Te(u,f,i)&&n.push(Re(u,o,f,i)),u=o;a&&n.push(n[0]),f=i}return n};var il,ul,ol,al,ll,cl=[],fl=[];Ye.prototype.prepare=function(){for(var n,t=this.edges,e=t.length;e--;)n=t[e].edge,n.b&&n.a||t.splice(e,1);return t.sort(Ve),t.length},tr.prototype={start:function(){return this.edge.l===this.site?this.edge.a:this.edge.b},end:function(){return this.edge.l===this.site?this.edge.b:this.edge.a}},er.prototype={insert:function(n,t){var e,r,i;if(n){if(t.P=n,t.N=n.N,n.N&&(n.N.P=t),n.N=t,n.R){for(n=n.R;n.L;)n=n.L;n.L=t}else n.R=t;e=n}else this._?(n=or(this._),t.P=null,t.N=n,n.P=n.L=t,e=n):(t.P=t.N=null,this._=t,e=null);for(t.L=t.R=null,t.U=e,t.C=!0,n=t;e&&e.C;)r=e.U,e===r.L?(i=r.R,i&&i.C?(e.C=i.C=!1,r.C=!0,n=r):(n===e.R&&(ir(this,e),n=e,e=n.U),e.C=!1,r.C=!0,ur(this,r))):(i=r.L,i&&i.C?(e.C=i.C=!1,r.C=!0,n=r):(n===e.L&&(ur(this,e),n=e,e=n.U),e.C=!1,r.C=!0,ir(this,r))),e=n.U;this._.C=!1},remove:function(n){n.N&&(n.N.P=n.P),n.P&&(n.P.N=n.N),n.N=n.P=null;var t,e,r,i=n.U,u=n.L,o=n.R;if(e=u?o?or(o):u:o,i?i.L===n?i.L=e:i.R=e:this._=e,u&&o?(r=e.C,e.C=n.C,e.L=u,u.U=e,e!==o?(i=e.U,e.U=n.U,n=e.R,i.L=n,e.R=o,o.U=e):(e.U=i,i=e,n=e.R)):(r=n.C,n=e),n&&(n.U=i),!r){if(n&&n.C)return void(n.C=!1);do{if(n===this._)break;if(n===i.L){if(t=i.R,t.C&&(t.C=!1,i.C=!0,ir(this,i),t=i.R),t.L&&t.L.C||t.R&&t.R.C){t.R&&t.R.C||(t.L.C=!1,t.C=!0,ur(this,t),t=i.R),t.C=i.C,i.C=t.R.C=!1,ir(this,i),n=this._;break}}else if(t=i.L,t.C&&(t.C=!1,i.C=!0,ur(this,i),t=i.L),t.L&&t.L.C||t.R&&t.R.C){t.L&&t.L.C||(t.R.C=!1,t.C=!0,ir(this,t),t=i.L),t.C=i.C,i.C=t.L.C=!1,ur(this,i),n=this._;break}t.C=!0,n=i,i=i.U}while(!n.C);n&&(n.C=!1)}}},ao.geom.voronoi=function(n){function t(n){var t=new Array(n.length),r=a[0][0],i=a[0][1],u=a[1][0],o=a[1][1];return ar(e(n),a).cells.forEach(function(e,a){var l=e.edges,c=e.site,f=t[a]=l.length?l.map(function(n){var t=n.start();return[t.x,t.y]}):c.x>=r&&c.x<=u&&c.y>=i&&c.y<=o?[[r,o],[u,o],[u,i],[r,i]]:[];f.point=n[a]}),t}function e(n){return n.map(function(n,t){return{x:Math.round(u(n,t)/Uo)*Uo,y:Math.round(o(n,t)/Uo)*Uo,i:t}})}var r=Ce,i=ze,u=r,o=i,a=sl;return n?t(n):(t.links=function(n){return ar(e(n)).edges.filter(function(n){return n.l&&n.r}).map(function(t){return{source:n[t.l.i],target:n[t.r.i]}})},t.triangles=function(n){var t=[];return ar(e(n)).cells.forEach(function(e,r){for(var i,u,o=e.site,a=e.edges.sort(Ve),l=-1,c=a.length,f=a[c-1].edge,s=f.l===o?f.r:f.l;++l<c;)i=f,u=s,f=a[l].edge,s=f.l===o?f.r:f.l,r<u.i&&r<s.i&&cr(o,u,s)<0&&t.push([n[r],n[u.i],n[s.i]])}),t},t.x=function(n){return arguments.length?(u=En(r=n),t):r},t.y=function(n){return arguments.length?(o=En(i=n),t):i},t.clipExtent=function(n){return arguments.length?(a=null==n?sl:n,t):a===sl?null:a},t.size=function(n){return arguments.length?t.clipExtent(n&&[[0,0],n]):a===sl?null:a&&a[1]},t)};var sl=[[-1e6,-1e6],[1e6,1e6]];ao.geom.delaunay=function(n){return ao.geom.voronoi().triangles(n)},ao.geom.quadtree=function(n,t,e,r,i){function u(n){function u(n,t,e,r,i,u,o,a){if(!isNaN(e)&&!isNaN(r))if(n.leaf){var l=n.x,f=n.y;if(null!=l)if(xo(l-e)+xo(f-r)<.01)c(n,t,e,r,i,u,o,a);else{var s=n.point;n.x=n.y=n.point=null,c(n,s,l,f,i,u,o,a),c(n,t,e,r,i,u,o,a)}else n.x=e,n.y=r,n.point=t}else c(n,t,e,r,i,u,o,a)}function c(n,t,e,r,i,o,a,l){var c=.5*(i+a),f=.5*(o+l),s=e>=c,h=r>=f,p=h<<1|s;n.leaf=!1,n=n.nodes[p]||(n.nodes[p]=hr()),s?i=c:a=c,h?o=f:l=f,u(n,t,e,r,i,o,a,l)}var f,s,h,p,g,v,d,y,m,M=En(a),x=En(l);if(null!=t)v=t,d=e,y=r,m=i;else if(y=m=-(v=d=1/0),s=[],h=[],g=n.length,o)for(p=0;g>p;++p)f=n[p],f.x<v&&(v=f.x),f.y<d&&(d=f.y),f.x>y&&(y=f.x),f.y>m&&(m=f.y),s.push(f.x),h.push(f.y);else for(p=0;g>p;++p){var b=+M(f=n[p],p),_=+x(f,p);v>b&&(v=b),d>_&&(d=_),b>y&&(y=b),_>m&&(m=_),s.push(b),h.push(_)}var w=y-v,S=m-d;w>S?m=d+w:y=v+S;var k=hr();if(k.add=function(n){u(k,n,+M(n,++p),+x(n,p),v,d,y,m)},k.visit=function(n){pr(n,k,v,d,y,m)},k.find=function(n){return gr(k,n[0],n[1],v,d,y,m)},p=-1,null==t){for(;++p<g;)u(k,n[p],s[p],h[p],v,d,y,m);--p}else n.forEach(k.add);return s=h=n=f=null,k}var o,a=Ce,l=ze;return(o=arguments.length)?(a=fr,l=sr,3===o&&(i=e,r=t,e=t=0),u(n)):(u.x=function(n){return arguments.length?(a=n,u):a},u.y=function(n){return arguments.length?(l=n,u):l},u.extent=function(n){return arguments.length?(null==n?t=e=r=i=null:(t=+n[0][0],e=+n[0][1],r=+n[1][0],i=+n[1][1]),u):null==t?null:[[t,e],[r,i]]},u.size=function(n){return arguments.length?(null==n?t=e=r=i=null:(t=e=0,r=+n[0],i=+n[1]),u):null==t?null:[r-t,i-e]},u)},ao.interpolateRgb=vr,ao.interpolateObject=dr,ao.interpolateNumber=yr,ao.interpolateString=mr;var hl=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,pl=new RegExp(hl.source,"g");ao.interpolate=Mr,ao.interpolators=[function(n,t){var e=typeof t;return("string"===e?ua.has(t.toLowerCase())||/^(#|rgb\(|hsl\()/i.test(t)?vr:mr:t instanceof an?vr:Array.isArray(t)?xr:"object"===e&&isNaN(t)?dr:yr)(n,t)}],ao.interpolateArray=xr;var gl=function(){return m},vl=ao.map({linear:gl,poly:Er,quad:function(){return Sr},cubic:function(){return kr},sin:function(){return Ar},exp:function(){return Cr},circle:function(){return zr},elastic:Lr,back:qr,bounce:function(){return Tr}}),dl=ao.map({"in":m,out:_r,"in-out":wr,"out-in":function(n){return wr(_r(n))}});ao.ease=function(n){var t=n.indexOf("-"),e=t>=0?n.slice(0,t):n,r=t>=0?n.slice(t+1):"in";return e=vl.get(e)||gl,r=dl.get(r)||m,br(r(e.apply(null,lo.call(arguments,1))))},ao.interpolateHcl=Rr,ao.interpolateHsl=Dr,ao.interpolateLab=Pr,ao.interpolateRound=Ur,ao.transform=function(n){var t=fo.createElementNS(ao.ns.prefix.svg,"g");return(ao.transform=function(n){if(null!=n){t.setAttribute("transform",n);var e=t.transform.baseVal.consolidate()}return new jr(e?e.matrix:yl)})(n)},jr.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var yl={a:1,b:0,c:0,d:1,e:0,f:0};ao.interpolateTransform=$r,ao.layout={},ao.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++e<r;)t.push(Jr(n[e]));return t}},ao.layout.chord=function(){function n(){var n,c,s,h,p,g={},v=[],d=ao.range(u),y=[];for(e=[],r=[],n=0,h=-1;++h<u;){for(c=0,p=-1;++p<u;)c+=i[h][p];v.push(c),y.push(ao.range(u)),n+=c}for(o&&d.sort(function(n,t){return o(v[n],v[t])}),a&&y.forEach(function(n,t){n.sort(function(n,e){return a(i[t][n],i[t][e])})}),n=(Ho-f*u)/n,c=0,h=-1;++h<u;){for(s=c,p=-1;++p<u;){var m=d[h],M=y[m][p],x=i[m][M],b=c,_=c+=x*n;g[m+"-"+M]={index:m,subindex:M,startAngle:b,endAngle:_,value:x}}r[m]={index:m,startAngle:s,endAngle:c,value:v[m]},c+=f}for(h=-1;++h<u;)for(p=h-1;++p<u;){var w=g[h+"-"+p],S=g[p+"-"+h];(w.value||S.value)&&e.push(w.value<S.value?{source:S,target:w}:{source:w,target:S})}l&&t()}function t(){e.sort(function(n,t){return l((n.source.value+n.target.value)/2,(t.source.value+t.target.value)/2)})}var e,r,i,u,o,a,l,c={},f=0;return c.matrix=function(n){return arguments.length?(u=(i=n)&&i.length,e=r=null,c):i},c.padding=function(n){return arguments.length?(f=n,e=r=null,c):f},c.sortGroups=function(n){return arguments.length?(o=n,e=r=null,c):o},c.sortSubgroups=function(n){return arguments.length?(a=n,e=null,c):a},c.sortChords=function(n){return arguments.length?(l=n,e&&t(),c):l},c.chords=function(){return e||n(),e},c.groups=function(){return r||n(),r},c},ao.layout.force=function(){function n(n){return function(t,e,r,i){if(t.point!==n){var u=t.cx-n.x,o=t.cy-n.y,a=i-e,l=u*u+o*o;if(l>a*a/y){if(v>l){var c=t.charge/l;n.px-=u*c,n.py-=o*c}return!0}if(t.point&&l&&v>l){var c=t.pointCharge/l;n.px-=u*c,n.py-=o*c}}return!t.charge}}function t(n){n.px=ao.event.x,n.py=ao.event.y,l.resume()}var e,r,i,u,o,a,l={},c=ao.dispatch("start","tick","end"),f=[1,1],s=.9,h=ml,p=Ml,g=-30,v=xl,d=.1,y=.64,M=[],x=[];return l.tick=function(){if((i*=.99)<.005)return e=null,c.end({type:"end",alpha:i=0}),!0;var t,r,l,h,p,v,y,m,b,_=M.length,w=x.length;for(r=0;w>r;++r)l=x[r],h=l.source,p=l.target,m=p.x-h.x,b=p.y-h.y,(v=m*m+b*b)&&(v=i*o[r]*((v=Math.sqrt(v))-u[r])/v,m*=v,b*=v,p.x-=m*(y=h.weight+p.weight?h.weight/(h.weight+p.weight):.5),p.y-=b*y,h.x+=m*(y=1-y),h.y+=b*y);if((y=i*d)&&(m=f[0]/2,b=f[1]/2,r=-1,y))for(;++r<_;)l=M[r],l.x+=(m-l.x)*y,l.y+=(b-l.y)*y;if(g)for(ri(t=ao.geom.quadtree(M),i,a),r=-1;++r<_;)(l=M[r]).fixed||t.visit(n(l));for(r=-1;++r<_;)l=M[r],l.fixed?(l.x=l.px,l.y=l.py):(l.x-=(l.px-(l.px=l.x))*s,l.y-=(l.py-(l.py=l.y))*s);c.tick({type:"tick",alpha:i})},l.nodes=function(n){return arguments.length?(M=n,l):M},l.links=function(n){return arguments.length?(x=n,l):x},l.size=function(n){return arguments.length?(f=n,l):f},l.linkDistance=function(n){return arguments.length?(h="function"==typeof n?n:+n,l):h},l.distance=l.linkDistance,l.linkStrength=function(n){return arguments.length?(p="function"==typeof n?n:+n,l):p},l.friction=function(n){return arguments.length?(s=+n,l):s},l.charge=function(n){return arguments.length?(g="function"==typeof n?n:+n,l):g},l.chargeDistance=function(n){return arguments.length?(v=n*n,l):Math.sqrt(v)},l.gravity=function(n){return arguments.length?(d=+n,l):d},l.theta=function(n){return arguments.length?(y=n*n,l):Math.sqrt(y)},l.alpha=function(n){return arguments.length?(n=+n,i?n>0?i=n:(e.c=null,e.t=NaN,e=null,c.end({type:"end",alpha:i=0})):n>0&&(c.start({type:"start",alpha:i=n}),e=qn(l.tick)),l):i},l.start=function(){function n(n,r){if(!e){for(e=new Array(i),l=0;i>l;++l)e[l]=[];for(l=0;c>l;++l){var u=x[l];e[u.source.index].push(u.target),e[u.target.index].push(u.source)}}for(var o,a=e[t],l=-1,f=a.length;++l<f;)if(!isNaN(o=a[l][n]))return o;return Math.random()*r}var t,e,r,i=M.length,c=x.length,s=f[0],v=f[1];for(t=0;i>t;++t)(r=M[t]).index=t,r.weight=0;for(t=0;c>t;++t)r=x[t],"number"==typeof r.source&&(r.source=M[r.source]),"number"==typeof r.target&&(r.target=M[r.target]),++r.source.weight,++r.target.weight;for(t=0;i>t;++t)r=M[t],isNaN(r.x)&&(r.x=n("x",s)),isNaN(r.y)&&(r.y=n("y",v)),isNaN(r.px)&&(r.px=r.x),isNaN(r.py)&&(r.py=r.y);if(u=[],"function"==typeof h)for(t=0;c>t;++t)u[t]=+h.call(this,x[t],t);else for(t=0;c>t;++t)u[t]=h;if(o=[],"function"==typeof p)for(t=0;c>t;++t)o[t]=+p.call(this,x[t],t);else for(t=0;c>t;++t)o[t]=p;if(a=[],"function"==typeof g)for(t=0;i>t;++t)a[t]=+g.call(this,M[t],t);else for(t=0;i>t;++t)a[t]=g;return l.resume()},l.resume=function(){return l.alpha(.1)},l.stop=function(){return l.alpha(0)},l.drag=function(){return r||(r=ao.behavior.drag().origin(m).on("dragstart.force",Qr).on("drag.force",t).on("dragend.force",ni)),arguments.length?void this.on("mouseover.force",ti).on("mouseout.force",ei).call(r):r},ao.rebind(l,c,"on")};var ml=20,Ml=1,xl=1/0;ao.layout.hierarchy=function(){function n(i){var u,o=[i],a=[];for(i.depth=0;null!=(u=o.pop());)if(a.push(u),(c=e.call(n,u,u.depth))&&(l=c.length)){for(var l,c,f;--l>=0;)o.push(f=c[l]),f.parent=u,f.depth=u.depth+1;r&&(u.value=0),u.children=c}else r&&(u.value=+r.call(n,u,u.depth)||0),delete u.children;return oi(i,function(n){var e,i;t&&(e=n.children)&&e.sort(t),r&&(i=n.parent)&&(i.value+=n.value)}),a}var t=ci,e=ai,r=li;return n.sort=function(e){return arguments.length?(t=e,n):t},n.children=function(t){return arguments.length?(e=t,n):e},n.value=function(t){return arguments.length?(r=t,n):r},n.revalue=function(t){return r&&(ui(t,function(n){n.children&&(n.value=0)}),oi(t,function(t){var e;t.children||(t.value=+r.call(n,t,t.depth)||0),(e=t.parent)&&(e.value+=t.value)})),t},n},ao.layout.partition=function(){function n(t,e,r,i){var u=t.children;if(t.x=e,t.y=t.depth*i,t.dx=r,t.dy=i,u&&(o=u.length)){var o,a,l,c=-1;for(r=t.value?r/t.value:0;++c<o;)n(a=u[c],e,l=a.value*r,i),e+=l}}function t(n){var e=n.children,r=0;if(e&&(i=e.length))for(var i,u=-1;++u<i;)r=Math.max(r,t(e[u]));return 1+r}function e(e,u){var o=r.call(this,e,u);return n(o[0],0,i[0],i[1]/t(o[0])),o}var r=ao.layout.hierarchy(),i=[1,1];return e.size=function(n){return arguments.length?(i=n,e):i},ii(e,r)},ao.layout.pie=function(){function n(o){var a,l=o.length,c=o.map(function(e,r){return+t.call(n,e,r)}),f=+("function"==typeof r?r.apply(this,arguments):r),s=("function"==typeof i?i.apply(this,arguments):i)-f,h=Math.min(Math.abs(s)/l,+("function"==typeof u?u.apply(this,arguments):u)),p=h*(0>s?-1:1),g=ao.sum(c),v=g?(s-l*p)/g:0,d=ao.range(l),y=[];return null!=e&&d.sort(e===bl?function(n,t){return c[t]-c[n]}:function(n,t){return e(o[n],o[t])}),d.forEach(function(n){y[n]={data:o[n],value:a=c[n],startAngle:f,endAngle:f+=a*v+p,padAngle:h}}),y}var t=Number,e=bl,r=0,i=Ho,u=0;return n.value=function(e){return arguments.length?(t=e,n):t},n.sort=function(t){return arguments.length?(e=t,n):e},n.startAngle=function(t){return arguments.length?(r=t,n):r},n.endAngle=function(t){return arguments.length?(i=t,n):i},n.padAngle=function(t){return arguments.length?(u=t,n):u},n};var bl={};ao.layout.stack=function(){function n(a,l){if(!(h=a.length))return a;var c=a.map(function(e,r){return t.call(n,e,r)}),f=c.map(function(t){return t.map(function(t,e){return[u.call(n,t,e),o.call(n,t,e)]})}),s=e.call(n,f,l);c=ao.permute(c,s),f=ao.permute(f,s);var h,p,g,v,d=r.call(n,f,l),y=c[0].length;for(g=0;y>g;++g)for(i.call(n,c[0][g],v=d[g],f[0][g][1]),p=1;h>p;++p)i.call(n,c[p][g],v+=f[p-1][g][1],f[p][g][1]);return a}var t=m,e=gi,r=vi,i=pi,u=si,o=hi;return n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return arguments.length?(e="function"==typeof t?t:_l.get(t)||gi,n):e},n.offset=function(t){return arguments.length?(r="function"==typeof t?t:wl.get(t)||vi,n):r},n.x=function(t){return arguments.length?(u=t,n):u},n.y=function(t){return arguments.length?(o=t,n):o},n.out=function(t){return arguments.length?(i=t,n):i},n};var _l=ao.map({"inside-out":function(n){var t,e,r=n.length,i=n.map(di),u=n.map(yi),o=ao.range(r).sort(function(n,t){return i[n]-i[t]}),a=0,l=0,c=[],f=[];for(t=0;r>t;++t)e=o[t],l>a?(a+=u[e],c.push(e)):(l+=u[e],f.push(e));return f.reverse().concat(c)},reverse:function(n){return ao.range(n.length).reverse()},"default":gi}),wl=ao.map({silhouette:function(n){var t,e,r,i=n.length,u=n[0].length,o=[],a=0,l=[];for(e=0;u>e;++e){for(t=0,r=0;i>t;t++)r+=n[t][e][1];r>a&&(a=r),o.push(r)}for(e=0;u>e;++e)l[e]=(a-o[e])/2;return l},wiggle:function(n){var t,e,r,i,u,o,a,l,c,f=n.length,s=n[0],h=s.length,p=[];for(p[0]=l=c=0,e=1;h>e;++e){for(t=0,i=0;f>t;++t)i+=n[t][e][1];for(t=0,u=0,a=s[e][0]-s[e-1][0];f>t;++t){for(r=0,o=(n[t][e][1]-n[t][e-1][1])/(2*a);t>r;++r)o+=(n[r][e][1]-n[r][e-1][1])/a;u+=o*n[t][e][1]}p[e]=l-=i?u/i*a:0,c>l&&(c=l)}for(e=0;h>e;++e)p[e]-=c;return p},expand:function(n){var t,e,r,i=n.length,u=n[0].length,o=1/i,a=[];for(e=0;u>e;++e){for(t=0,r=0;i>t;t++)r+=n[t][e][1];if(r)for(t=0;i>t;t++)n[t][e][1]/=r;else for(t=0;i>t;t++)n[t][e][1]=o}for(e=0;u>e;++e)a[e]=0;return a},zero:vi});ao.layout.histogram=function(){function n(n,u){for(var o,a,l=[],c=n.map(e,this),f=r.call(this,c,u),s=i.call(this,f,c,u),u=-1,h=c.length,p=s.length-1,g=t?1:1/h;++u<p;)o=l[u]=[],o.dx=s[u+1]-(o.x=s[u]),o.y=0;if(p>0)for(u=-1;++u<h;)a=c[u],a>=f[0]&&a<=f[1]&&(o=l[ao.bisect(s,a,1,p)-1],o.y+=g,o.push(n[u]));return l}var t=!0,e=Number,r=bi,i=Mi;return n.value=function(t){return arguments.length?(e=t,n):e},n.range=function(t){return arguments.length?(r=En(t),n):r},n.bins=function(t){return arguments.length?(i="number"==typeof t?function(n){return xi(n,t)}:En(t),n):i},n.frequency=function(e){return arguments.length?(t=!!e,n):t},n},ao.layout.pack=function(){function n(n,u){var o=e.call(this,n,u),a=o[0],l=i[0],c=i[1],f=null==t?Math.sqrt:"function"==typeof t?t:function(){return t};if(a.x=a.y=0,oi(a,function(n){n.r=+f(n.value)}),oi(a,Ni),r){var s=r*(t?1:Math.max(2*a.r/l,2*a.r/c))/2;oi(a,function(n){n.r+=s}),oi(a,Ni),oi(a,function(n){n.r-=s})}return Ci(a,l/2,c/2,t?1:1/Math.max(2*a.r/l,2*a.r/c)),o}var t,e=ao.layout.hierarchy().sort(_i),r=0,i=[1,1];return n.size=function(t){return arguments.length?(i=t,n):i},n.radius=function(e){return arguments.length?(t=null==e||"function"==typeof e?e:+e,n):t},n.padding=function(t){return arguments.length?(r=+t,n):r},ii(n,e)},ao.layout.tree=function(){function n(n,i){var f=o.call(this,n,i),s=f[0],h=t(s);if(oi(h,e),h.parent.m=-h.z,ui(h,r),c)ui(s,u);else{var p=s,g=s,v=s;ui(s,function(n){n.x<p.x&&(p=n),n.x>g.x&&(g=n),n.depth>v.depth&&(v=n)});var d=a(p,g)/2-p.x,y=l[0]/(g.x+a(g,p)/2+d),m=l[1]/(v.depth||1);ui(s,function(n){n.x=(n.x+d)*y,n.y=n.depth*m})}return f}function t(n){for(var t,e={A:null,children:[n]},r=[e];null!=(t=r.pop());)for(var i,u=t.children,o=0,a=u.length;a>o;++o)r.push((u[o]=i={_:u[o],parent:t,children:(i=u[o].children)&&i.slice()||[],A:null,a:null,z:0,m:0,c:0,s:0,t:null,i:o}).a=i);return e.children[0]}function e(n){var t=n.children,e=n.parent.children,r=n.i?e[n.i-1]:null;if(t.length){Di(n);var u=(t[0].z+t[t.length-1].z)/2;r?(n.z=r.z+a(n._,r._),n.m=n.z-u):n.z=u}else r&&(n.z=r.z+a(n._,r._));n.parent.A=i(n,r,n.parent.A||e[0])}function r(n){n._.x=n.z+n.parent.m,n.m+=n.parent.m}function i(n,t,e){if(t){for(var r,i=n,u=n,o=t,l=i.parent.children[0],c=i.m,f=u.m,s=o.m,h=l.m;o=Ti(o),i=qi(i),o&&i;)l=qi(l),u=Ti(u),u.a=n,r=o.z+s-i.z-c+a(o._,i._),r>0&&(Ri(Pi(o,n,e),n,r),c+=r,f+=r),s+=o.m,c+=i.m,h+=l.m,f+=u.m;o&&!Ti(u)&&(u.t=o,u.m+=s-f),i&&!qi(l)&&(l.t=i,l.m+=c-h,e=n)}return e}function u(n){n.x*=l[0],n.y=n.depth*l[1]}var o=ao.layout.hierarchy().sort(null).value(null),a=Li,l=[1,1],c=null;return n.separation=function(t){return arguments.length?(a=t,n):a},n.size=function(t){return arguments.length?(c=null==(l=t)?u:null,n):c?null:l},n.nodeSize=function(t){return arguments.length?(c=null==(l=t)?null:u,n):c?l:null},ii(n,o)},ao.layout.cluster=function(){function n(n,u){var o,a=t.call(this,n,u),l=a[0],c=0;oi(l,function(n){var t=n.children;t&&t.length?(n.x=ji(t),n.y=Ui(t)):(n.x=o?c+=e(n,o):0,n.y=0,o=n)});var f=Fi(l),s=Hi(l),h=f.x-e(f,s)/2,p=s.x+e(s,f)/2;return oi(l,i?function(n){n.x=(n.x-l.x)*r[0],n.y=(l.y-n.y)*r[1]}:function(n){n.x=(n.x-h)/(p-h)*r[0],n.y=(1-(l.y?n.y/l.y:1))*r[1]}),a}var t=ao.layout.hierarchy().sort(null).value(null),e=Li,r=[1,1],i=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(i=null==(r=t),n):i?null:r},n.nodeSize=function(t){return arguments.length?(i=null!=(r=t),n):i?r:null},ii(n,t)},ao.layout.treemap=function(){function n(n,t){for(var e,r,i=-1,u=n.length;++i<u;)r=(e=n[i]).value*(0>t?0:t),e.area=isNaN(r)||0>=r?0:r}function t(e){var u=e.children;if(u&&u.length){var o,a,l,c=s(e),f=[],h=u.slice(),g=1/0,v="slice"===p?c.dx:"dice"===p?c.dy:"slice-dice"===p?1&e.depth?c.dy:c.dx:Math.min(c.dx,c.dy);for(n(h,c.dx*c.dy/e.value),f.area=0;(l=h.length)>0;)f.push(o=h[l-1]),f.area+=o.area,"squarify"!==p||(a=r(f,v))<=g?(h.pop(),g=a):(f.area-=f.pop().area,i(f,v,c,!1),v=Math.min(c.dx,c.dy),f.length=f.area=0,g=1/0);f.length&&(i(f,v,c,!0),f.length=f.area=0),u.forEach(t)}}function e(t){var r=t.children;if(r&&r.length){var u,o=s(t),a=r.slice(),l=[];for(n(a,o.dx*o.dy/t.value),l.area=0;u=a.pop();)l.push(u),l.area+=u.area,null!=u.z&&(i(l,u.z?o.dx:o.dy,o,!a.length),l.length=l.area=0);r.forEach(e)}}function r(n,t){for(var e,r=n.area,i=0,u=1/0,o=-1,a=n.length;++o<a;)(e=n[o].area)&&(u>e&&(u=e),e>i&&(i=e));return r*=r,t*=t,r?Math.max(t*i*g/r,r/(t*u*g)):1/0}function i(n,t,e,r){var i,u=-1,o=n.length,a=e.x,c=e.y,f=t?l(n.area/t):0;
5
- if(t==e.dx){for((r||f>e.dy)&&(f=e.dy);++u<o;)i=n[u],i.x=a,i.y=c,i.dy=f,a+=i.dx=Math.min(e.x+e.dx-a,f?l(i.area/f):0);i.z=!0,i.dx+=e.x+e.dx-a,e.y+=f,e.dy-=f}else{for((r||f>e.dx)&&(f=e.dx);++u<o;)i=n[u],i.x=a,i.y=c,i.dx=f,c+=i.dy=Math.min(e.y+e.dy-c,f?l(i.area/f):0);i.z=!1,i.dy+=e.y+e.dy-c,e.x+=f,e.dx-=f}}function u(r){var i=o||a(r),u=i[0];return u.x=u.y=0,u.value?(u.dx=c[0],u.dy=c[1]):u.dx=u.dy=0,o&&a.revalue(u),n([u],u.dx*u.dy/u.value),(o?e:t)(u),h&&(o=i),i}var o,a=ao.layout.hierarchy(),l=Math.round,c=[1,1],f=null,s=Oi,h=!1,p="squarify",g=.5*(1+Math.sqrt(5));return u.size=function(n){return arguments.length?(c=n,u):c},u.padding=function(n){function t(t){var e=n.call(u,t,t.depth);return null==e?Oi(t):Ii(t,"number"==typeof e?[e,e,e,e]:e)}function e(t){return Ii(t,n)}if(!arguments.length)return f;var r;return s=null==(f=n)?Oi:"function"==(r=typeof n)?t:"number"===r?(n=[n,n,n,n],e):e,u},u.round=function(n){return arguments.length?(l=n?Math.round:Number,u):l!=Number},u.sticky=function(n){return arguments.length?(h=n,o=null,u):h},u.ratio=function(n){return arguments.length?(g=n,u):g},u.mode=function(n){return arguments.length?(p=n+"",u):p},ii(u,a)},ao.random={normal:function(n,t){var e=arguments.length;return 2>e&&(t=1),1>e&&(n=0),function(){var e,r,i;do e=2*Math.random()-1,r=2*Math.random()-1,i=e*e+r*r;while(!i||i>1);return n+t*e*Math.sqrt(-2*Math.log(i)/i)}},logNormal:function(){var n=ao.random.normal.apply(ao,arguments);return function(){return Math.exp(n())}},bates:function(n){var t=ao.random.irwinHall(n);return function(){return t()/n}},irwinHall:function(n){return function(){for(var t=0,e=0;n>e;e++)t+=Math.random();return t}}},ao.scale={};var Sl={floor:m,ceil:m};ao.scale.linear=function(){return Wi([0,1],[0,1],Mr,!1)};var kl={s:1,g:1,p:1,r:1,e:1};ao.scale.log=function(){return ru(ao.scale.linear().domain([0,1]),10,!0,[1,10])};var Nl=ao.format(".0e"),El={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};ao.scale.pow=function(){return iu(ao.scale.linear(),1,[0,1])},ao.scale.sqrt=function(){return ao.scale.pow().exponent(.5)},ao.scale.ordinal=function(){return ou([],{t:"range",a:[[]]})},ao.scale.category10=function(){return ao.scale.ordinal().range(Al)},ao.scale.category20=function(){return ao.scale.ordinal().range(Cl)},ao.scale.category20b=function(){return ao.scale.ordinal().range(zl)},ao.scale.category20c=function(){return ao.scale.ordinal().range(Ll)};var Al=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(xn),Cl=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(xn),zl=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(xn),Ll=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(xn);ao.scale.quantile=function(){return au([],[])},ao.scale.quantize=function(){return lu(0,1,[0,1])},ao.scale.threshold=function(){return cu([.5],[0,1])},ao.scale.identity=function(){return fu([0,1])},ao.svg={},ao.svg.arc=function(){function n(){var n=Math.max(0,+e.apply(this,arguments)),c=Math.max(0,+r.apply(this,arguments)),f=o.apply(this,arguments)-Io,s=a.apply(this,arguments)-Io,h=Math.abs(s-f),p=f>s?0:1;if(n>c&&(g=c,c=n,n=g),h>=Oo)return t(c,p)+(n?t(n,1-p):"")+"Z";var g,v,d,y,m,M,x,b,_,w,S,k,N=0,E=0,A=[];if((y=(+l.apply(this,arguments)||0)/2)&&(d=u===ql?Math.sqrt(n*n+c*c):+u.apply(this,arguments),p||(E*=-1),c&&(E=tn(d/c*Math.sin(y))),n&&(N=tn(d/n*Math.sin(y)))),c){m=c*Math.cos(f+E),M=c*Math.sin(f+E),x=c*Math.cos(s-E),b=c*Math.sin(s-E);var C=Math.abs(s-f-2*E)<=Fo?0:1;if(E&&yu(m,M,x,b)===p^C){var z=(f+s)/2;m=c*Math.cos(z),M=c*Math.sin(z),x=b=null}}else m=M=0;if(n){_=n*Math.cos(s-N),w=n*Math.sin(s-N),S=n*Math.cos(f+N),k=n*Math.sin(f+N);var L=Math.abs(f-s+2*N)<=Fo?0:1;if(N&&yu(_,w,S,k)===1-p^L){var q=(f+s)/2;_=n*Math.cos(q),w=n*Math.sin(q),S=k=null}}else _=w=0;if(h>Uo&&(g=Math.min(Math.abs(c-n)/2,+i.apply(this,arguments)))>.001){v=c>n^p?0:1;var T=g,R=g;if(Fo>h){var D=null==S?[_,w]:null==x?[m,M]:Re([m,M],[S,k],[x,b],[_,w]),P=m-D[0],U=M-D[1],j=x-D[0],F=b-D[1],H=1/Math.sin(Math.acos((P*j+U*F)/(Math.sqrt(P*P+U*U)*Math.sqrt(j*j+F*F)))/2),O=Math.sqrt(D[0]*D[0]+D[1]*D[1]);R=Math.min(g,(n-O)/(H-1)),T=Math.min(g,(c-O)/(H+1))}if(null!=x){var I=mu(null==S?[_,w]:[S,k],[m,M],c,T,p),Y=mu([x,b],[_,w],c,T,p);g===T?A.push("M",I[0],"A",T,",",T," 0 0,",v," ",I[1],"A",c,",",c," 0 ",1-p^yu(I[1][0],I[1][1],Y[1][0],Y[1][1]),",",p," ",Y[1],"A",T,",",T," 0 0,",v," ",Y[0]):A.push("M",I[0],"A",T,",",T," 0 1,",v," ",Y[0])}else A.push("M",m,",",M);if(null!=S){var Z=mu([m,M],[S,k],n,-R,p),V=mu([_,w],null==x?[m,M]:[x,b],n,-R,p);g===R?A.push("L",V[0],"A",R,",",R," 0 0,",v," ",V[1],"A",n,",",n," 0 ",p^yu(V[1][0],V[1][1],Z[1][0],Z[1][1]),",",1-p," ",Z[1],"A",R,",",R," 0 0,",v," ",Z[0]):A.push("L",V[0],"A",R,",",R," 0 0,",v," ",Z[0])}else A.push("L",_,",",w)}else A.push("M",m,",",M),null!=x&&A.push("A",c,",",c," 0 ",C,",",p," ",x,",",b),A.push("L",_,",",w),null!=S&&A.push("A",n,",",n," 0 ",L,",",1-p," ",S,",",k);return A.push("Z"),A.join("")}function t(n,t){return"M0,"+n+"A"+n+","+n+" 0 1,"+t+" 0,"+-n+"A"+n+","+n+" 0 1,"+t+" 0,"+n}var e=hu,r=pu,i=su,u=ql,o=gu,a=vu,l=du;return n.innerRadius=function(t){return arguments.length?(e=En(t),n):e},n.outerRadius=function(t){return arguments.length?(r=En(t),n):r},n.cornerRadius=function(t){return arguments.length?(i=En(t),n):i},n.padRadius=function(t){return arguments.length?(u=t==ql?ql:En(t),n):u},n.startAngle=function(t){return arguments.length?(o=En(t),n):o},n.endAngle=function(t){return arguments.length?(a=En(t),n):a},n.padAngle=function(t){return arguments.length?(l=En(t),n):l},n.centroid=function(){var n=(+e.apply(this,arguments)+ +r.apply(this,arguments))/2,t=(+o.apply(this,arguments)+ +a.apply(this,arguments))/2-Io;return[Math.cos(t)*n,Math.sin(t)*n]},n};var ql="auto";ao.svg.line=function(){return Mu(m)};var Tl=ao.map({linear:xu,"linear-closed":bu,step:_u,"step-before":wu,"step-after":Su,basis:zu,"basis-open":Lu,"basis-closed":qu,bundle:Tu,cardinal:Eu,"cardinal-open":ku,"cardinal-closed":Nu,monotone:Fu});Tl.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var Rl=[0,2/3,1/3,0],Dl=[0,1/3,2/3,0],Pl=[0,1/6,2/3,1/6];ao.svg.line.radial=function(){var n=Mu(Hu);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},wu.reverse=Su,Su.reverse=wu,ao.svg.area=function(){return Ou(m)},ao.svg.area.radial=function(){var n=Ou(Hu);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},ao.svg.chord=function(){function n(n,a){var l=t(this,u,n,a),c=t(this,o,n,a);return"M"+l.p0+r(l.r,l.p1,l.a1-l.a0)+(e(l,c)?i(l.r,l.p1,l.r,l.p0):i(l.r,l.p1,c.r,c.p0)+r(c.r,c.p1,c.a1-c.a0)+i(c.r,c.p1,l.r,l.p0))+"Z"}function t(n,t,e,r){var i=t.call(n,e,r),u=a.call(n,i,r),o=l.call(n,i,r)-Io,f=c.call(n,i,r)-Io;return{r:u,a0:o,a1:f,p0:[u*Math.cos(o),u*Math.sin(o)],p1:[u*Math.cos(f),u*Math.sin(f)]}}function e(n,t){return n.a0==t.a0&&n.a1==t.a1}function r(n,t,e){return"A"+n+","+n+" 0 "+ +(e>Fo)+",1 "+t}function i(n,t,e,r){return"Q 0,0 "+r}var u=Me,o=xe,a=Iu,l=gu,c=vu;return n.radius=function(t){return arguments.length?(a=En(t),n):a},n.source=function(t){return arguments.length?(u=En(t),n):u},n.target=function(t){return arguments.length?(o=En(t),n):o},n.startAngle=function(t){return arguments.length?(l=En(t),n):l},n.endAngle=function(t){return arguments.length?(c=En(t),n):c},n},ao.svg.diagonal=function(){function n(n,i){var u=t.call(this,n,i),o=e.call(this,n,i),a=(u.y+o.y)/2,l=[u,{x:u.x,y:a},{x:o.x,y:a},o];return l=l.map(r),"M"+l[0]+"C"+l[1]+" "+l[2]+" "+l[3]}var t=Me,e=xe,r=Yu;return n.source=function(e){return arguments.length?(t=En(e),n):t},n.target=function(t){return arguments.length?(e=En(t),n):e},n.projection=function(t){return arguments.length?(r=t,n):r},n},ao.svg.diagonal.radial=function(){var n=ao.svg.diagonal(),t=Yu,e=n.projection;return n.projection=function(n){return arguments.length?e(Zu(t=n)):t},n},ao.svg.symbol=function(){function n(n,r){return(Ul.get(t.call(this,n,r))||$u)(e.call(this,n,r))}var t=Xu,e=Vu;return n.type=function(e){return arguments.length?(t=En(e),n):t},n.size=function(t){return arguments.length?(e=En(t),n):e},n};var Ul=ao.map({circle:$u,cross:function(n){var t=Math.sqrt(n/5)/2;return"M"+-3*t+","+-t+"H"+-t+"V"+-3*t+"H"+t+"V"+-t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+-t+"V"+t+"H"+-3*t+"Z"},diamond:function(n){var t=Math.sqrt(n/(2*Fl)),e=t*Fl;return"M0,"+-t+"L"+e+",0 0,"+t+" "+-e+",0Z"},square:function(n){var t=Math.sqrt(n)/2;return"M"+-t+","+-t+"L"+t+","+-t+" "+t+","+t+" "+-t+","+t+"Z"},"triangle-down":function(n){var t=Math.sqrt(n/jl),e=t*jl/2;return"M0,"+e+"L"+t+","+-e+" "+-t+","+-e+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/jl),e=t*jl/2;return"M0,"+-e+"L"+t+","+e+" "+-t+","+e+"Z"}});ao.svg.symbolTypes=Ul.keys();var jl=Math.sqrt(3),Fl=Math.tan(30*Yo);Co.transition=function(n){for(var t,e,r=Hl||++Zl,i=Ku(n),u=[],o=Ol||{time:Date.now(),ease:Nr,delay:0,duration:250},a=-1,l=this.length;++a<l;){u.push(t=[]);for(var c=this[a],f=-1,s=c.length;++f<s;)(e=c[f])&&Qu(e,f,i,r,o),t.push(e)}return Wu(u,i,r)},Co.interrupt=function(n){return this.each(null==n?Il:Bu(Ku(n)))};var Hl,Ol,Il=Bu(Ku()),Yl=[],Zl=0;Yl.call=Co.call,Yl.empty=Co.empty,Yl.node=Co.node,Yl.size=Co.size,ao.transition=function(n,t){return n&&n.transition?Hl?n.transition(t):n:ao.selection().transition(n)},ao.transition.prototype=Yl,Yl.select=function(n){var t,e,r,i=this.id,u=this.namespace,o=[];n=A(n);for(var a=-1,l=this.length;++a<l;){o.push(t=[]);for(var c=this[a],f=-1,s=c.length;++f<s;)(r=c[f])&&(e=n.call(r,r.__data__,f,a))?("__data__"in r&&(e.__data__=r.__data__),Qu(e,f,u,i,r[u][i]),t.push(e)):t.push(null)}return Wu(o,u,i)},Yl.selectAll=function(n){var t,e,r,i,u,o=this.id,a=this.namespace,l=[];n=C(n);for(var c=-1,f=this.length;++c<f;)for(var s=this[c],h=-1,p=s.length;++h<p;)if(r=s[h]){u=r[a][o],e=n.call(r,r.__data__,h,c),l.push(t=[]);for(var g=-1,v=e.length;++g<v;)(i=e[g])&&Qu(i,g,a,o,u),t.push(i)}return Wu(l,a,o)},Yl.filter=function(n){var t,e,r,i=[];"function"!=typeof n&&(n=O(n));for(var u=0,o=this.length;o>u;u++){i.push(t=[]);for(var e=this[u],a=0,l=e.length;l>a;a++)(r=e[a])&&n.call(r,r.__data__,a,u)&&t.push(r)}return Wu(i,this.namespace,this.id)},Yl.tween=function(n,t){var e=this.id,r=this.namespace;return arguments.length<2?this.node()[r][e].tween.get(n):Y(this,null==t?function(t){t[r][e].tween.remove(n)}:function(i){i[r][e].tween.set(n,t)})},Yl.attr=function(n,t){function e(){this.removeAttribute(a)}function r(){this.removeAttributeNS(a.space,a.local)}function i(n){return null==n?e:(n+="",function(){var t,e=this.getAttribute(a);return e!==n&&(t=o(e,n),function(n){this.setAttribute(a,t(n))})})}function u(n){return null==n?r:(n+="",function(){var t,e=this.getAttributeNS(a.space,a.local);return e!==n&&(t=o(e,n),function(n){this.setAttributeNS(a.space,a.local,t(n))})})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var o="transform"==n?$r:Mr,a=ao.ns.qualify(n);return Ju(this,"attr."+n,t,a.local?u:i)},Yl.attrTween=function(n,t){function e(n,e){var r=t.call(this,n,e,this.getAttribute(i));return r&&function(n){this.setAttribute(i,r(n))}}function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(i.space,i.local));return r&&function(n){this.setAttributeNS(i.space,i.local,r(n))}}var i=ao.ns.qualify(n);return this.tween("attr."+n,i.local?r:e)},Yl.style=function(n,e,r){function i(){this.style.removeProperty(n)}function u(e){return null==e?i:(e+="",function(){var i,u=t(this).getComputedStyle(this,null).getPropertyValue(n);return u!==e&&(i=Mr(u,e),function(t){this.style.setProperty(n,i(t),r)})})}var o=arguments.length;if(3>o){if("string"!=typeof n){2>o&&(e="");for(r in n)this.style(r,n[r],e);return this}r=""}return Ju(this,"style."+n,e,u)},Yl.styleTween=function(n,e,r){function i(i,u){var o=e.call(this,i,u,t(this).getComputedStyle(this,null).getPropertyValue(n));return o&&function(t){this.style.setProperty(n,o(t),r)}}return arguments.length<3&&(r=""),this.tween("style."+n,i)},Yl.text=function(n){return Ju(this,"text",n,Gu)},Yl.remove=function(){var n=this.namespace;return this.each("end.transition",function(){var t;this[n].count<2&&(t=this.parentNode)&&t.removeChild(this)})},Yl.ease=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].ease:("function"!=typeof n&&(n=ao.ease.apply(ao,arguments)),Y(this,function(r){r[e][t].ease=n}))},Yl.delay=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].delay:Y(this,"function"==typeof n?function(r,i,u){r[e][t].delay=+n.call(r,r.__data__,i,u)}:(n=+n,function(r){r[e][t].delay=n}))},Yl.duration=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].duration:Y(this,"function"==typeof n?function(r,i,u){r[e][t].duration=Math.max(1,n.call(r,r.__data__,i,u))}:(n=Math.max(1,n),function(r){r[e][t].duration=n}))},Yl.each=function(n,t){var e=this.id,r=this.namespace;if(arguments.length<2){var i=Ol,u=Hl;try{Hl=e,Y(this,function(t,i,u){Ol=t[r][e],n.call(t,t.__data__,i,u)})}finally{Ol=i,Hl=u}}else Y(this,function(i){var u=i[r][e];(u.event||(u.event=ao.dispatch("start","end","interrupt"))).on(n,t)});return this},Yl.transition=function(){for(var n,t,e,r,i=this.id,u=++Zl,o=this.namespace,a=[],l=0,c=this.length;c>l;l++){a.push(n=[]);for(var t=this[l],f=0,s=t.length;s>f;f++)(e=t[f])&&(r=e[o][i],Qu(e,f,o,u,{time:r.time,ease:r.ease,delay:r.delay+r.duration,duration:r.duration})),n.push(e)}return Wu(a,o,u)},ao.svg.axis=function(){function n(n){n.each(function(){var n,c=ao.select(this),f=this.__chart__||e,s=this.__chart__=e.copy(),h=null==l?s.ticks?s.ticks.apply(s,a):s.domain():l,p=null==t?s.tickFormat?s.tickFormat.apply(s,a):m:t,g=c.selectAll(".tick").data(h,s),v=g.enter().insert("g",".domain").attr("class","tick").style("opacity",Uo),d=ao.transition(g.exit()).style("opacity",Uo).remove(),y=ao.transition(g.order()).style("opacity",1),M=Math.max(i,0)+o,x=Zi(s),b=c.selectAll(".domain").data([0]),_=(b.enter().append("path").attr("class","domain"),ao.transition(b));v.append("line"),v.append("text");var w,S,k,N,E=v.select("line"),A=y.select("line"),C=g.select("text").text(p),z=v.select("text"),L=y.select("text"),q="top"===r||"left"===r?-1:1;if("bottom"===r||"top"===r?(n=no,w="x",k="y",S="x2",N="y2",C.attr("dy",0>q?"0em":".71em").style("text-anchor","middle"),_.attr("d","M"+x[0]+","+q*u+"V0H"+x[1]+"V"+q*u)):(n=to,w="y",k="x",S="y2",N="x2",C.attr("dy",".32em").style("text-anchor",0>q?"end":"start"),_.attr("d","M"+q*u+","+x[0]+"H0V"+x[1]+"H"+q*u)),E.attr(N,q*i),z.attr(k,q*M),A.attr(S,0).attr(N,q*i),L.attr(w,0).attr(k,q*M),s.rangeBand){var T=s,R=T.rangeBand()/2;f=s=function(n){return T(n)+R}}else f.rangeBand?f=s:d.call(n,s,f);v.call(n,f,s),y.call(n,s,s)})}var t,e=ao.scale.linear(),r=Vl,i=6,u=6,o=3,a=[10],l=null;return n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return arguments.length?(r=t in Xl?t+"":Vl,n):r},n.ticks=function(){return arguments.length?(a=co(arguments),n):a},n.tickValues=function(t){return arguments.length?(l=t,n):l},n.tickFormat=function(e){return arguments.length?(t=e,n):t},n.tickSize=function(t){var e=arguments.length;return e?(i=+t,u=+arguments[e-1],n):i},n.innerTickSize=function(t){return arguments.length?(i=+t,n):i},n.outerTickSize=function(t){return arguments.length?(u=+t,n):u},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(){return arguments.length&&n},n};var Vl="bottom",Xl={top:1,right:1,bottom:1,left:1};ao.svg.brush=function(){function n(t){t.each(function(){var t=ao.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",u).on("touchstart.brush",u),o=t.selectAll(".background").data([0]);o.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),t.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var a=t.selectAll(".resize").data(v,m);a.exit().remove(),a.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return $l[n]}).append("rect").attr("x",function(n){return/[ew]$/.test(n)?-3:null}).attr("y",function(n){return/^[ns]/.test(n)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),a.style("display",n.empty()?"none":null);var l,s=ao.transition(t),h=ao.transition(o);c&&(l=Zi(c),h.attr("x",l[0]).attr("width",l[1]-l[0]),r(s)),f&&(l=Zi(f),h.attr("y",l[0]).attr("height",l[1]-l[0]),i(s)),e(s)})}function e(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+s[+/e$/.test(n)]+","+h[+/^s/.test(n)]+")"})}function r(n){n.select(".extent").attr("x",s[0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",s[1]-s[0])}function i(n){n.select(".extent").attr("y",h[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",h[1]-h[0])}function u(){function u(){32==ao.event.keyCode&&(C||(M=null,L[0]-=s[1],L[1]-=h[1],C=2),S())}function v(){32==ao.event.keyCode&&2==C&&(L[0]+=s[1],L[1]+=h[1],C=0,S())}function d(){var n=ao.mouse(b),t=!1;x&&(n[0]+=x[0],n[1]+=x[1]),C||(ao.event.altKey?(M||(M=[(s[0]+s[1])/2,(h[0]+h[1])/2]),L[0]=s[+(n[0]<M[0])],L[1]=h[+(n[1]<M[1])]):M=null),E&&y(n,c,0)&&(r(k),t=!0),A&&y(n,f,1)&&(i(k),t=!0),t&&(e(k),w({type:"brush",mode:C?"move":"resize"}))}function y(n,t,e){var r,i,u=Zi(t),l=u[0],c=u[1],f=L[e],v=e?h:s,d=v[1]-v[0];return C&&(l-=f,c-=d+f),r=(e?g:p)?Math.max(l,Math.min(c,n[e])):n[e],C?i=(r+=f)+d:(M&&(f=Math.max(l,Math.min(c,2*M[e]-r))),r>f?(i=r,r=f):i=f),v[0]!=r||v[1]!=i?(e?a=null:o=null,v[0]=r,v[1]=i,!0):void 0}function m(){d(),k.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),ao.select("body").style("cursor",null),q.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),z(),w({type:"brushend"})}var M,x,b=this,_=ao.select(ao.event.target),w=l.of(b,arguments),k=ao.select(b),N=_.datum(),E=!/^(n|s)$/.test(N)&&c,A=!/^(e|w)$/.test(N)&&f,C=_.classed("extent"),z=W(b),L=ao.mouse(b),q=ao.select(t(b)).on("keydown.brush",u).on("keyup.brush",v);if(ao.event.changedTouches?q.on("touchmove.brush",d).on("touchend.brush",m):q.on("mousemove.brush",d).on("mouseup.brush",m),k.interrupt().selectAll("*").interrupt(),C)L[0]=s[0]-L[0],L[1]=h[0]-L[1];else if(N){var T=+/w$/.test(N),R=+/^n/.test(N);x=[s[1-T]-L[0],h[1-R]-L[1]],L[0]=s[T],L[1]=h[R]}else ao.event.altKey&&(M=L.slice());k.style("pointer-events","none").selectAll(".resize").style("display",null),ao.select("body").style("cursor",_.style("cursor")),w({type:"brushstart"}),d()}var o,a,l=N(n,"brushstart","brush","brushend"),c=null,f=null,s=[0,0],h=[0,0],p=!0,g=!0,v=Bl[0];return n.event=function(n){n.each(function(){var n=l.of(this,arguments),t={x:s,y:h,i:o,j:a},e=this.__chart__||t;this.__chart__=t,Hl?ao.select(this).transition().each("start.brush",function(){o=e.i,a=e.j,s=e.x,h=e.y,n({type:"brushstart"})}).tween("brush:brush",function(){var e=xr(s,t.x),r=xr(h,t.y);return o=a=null,function(i){s=t.x=e(i),h=t.y=r(i),n({type:"brush",mode:"resize"})}}).each("end.brush",function(){o=t.i,a=t.j,n({type:"brush",mode:"resize"}),n({type:"brushend"})}):(n({type:"brushstart"}),n({type:"brush",mode:"resize"}),n({type:"brushend"}))})},n.x=function(t){return arguments.length?(c=t,v=Bl[!c<<1|!f],n):c},n.y=function(t){return arguments.length?(f=t,v=Bl[!c<<1|!f],n):f},n.clamp=function(t){return arguments.length?(c&&f?(p=!!t[0],g=!!t[1]):c?p=!!t:f&&(g=!!t),n):c&&f?[p,g]:c?p:f?g:null},n.extent=function(t){var e,r,i,u,l;return arguments.length?(c&&(e=t[0],r=t[1],f&&(e=e[0],r=r[0]),o=[e,r],c.invert&&(e=c(e),r=c(r)),e>r&&(l=e,e=r,r=l),e==s[0]&&r==s[1]||(s=[e,r])),f&&(i=t[0],u=t[1],c&&(i=i[1],u=u[1]),a=[i,u],f.invert&&(i=f(i),u=f(u)),i>u&&(l=i,i=u,u=l),i==h[0]&&u==h[1]||(h=[i,u])),n):(c&&(o?(e=o[0],r=o[1]):(e=s[0],r=s[1],c.invert&&(e=c.invert(e),r=c.invert(r)),e>r&&(l=e,e=r,r=l))),f&&(a?(i=a[0],u=a[1]):(i=h[0],u=h[1],f.invert&&(i=f.invert(i),u=f.invert(u)),i>u&&(l=i,i=u,u=l))),c&&f?[[e,i],[r,u]]:c?[e,r]:f&&[i,u])},n.clear=function(){return n.empty()||(s=[0,0],h=[0,0],o=a=null),n},n.empty=function(){return!!c&&s[0]==s[1]||!!f&&h[0]==h[1]},ao.rebind(n,l,"on")};var $l={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Bl=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Wl=ga.format=xa.timeFormat,Jl=Wl.utc,Gl=Jl("%Y-%m-%dT%H:%M:%S.%LZ");Wl.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?eo:Gl,eo.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},eo.toString=Gl.toString,ga.second=On(function(n){return new va(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),ga.seconds=ga.second.range,ga.seconds.utc=ga.second.utc.range,ga.minute=On(function(n){return new va(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),ga.minutes=ga.minute.range,ga.minutes.utc=ga.minute.utc.range,ga.hour=On(function(n){var t=n.getTimezoneOffset()/60;return new va(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),ga.hours=ga.hour.range,ga.hours.utc=ga.hour.utc.range,ga.month=On(function(n){return n=ga.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),ga.months=ga.month.range,ga.months.utc=ga.month.utc.range;var Kl=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],Ql=[[ga.second,1],[ga.second,5],[ga.second,15],[ga.second,30],[ga.minute,1],[ga.minute,5],[ga.minute,15],[ga.minute,30],[ga.hour,1],[ga.hour,3],[ga.hour,6],[ga.hour,12],[ga.day,1],[ga.day,2],[ga.week,1],[ga.month,1],[ga.month,3],[ga.year,1]],nc=Wl.multi([[".%L",function(n){return n.getMilliseconds()}],[":%S",function(n){return n.getSeconds()}],["%I:%M",function(n){return n.getMinutes()}],["%I %p",function(n){return n.getHours()}],["%a %d",function(n){return n.getDay()&&1!=n.getDate()}],["%b %d",function(n){return 1!=n.getDate()}],["%B",function(n){return n.getMonth()}],["%Y",zt]]),tc={range:function(n,t,e){return ao.range(Math.ceil(n/e)*e,+t,e).map(io)},floor:m,ceil:m};Ql.year=ga.year,ga.scale=function(){return ro(ao.scale.linear(),Ql,nc)};var ec=Ql.map(function(n){return[n[0].utc,n[1]]}),rc=Jl.multi([[".%L",function(n){return n.getUTCMilliseconds()}],[":%S",function(n){return n.getUTCSeconds()}],["%I:%M",function(n){return n.getUTCMinutes()}],["%I %p",function(n){return n.getUTCHours()}],["%a %d",function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],["%b %d",function(n){return 1!=n.getUTCDate()}],["%B",function(n){return n.getUTCMonth()}],["%Y",zt]]);ec.year=ga.year.utc,ga.scale.utc=function(){return ro(ao.scale.linear(),ec,rc)},ao.text=An(function(n){return n.responseText}),ao.json=function(n,t){return Cn(n,"application/json",uo,t)},ao.html=function(n,t){return Cn(n,"text/html",oo,t)},ao.xml=An(function(n){return n.responseXML}),"function"==typeof define&&define.amd?(this.d3=ao,define(ao)):"object"==typeof module&&module.exports?module.exports=ao:this.d3=ao}();
 
 
 
 
 
inc/js/scripts.js CHANGED
@@ -82,9 +82,26 @@ jQuery(document).ready(function ($) {
82
  $('.sucuriscan-container').on('mouseover', '.sucuriscan-tooltip', function (event) {
83
  var element = $(this);
84
  var content = element.attr('content');
 
 
 
 
 
 
85
  var tooltip = $('<div>', { 'class': 'sucuriscan-tooltip-object' });
86
 
87
- tooltip.text(content);
 
 
 
 
 
 
 
 
 
 
 
88
  element.append(tooltip);
89
  var arrowHeight = 10; /* border width */
90
  var tooltipHeight = tooltip.outerHeight();
82
  $('.sucuriscan-container').on('mouseover', '.sucuriscan-tooltip', function (event) {
83
  var element = $(this);
84
  var content = element.attr('content');
85
+
86
+ if (!content) {
87
+ return;
88
+ }
89
+
90
+ /* create instance of tooltip container */
91
  var tooltip = $('<div>', { 'class': 'sucuriscan-tooltip-object' });
92
 
93
+ if (element.attr('tooltip-width')) {
94
+ var customWidth = element.attr('tooltip-width');
95
+ tooltip.css('width', customWidth);
96
+ }
97
+
98
+ /* interpret HTML code as is; careful with XSS */
99
+ if (element.attr('tooltip-html') === 'true') {
100
+ tooltip.html(content);
101
+ } else {
102
+ tooltip.text(content);
103
+ }
104
+
105
  element.append(tooltip);
106
  var arrowHeight = 10; /* border width */
107
  var tooltipHeight = tooltip.outerHeight();
inc/tpl/auditlogs-report.html.tpl DELETED
@@ -1,103 +0,0 @@
1
-
2
- <script type="text/javascript">
3
- /* global c3 */
4
- /* global jQuery */
5
- /* jshint camelcase:false */
6
- jQuery(function ($) {
7
- var sucuriscanPieChart = function (element, series, colors) {
8
- c3.generate({
9
- bindto: element,
10
- size: { height: 250 },
11
- padding: { top: 10, bottom: 10 },
12
- color: { pattern: colors },
13
- legend: { position: 'right' },
14
- data: { type: 'pie', labels: true, columns: series },
15
- });
16
- };
17
-
18
- var sucuriscanBarChart = function (element, categories, series) {
19
- c3.generate({
20
- bindto: element,
21
- size: { height: 320 },
22
- padding: { top: 10, bottom: 0 },
23
- tooltip: { show: false },
24
- legend: { show: false },
25
- data: { type: 'bar', labels: true, columns: [ series ] },
26
- axis: {
27
- rotated: true,
28
- x: { type: 'category', categories: categories },
29
- },
30
- });
31
- };
32
-
33
- $.post('%%SUCURI.AjaxURL.Dashboard%%', {
34
- action: 'sucuriscan_ajax',
35
- sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
36
- form_action: 'get_audit_logs_report',
37
- }, function (data) {
38
- $('#sucuriscan-audit-report-response').html(data.message);
39
-
40
- if (data.status) {
41
- $('.sucuriscan-report-chart').removeClass('sucuriscan-hidden');
42
-
43
- /* Pie-chart with number of audit logs per event type. */
44
- sucuriscanPieChart(
45
- '#sucuriscan-report-events-per-type',
46
- data.eventsPerTypePoints,
47
- data.eventsPerTypeColors
48
- );
49
-
50
- /* Column-chart with number of audit logs per event login. */
51
- sucuriscanPieChart(
52
- '#sucuriscan-report-events-per-login',
53
- data.eventsPerLogin,
54
- [ '#5cb85c', '#f27d7d' ]
55
- );
56
-
57
- /* Bar-chart with number of audit logs per user account. */
58
- sucuriscanBarChart(
59
- '#sucuriscan-report-events-per-user',
60
- data.eventsPerUserCategories,
61
- data.eventsPerUserSeries
62
- );
63
-
64
- /* Bar-chart with number of audit logs per remote address. */
65
- sucuriscanBarChart(
66
- '#sucuriscan-report-events-per-ipaddress',
67
- data.eventsPerIPAddressCategories,
68
- data.eventsPerIPAddressSeries
69
- );
70
- }
71
- });
72
- });
73
- </script>
74
-
75
- <div class="sucuriscan-audit-report">
76
- <div class="sucuriscan-inline-alert-info">
77
- <p>@@SUCURI.LogsReportInfo@@</p>
78
- </div>
79
-
80
- <div id="sucuriscan-audit-report-response">
81
- <p>@@SUCURI.Loading@@</p>
82
- </div>
83
-
84
- <div class="sucuriscan-report-chart sucuriscan-hidden">
85
- <h4>@@SUCURI.LogsPerEvent@@</h4>
86
- <div id="sucuriscan-report-events-per-type"></div>
87
- </div>
88
-
89
- <div class="sucuriscan-report-chart sucuriscan-hidden">
90
- <h4>@@SUCURI.LogsForLogins@@</h4>
91
- <div id="sucuriscan-report-events-per-login"></div>
92
- </div>
93
-
94
- <div class="sucuriscan-report-chart sucuriscan-hidden">
95
- <h4>@@SUCURI.LogsPerUser@@</h4>
96
- <div id="sucuriscan-report-events-per-user"></div>
97
- </div>
98
-
99
- <div class="sucuriscan-report-chart sucuriscan-hidden">
100
- <h4>@@SUCURI.LogsPerIP@@</h4>
101
- <div id="sucuriscan-report-events-per-ipaddress"></div>
102
- </div>
103
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
inc/tpl/auditlogs.html.tpl CHANGED
@@ -3,8 +3,7 @@
3
  /* global jQuery */
4
  /* jshint camelcase:false */
5
  jQuery(function ($) {
6
- var writeQueueSize = function (queueSize)
7
- {
8
  if (queueSize === 0) {
9
  $('.sucuriscan-auditlogs-sendlogs-response').html('');
10
  $('.sucuriscan-sendlogs-panel').addClass('sucuriscan-hidden');
@@ -15,19 +14,16 @@ jQuery(function ($) {
15
  }
16
  };
17
 
18
- var sucuriscanLoadAuditLogs = function (page, reset) {
19
  var url = '%%SUCURI.AjaxURL.Dashboard%%';
20
 
21
  if (page !== undefined && page > 0) {
22
  url += '&paged=' + page;
23
  }
24
 
25
- if (reset === true) {
26
- $('.sucuriscan-auditlog-response').html('<em>@@SUCURI.Loading@@</em>');
27
- }
28
-
29
- $('.sucuriscan-auditlog-status').html('');
30
- $('.sucuriscan-pagination-loading').html('');
31
  $('.sucuriscan-pagination-panel').addClass('sucuriscan-hidden');
32
  $('.sucuriscan-auditlog-footer').addClass('sucuriscan-hidden');
33
 
@@ -63,23 +59,44 @@ jQuery(function ($) {
63
  }
64
 
65
  setTimeout(function () {
66
- sucuriscanLoadAuditLogs(0, true);
67
  }, 100);
68
 
69
  $('.sucuriscan-auditlog-table').on('click', '.sucuriscan-pagination-link', function (event) {
70
  event.preventDefault();
 
71
  sucuriscanLoadAuditLogs($(this).attr('data-page'));
72
  });
73
 
74
  $('.sucuriscan-auditlog-table').on('click', '.sucuriscan-auditlogs-sendlogs', function (event) {
75
  event.preventDefault();
 
 
76
  $('.sucuriscan-auditlogs-sendlogs-response').html('@@SUCURI.Loading@@');
 
77
  $.post('%%SUCURI.AjaxURL.Dashboard%%', {
78
  action: 'sucuriscan_ajax',
79
  sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
80
  form_action: 'auditlogs_send_logs',
81
- }, function () {
82
- sucuriscanLoadAuditLogs(0, true);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  });
84
  });
85
  });
@@ -101,7 +118,8 @@ jQuery(function ($) {
101
  </div>
102
 
103
  <div class="sucuriscan-clearfix sucuriscan-auditlog-footer">
104
- <div class="sucuriscan-pull-left sucuriscan-hidden sucuriscan-sendlogs-panel">
 
105
  <small class="sucuriscan-auditlogs-sendlogs-response"></small>
106
  <small><a href="#" class="sucuriscan-auditlogs-sendlogs">@@SUCURI.SendLogs@@</a></small>
107
  </div>
3
  /* global jQuery */
4
  /* jshint camelcase:false */
5
  jQuery(function ($) {
6
+ var writeQueueSize = function (queueSize) {
 
7
  if (queueSize === 0) {
8
  $('.sucuriscan-auditlogs-sendlogs-response').html('');
9
  $('.sucuriscan-sendlogs-panel').addClass('sucuriscan-hidden');
14
  }
15
  };
16
 
17
+ var sucuriscanLoadAuditLogs = function (page) {
18
  var url = '%%SUCURI.AjaxURL.Dashboard%%';
19
 
20
  if (page !== undefined && page > 0) {
21
  url += '&paged=' + page;
22
  }
23
 
24
+ $('.sucuriscan-auditlog-response').html('<em>@@SUCURI.Loading@@</em>');
25
+ $('.sucuriscan-auditlog-status').html('@@SUCURI.Loading@@');
26
+ $('.sucuriscan-pagination-loading').html('@@SUCURI.Loading@@');
 
 
 
27
  $('.sucuriscan-pagination-panel').addClass('sucuriscan-hidden');
28
  $('.sucuriscan-auditlog-footer').addClass('sucuriscan-hidden');
29
 
59
  }
60
 
61
  setTimeout(function () {
62
+ sucuriscanLoadAuditLogs(0);
63
  }, 100);
64
 
65
  $('.sucuriscan-auditlog-table').on('click', '.sucuriscan-pagination-link', function (event) {
66
  event.preventDefault();
67
+ window.scrollTo(0, $('#sucuriscan-integrity-response').height() + 100);
68
  sucuriscanLoadAuditLogs($(this).attr('data-page'));
69
  });
70
 
71
  $('.sucuriscan-auditlog-table').on('click', '.sucuriscan-auditlogs-sendlogs', function (event) {
72
  event.preventDefault();
73
+
74
+ $('.sucuriscan-sendlogs-panel').attr('content', '');
75
  $('.sucuriscan-auditlogs-sendlogs-response').html('@@SUCURI.Loading@@');
76
+
77
  $.post('%%SUCURI.AjaxURL.Dashboard%%', {
78
  action: 'sucuriscan_ajax',
79
  sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
80
  form_action: 'auditlogs_send_logs',
81
+ }, function (data) {
82
+ sucuriscanLoadAuditLogs(0);
83
+
84
+ setTimeout(function (){
85
+ var tooltipContent =
86
+ 'Total logs in the queue: {TTLLOGS}<br>' +
87
+ 'Maximum execution time: {MAXTIME}<br>' +
88
+ 'Successfully sent to the API: {SUCCESS}<br>' +
89
+ 'Total request timeouts (failures): {FAILURE}<br>' +
90
+ 'Total execution time: {ELAPSED} secs';
91
+ $('.sucuriscan-sendlogs-panel')
92
+ .attr('content', tooltipContent
93
+ .replace('{MAXTIME}', data.maxtime)
94
+ .replace('{TTLLOGS}', data.ttllogs)
95
+ .replace('{SUCCESS}', data.success)
96
+ .replace('{FAILURE}', data.failure)
97
+ .replace('{ELAPSED}', data.elapsed)
98
+ );
99
+ }, 200);
100
  });
101
  });
102
  });
118
  </div>
119
 
120
  <div class="sucuriscan-clearfix sucuriscan-auditlog-footer">
121
+ <div class="sucuriscan-pull-left sucuriscan-hidden sucuriscan-tooltip
122
+ sucuriscan-sendlogs-panel" tooltip-width="250" tooltip-html="true">
123
  <small class="sucuriscan-auditlogs-sendlogs-response"></small>
124
  <small><a href="#" class="sucuriscan-auditlogs-sendlogs">@@SUCURI.SendLogs@@</a></small>
125
  </div>
inc/tpl/dashboard.html.tpl CHANGED
@@ -5,6 +5,26 @@
5
  /* global jQuery */
6
  /* jshint camelcase: false */
7
  jQuery(function ($) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  $.post('%%SUCURI.AjaxURL.Dashboard%%', {
9
  action: 'sucuriscan_ajax',
10
  sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
@@ -14,9 +34,9 @@ jQuery(function ($) {
14
  $('#sucuriscan-title-links').html(data.links.title);
15
  $('#sucuriscan-title-scripts').html(data.scripts.title);
16
 
17
- $('#sucuriscan-tabs-iframes').html(data.iframes.content);
18
- $('#sucuriscan-tabs-links').html(data.links.content);
19
- $('#sucuriscan-tabs-scripts').html(data.scripts.content);
20
 
21
  $('#sucuriscan-malware').html(data.malware);
22
  $('#sucuriscan-blacklist').html(data.blacklist);
@@ -31,7 +51,6 @@ jQuery(function ($) {
31
  <div class="sucuriscan-tabs">
32
  <ul class="sucuriscan-clearfix sucuriscan-tabs-buttons">
33
  <li><a href="%%SUCURI.URL.Dashboard%%#auditlogs">@@SUCURI.AuditLogs@@</a></li>
34
- <li><a href="%%SUCURI.URL.Dashboard%%#stats">@@SUCURI.Statistics@@</a></li>
35
  <li><a href="%%SUCURI.URL.Dashboard%%#iframes" id="sucuriscan-title-iframes">%%SUCURI.SiteCheck.iFramesTitle%%</a></li>
36
  <li><a href="%%SUCURI.URL.Dashboard%%#links" id="sucuriscan-title-links">%%SUCURI.SiteCheck.LinksTitle%%</a></li>
37
  <li><a href="%%SUCURI.URL.Dashboard%%#scripts" id="sucuriscan-title-scripts">%%SUCURI.SiteCheck.ScriptsTitle%%</a></li>
@@ -42,10 +61,6 @@ jQuery(function ($) {
42
  %%%SUCURI.AuditLogs%%%
43
  </div>
44
 
45
- <div id="sucuriscan-tabs-stats">
46
- %%%SUCURI.AuditLogsReport%%%
47
- </div>
48
-
49
  <div id="sucuriscan-tabs-iframes">
50
  %%%SUCURI.SiteCheck.iFramesContent%%%
51
  </div>
5
  /* global jQuery */
6
  /* jshint camelcase: false */
7
  jQuery(function ($) {
8
+ var sucuriscanSiteCheckLinks = function (target, links) {
9
+ if (links.length === 0) {
10
+ $(target).html('<div><em>@@SUCURI.NoData@@</em></div>');
11
+ return;
12
+ }
13
+
14
+ var tbody = $('<tbody>');
15
+ var options = {class: 'wp-list-table widefat sucuriscan-table'};
16
+
17
+ for (var key in links) {
18
+ if (links.hasOwnProperty(key)) {
19
+ tbody.append('<tr><td><a href="' + links[key] + '" target="_b' +
20
+ 'lank" class="sucuriscan-monospace">' + links[key] + '</a></t' +
21
+ 'd></tr>');
22
+ }
23
+ }
24
+
25
+ $(target).html($('<table>', options).html(tbody));
26
+ };
27
+
28
  $.post('%%SUCURI.AjaxURL.Dashboard%%', {
29
  action: 'sucuriscan_ajax',
30
  sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
34
  $('#sucuriscan-title-links').html(data.links.title);
35
  $('#sucuriscan-title-scripts').html(data.scripts.title);
36
 
37
+ sucuriscanSiteCheckLinks('#sucuriscan-tabs-iframes', data.iframes.content);
38
+ sucuriscanSiteCheckLinks('#sucuriscan-tabs-links', data.links.content);
39
+ sucuriscanSiteCheckLinks('#sucuriscan-tabs-scripts', data.scripts.content);
40
 
41
  $('#sucuriscan-malware').html(data.malware);
42
  $('#sucuriscan-blacklist').html(data.blacklist);
51
  <div class="sucuriscan-tabs">
52
  <ul class="sucuriscan-clearfix sucuriscan-tabs-buttons">
53
  <li><a href="%%SUCURI.URL.Dashboard%%#auditlogs">@@SUCURI.AuditLogs@@</a></li>
 
54
  <li><a href="%%SUCURI.URL.Dashboard%%#iframes" id="sucuriscan-title-iframes">%%SUCURI.SiteCheck.iFramesTitle%%</a></li>
55
  <li><a href="%%SUCURI.URL.Dashboard%%#links" id="sucuriscan-title-links">%%SUCURI.SiteCheck.LinksTitle%%</a></li>
56
  <li><a href="%%SUCURI.URL.Dashboard%%#scripts" id="sucuriscan-title-scripts">%%SUCURI.SiteCheck.ScriptsTitle%%</a></li>
61
  %%%SUCURI.AuditLogs%%%
62
  </div>
63
 
 
 
 
 
64
  <div id="sucuriscan-tabs-iframes">
65
  %%%SUCURI.SiteCheck.iFramesContent%%%
66
  </div>
inc/tpl/firewall-auditlogs.snippet.tpl CHANGED
@@ -1,43 +1,47 @@
1
 
2
  <tr>
3
- <td>
4
- <div class="sucuriscan-firewall-accesslog sucuriscan-monospace">
5
- <div class="sucuriscan-accesslog-origin">
6
- <img src="%%SUCURI.SucuriURL%%/inc/images/blank.png"
7
- class="sucuriscan-flag sucuriscan-flag-%%SUCURI.AccessLog.RequestCountryCode%%" />
8
- <span>%%SUCURI.AccessLog.RemoteAddr%%</span>
9
- <span>(%%SUCURI.AccessLog.RequestCountryName%%)</span>
10
- </div>
11
- <div class="sucuriscan-accesslog-datetime">
12
- <span class="sucuriscan-accesslog-label">Date/Time:</span>
13
- <span>%%SUCURI.AccessLog.RequestDate%%</span>
14
- <span>%%SUCURI.AccessLog.RequestTime%%</span>
15
- <span>%%SUCURI.AccessLog.RequestTimezone%%</span>
16
- </div>
17
- <div class="sucuriscan-accesslog-signature">
18
- <span class="sucuriscan-accesslog-label">Signature:</span>
19
- <span>%%SUCURI.AccessLog.SucuriBlockCode%%</span>
20
- <span>(%%SUCURI.AccessLog.SucuriBlockReason%%)</span>
21
- </div>
22
- <div class="sucuriscan-accesslog-request">
23
- <span class="sucuriscan-accesslog-label">Request:</span>
24
- <span>%%SUCURI.AccessLog.HttpProtocol%%</span>
25
- <span>%%SUCURI.AccessLog.RequestMethod%%</span>
26
- <span>%%SUCURI.AccessLog.HttpStatus%%</span>
27
- <span>%%SUCURI.AccessLog.HttpStatusTitle%%</span>
28
- </div>
29
- <div class="sucuriscan-accesslog-useragent">
30
- <span class="sucuriscan-accesslog-label">U-Agent:</span>
31
- <span>%%SUCURI.AccessLog.HttpUserAgent%%</span>
32
- </div>
33
- <div class="sucuriscan-accesslog-target">
34
- <span class="sucuriscan-accesslog-label">Target.:</span>
35
- <span>%%SUCURI.AccessLog.ResourcePath%%</span>
36
- </div>
37
- <div class="sucuriscan-accesslog-referer">
38
- <span class="sucuriscan-accesslog-label">Referer:</span>
39
- <span>%%SUCURI.AccessLog.HttpReferer%%</span>
40
- </div>
 
 
 
 
41
  </div>
42
  </td>
43
  </tr>
1
 
2
  <tr>
3
+ <td class="sucuriscan-firewall-accesslog sucuriscan-monospace">
4
+ <div class="sucuriscan-accesslog-origin">
5
+ <img src="%%SUCURI.SucuriURL%%/inc/images/blank.png"
6
+ class="sucuriscan-flag sucuriscan-flag-%%SUCURI.AccessLog.RequestCountryCode%%" />
7
+ <span>%%SUCURI.AccessLog.RemoteAddr%%</span>
8
+ <span>(%%SUCURI.AccessLog.RequestCountryName%%)</span>
9
+ </div>
10
+
11
+ <div class="sucuriscan-accesslog-datetime">
12
+ <span class="sucuriscan-accesslog-label">Date/Time:</span>
13
+ <span>%%SUCURI.AccessLog.RequestDate%%</span>
14
+ <span>%%SUCURI.AccessLog.RequestTime%%</span>
15
+ <span>%%SUCURI.AccessLog.RequestTimezone%%</span>
16
+ </div>
17
+
18
+ <div class="sucuriscan-accesslog-signature">
19
+ <span class="sucuriscan-accesslog-label">Signature:</span>
20
+ <span>%%SUCURI.AccessLog.SucuriBlockCode%%</span>
21
+ <span>(%%SUCURI.AccessLog.SucuriBlockReason%%)</span>
22
+ </div>
23
+
24
+ <div class="sucuriscan-accesslog-request">
25
+ <span class="sucuriscan-accesslog-label">Request:</span>
26
+ <span>%%SUCURI.AccessLog.HttpProtocol%%</span>
27
+ <span>%%SUCURI.AccessLog.RequestMethod%%</span>
28
+ <span>%%SUCURI.AccessLog.HttpStatus%%</span>
29
+ <span>%%SUCURI.AccessLog.HttpStatusTitle%%</span>
30
+ </div>
31
+
32
+ <div class="sucuriscan-accesslog-useragent">
33
+ <span class="sucuriscan-accesslog-label">U-Agent:</span>
34
+ <span>%%SUCURI.AccessLog.HttpUserAgent%%</span>
35
+ </div>
36
+
37
+ <div class="sucuriscan-accesslog-target">
38
+ <span class="sucuriscan-accesslog-label">Target.:</span>
39
+ <span>%%SUCURI.AccessLog.ResourcePath%%</span>
40
+ </div>
41
+
42
+ <div class="sucuriscan-accesslog-referer">
43
+ <span class="sucuriscan-accesslog-label">Referer:</span>
44
+ <span>%%SUCURI.AccessLog.HttpReferer%%</span>
45
  </div>
46
  </td>
47
  </tr>
inc/tpl/firewall-clearcache.html.tpl CHANGED
@@ -1,4 +1,45 @@
1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  <div class="sucuriscan-panel">
3
  <h3 class="sucuriscan-title">@@SUCURI.FirewallCacheTitle@@</h3>
4
 
@@ -11,10 +52,14 @@
11
 
12
  <p>@@SUCURI.FirewallCacheWiki@@</p>
13
 
14
- <form action="%%SUCURI.URL.Firewall%%#clearcache" method="post">
15
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
16
- <input type="hidden" name="sucuriscan_clear_cache" value="1" />
17
- <input type="submit" value="@@SUCURI.FirewallCacheButton@@" class="button button-primary" />
18
- </form>
 
 
 
 
19
  </div>
20
  </div>
1
 
2
+ <script type="text/javascript">
3
+ /* global jQuery */
4
+ /* jshint camelcase: false */
5
+ jQuery(function ($) {
6
+ $('#firewall-clear-cache-button').on('click', function (event) {
7
+ event.preventDefault();
8
+
9
+ var button = $(this);
10
+ button.attr('disabled', true);
11
+ button.html('@@SUCURI.Loading@@');
12
+ $('#firewall-clear-cache-response').html('');
13
+
14
+ $.post('%%SUCURI.AjaxURL.Firewall%%', {
15
+ action: 'sucuriscan_ajax',
16
+ sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
17
+ form_action: 'firewall_clear_cache',
18
+ }, function (data) {
19
+ button.addClass('sucuriscan-hidden');
20
+ $('#firewall-clear-cache-response').html(data);
21
+ });
22
+ });
23
+
24
+ $('#firewall-clear-cache-auto').on('change', 'input:checkbox', function () {
25
+ var checked = $(this).is(':checked');
26
+
27
+ $('#firewall-clear-cache-auto span').html(
28
+ '@@SUCURI.FirewallAutoClearCache@@ (@@SUCURI.Loading@@)');
29
+
30
+ $.post('%%SUCURI.AjaxURL.Firewall%%', {
31
+ action: 'sucuriscan_ajax',
32
+ sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
33
+ form_action: 'firewall_auto_clear_cache',
34
+ auto_clear_cache: (checked?'enable':'disable'),
35
+ }, function () {
36
+ $('#firewall-clear-cache-auto span')
37
+ .html('@@SUCURI.FirewallAutoClearCache@@');
38
+ });
39
+ });
40
+ });
41
+ </script>
42
+
43
  <div class="sucuriscan-panel">
44
  <h3 class="sucuriscan-title">@@SUCURI.FirewallCacheTitle@@</h3>
45
 
52
 
53
  <p>@@SUCURI.FirewallCacheWiki@@</p>
54
 
55
+ <div id="firewall-clear-cache-auto">
56
+ <label>
57
+ <input type="checkbox" name="sucuriscan_auto_clear_cache" value="true" %%SUCURI.FirewallAutoClearCache%% />
58
+ <span>@@SUCURI.FirewallAutoClearCache@@</span>
59
+ </label>
60
+ </div>
61
+
62
+ <div id="firewall-clear-cache-response"></div>
63
+ <button id="firewall-clear-cache-button" class="button button-primary">@@SUCURI.FirewallCacheButton@@</button>
64
  </div>
65
  </div>
inc/tpl/firewall-ipaccess.html.tpl ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <script type="text/javascript">
3
+ /* global jQuery */
4
+ /* jshint forin: false */
5
+ /* jshint camelcase: false */
6
+ jQuery(document).ready(function ($) {
7
+ var sucuriscanLoadIPAccess = function () {
8
+ // $('.sucuriscan-ipaccess-table tbody').html('<tr>' +
9
+ // '<td colspan="2">@@SUCURI.Loading@@</td></tr>');
10
+
11
+ $.post('%%SUCURI.AjaxURL.Firewall%%', {
12
+ action: 'sucuriscan_ajax',
13
+ sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
14
+ form_action: 'firewall_ipaccess',
15
+ }, function (data) {
16
+ $('.sucuriscan-ipaccess-table tbody').html('');
17
+
18
+ for (var i in data.blacklist) {
19
+ $('.sucuriscan-ipaccess-table tbody').append('<tr>' +
20
+ '<td><span class="sucuriscan-monospace">' + data.blacklist[i] + '</span></td>' +
21
+ '<td><button class="button button-primary sucuriscan-deblacklist" ' +
22
+ 'ip="' + data.blacklist[i] + '">@@SUCURI.Delete@@</button></td>' +
23
+ '</tr>');
24
+ }
25
+ });
26
+ };
27
+
28
+ var sucuriscanPrintStatus = function (button, data) {
29
+ button.attr('disabled', false);
30
+ button.html('@@SUCURI.Submit@@');
31
+
32
+ if (data.ok) {
33
+ sucuriscanLoadIPAccess();
34
+
35
+ $('#sucuriscan-ipaccess-response').html('<div '+
36
+ 'class="sucuriscan-inline-alert-success"><p>' +
37
+ data.msg + '</p></div>');
38
+ } else {
39
+ $('#sucuriscan-ipaccess-response').html('<div '+
40
+ 'class="sucuriscan-inline-alert-error"><p>' +
41
+ data.msg + '</p></div>');
42
+ }
43
+ };
44
+
45
+ $('.sucuriscan-container').on('click', '.sucuriscan-ipaccess-button', function (event) {
46
+ event.preventDefault();
47
+
48
+ var button = $(this);
49
+ var ip = $('.sucuriscan-ipaccess-form input[name=sucuriscan_ip]').val();
50
+
51
+ button.attr('disabled', true);
52
+ button.html('@@SUCURI.Loading@@');
53
+ $('#sucuriscan-ipaccess-response').html('');
54
+
55
+ $.post('%%SUCURI.AjaxURL.Firewall%%', {
56
+ action: 'sucuriscan_ajax',
57
+ sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
58
+ form_action: 'firewall_blacklist',
59
+ ip: ip,
60
+ }, function (data) {
61
+ sucuriscanPrintStatus(button, data);
62
+ });
63
+ });
64
+
65
+ $('.sucuriscan-container').on('click', '.sucuriscan-deblacklist', function (event) {
66
+ event.preventDefault();
67
+
68
+ var button = $(this);
69
+
70
+ button.attr('disabled', true);
71
+ button.html('@@SUCURI.Loading@@');
72
+ $('#sucuriscan-ipaccess-response').html('');
73
+
74
+ $.post('%%SUCURI.AjaxURL.Firewall%%', {
75
+ action: 'sucuriscan_ajax',
76
+ sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
77
+ form_action: 'firewall_deblacklist',
78
+ ip: button.attr('ip'),
79
+ }, function (data) {
80
+ sucuriscanPrintStatus(button, data);
81
+ });
82
+ });
83
+
84
+ sucuriscanLoadIPAccess();
85
+ });
86
+ </script>
87
+
88
+ <div class="sucuriscan-panel">
89
+ <h3 class="sucuriscan-title">@@SUCURI.FirewallIPAccessTitle@@</h3>
90
+
91
+ <div class="inside">
92
+ <p>@@SUCURI.FirewallIPAccessInfo@@</p>
93
+
94
+ <div id="sucuriscan-ipaccess-response"></div>
95
+
96
+ <form action="%%SUCURI.URL.Firewall%%#ipaccess" method="post" class="sucuriscan-ipaccess-form">
97
+ <input type="hidden" name="sucuriscan_blacklist_ip" value="true" />
98
+ <fieldset class="sucuriscan-clearfix">
99
+ <label>@@SUCURI.BlacklistIP@@:</label>
100
+ <input type="text" name="sucuriscan_ip" placeholder="e.g. 192.168.1.54" />
101
+ <button class="button button-primary sucuriscan-ipaccess-button">@@SUCURI.Submit@@</button>
102
+ </fieldset>
103
+ </form>
104
+
105
+ <table class="wp-list-table widefat sucuriscan-table sucuriscan-ipaccess-table">
106
+ <thead>
107
+ <tr>
108
+ <th>@@SUCURI.RemoteAddr@@</th>
109
+ <th>&nbsp;</th>
110
+ </tr>
111
+ </thead>
112
+
113
+ <tbody>
114
+ <tr><td colspan="2">@@SUCURI.Loading@@</td></tr>
115
+ </tbody>
116
+ </table>
117
+ </div>
118
+ </div>
inc/tpl/firewall-settings.html.tpl CHANGED
@@ -1,4 +1,35 @@
1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  <div class="sucuriscan-panel">
3
  <h3 class="sucuriscan-title">@@SUCURI.FirewallSettingsTitle@@</h3>
4
 
@@ -10,6 +41,7 @@
10
  </div>
11
 
12
  <div class="sucuriscan-hstatus sucuriscan-hstatus-2 sucuriscan-firewall-apikey sucuriscan-%%SUCURI.Firewall.APIKeyVisibility%%">
 
13
  <span class="sucuriscan-monospace">%%SUCURI.Firewall.APIKey%%</span>
14
  <form action="%%SUCURI.URL.Firewall%%" method="post">
15
  <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
@@ -27,7 +59,7 @@
27
  <br>
28
  </form>
29
 
30
- <table class="wp-list-table widefat sucuriscan-table sucuriscan-firewall-settings sucuriscan-%%SUCURI.Firewall.SettingsVisibility%%">
31
  <thead>
32
  <tr>
33
  <th>@@SUCURI.Name@@</th>
@@ -36,7 +68,7 @@
36
  </thead>
37
 
38
  <tbody>
39
- %%%SUCURI.Firewall.SettingOptions%%%
40
  </tbody>
41
  </table>
42
 
1
 
2
+ <script type="text/javascript">
3
+ /* global jQuery */
4
+ /* jshint camelcase: false */
5
+ jQuery(document).ready(function ($) {
6
+ $.post('%%SUCURI.AjaxURL.Firewall%%', {
7
+ action: 'sucuriscan_ajax',
8
+ sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
9
+ form_action: 'firewall_settings',
10
+ }, function (data) {
11
+ if (data.ok) {
12
+ var value;
13
+ $('#firewall-settings-table tbody').html('');
14
+ for (var name in data.settings) {
15
+ if (data.settings.hasOwnProperty(name) &&
16
+ typeof data.settings[name] === 'string'
17
+ ) {
18
+ value = data.settings[name];
19
+ $('#firewall-settings-table tbody').append('<tr>' +
20
+ '<td><label>' + name + '</label></td>' +
21
+ '<td><span class="sucuriscan-monospace">' +
22
+ value + '</span></td></tr>');
23
+ }
24
+ }
25
+ } else {
26
+ $('#firewall-settings-table tbody')
27
+ .html('<tr><td colspan="2">' + data.error + '</td></tr>');
28
+ }
29
+ });
30
+ });
31
+ </script>
32
+
33
  <div class="sucuriscan-panel">
34
  <h3 class="sucuriscan-title">@@SUCURI.FirewallSettingsTitle@@</h3>
35
 
41
  </div>
42
 
43
  <div class="sucuriscan-hstatus sucuriscan-hstatus-2 sucuriscan-firewall-apikey sucuriscan-%%SUCURI.Firewall.APIKeyVisibility%%">
44
+ <strong>@@SUCURI.FirewallKey@@:</strong>
45
  <span class="sucuriscan-monospace">%%SUCURI.Firewall.APIKey%%</span>
46
  <form action="%%SUCURI.URL.Firewall%%" method="post">
47
  <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
59
  <br>
60
  </form>
61
 
62
+ <table class="wp-list-table widefat sucuriscan-table" id="firewall-settings-table">
63
  <thead>
64
  <tr>
65
  <th>@@SUCURI.Name@@</th>
68
  </thead>
69
 
70
  <tbody>
71
+ <tr><td colspan="2">@@SUCURI.Loading@@</td></tr>
72
  </tbody>
73
  </table>
74
 
inc/tpl/firewall-settings.snippet.tpl DELETED
@@ -1,5 +0,0 @@
1
-
2
- <tr>
3
- <td><label>%%SUCURI.Firewall.OptionName%%</label></td>
4
- <td><span class="sucuriscan-monospace">%%%SUCURI.Firewall.OptionValue%%%</span></td>
5
- </tr>
 
 
 
 
 
inc/tpl/firewall.html.tpl CHANGED
@@ -3,6 +3,7 @@
3
  <ul class="sucuriscan-clearfix sucuriscan-tabs-buttons">
4
  <li><a href="%%SUCURI.URL.Firewall%%#settings">@@SUCURI.Settings@@</a></li>
5
  <li><a href="%%SUCURI.URL.Firewall%%#auditlogs">@@SUCURI.AuditLogs@@</a></li>
 
6
  <li><a href="%%SUCURI.URL.Firewall%%#clearcache">@@SUCURI.ClearCache@@</a></li>
7
  </ul>
8
 
@@ -15,6 +16,10 @@
15
  %%%SUCURI.Firewall.AuditLogs%%%
16
  </div>
17
 
 
 
 
 
18
  <div id="sucuriscan-tabs-clearcache" class="sucuriscan-hidden">
19
  %%%SUCURI.Firewall.ClearCache%%%
20
  </div>
3
  <ul class="sucuriscan-clearfix sucuriscan-tabs-buttons">
4
  <li><a href="%%SUCURI.URL.Firewall%%#settings">@@SUCURI.Settings@@</a></li>
5
  <li><a href="%%SUCURI.URL.Firewall%%#auditlogs">@@SUCURI.AuditLogs@@</a></li>
6
+ <li><a href="%%SUCURI.URL.Firewall%%#ipaccess">@@SUCURI.IPAccess@@</a></li>
7
  <li><a href="%%SUCURI.URL.Firewall%%#clearcache">@@SUCURI.ClearCache@@</a></li>
8
  </ul>
9
 
16
  %%%SUCURI.Firewall.AuditLogs%%%
17
  </div>
18
 
19
+ <div id="sucuriscan-tabs-ipaccess" class="sucuriscan-hidden">
20
+ %%%SUCURI.Firewall.IPAccess%%%
21
+ </div>
22
+
23
  <div id="sucuriscan-tabs-clearcache" class="sucuriscan-hidden">
24
  %%%SUCURI.Firewall.ClearCache%%%
25
  </div>
inc/tpl/integrity-diff-utility.html.tpl CHANGED
@@ -1,19 +1,13 @@
1
 
2
  <div class="sucuriscan-integrity-diff-utility">
3
- <div class="sucuriscan-inline-alert-info">
4
- <p>@@SUCURI.DiffUtilityInfo@@</p>
5
- </div>
6
-
7
- <div class="sucuriscan-hidden sucuriscan-diff-instructions">
8
- <p>@@SUCURI.DiffUtilityInstructions@@</p>
9
- </div>
10
-
11
  %%%SUCURI.DiffUtility.Modal%%%
12
 
13
  <script type="text/javascript">
14
  /* global jQuery */
15
  /* jshint camelcase: false */
16
  jQuery(function ($) {
 
 
17
  $('.sucuriscan-integrity-table .sucuriscan-integrity-filepath').on('click', function (event) {
18
  event.preventDefault();
19
 
@@ -28,9 +22,8 @@
28
  form_action: 'integrity_diff_utility',
29
  filepath: filepath,
30
  }, function (data) {
31
- var instructions = $('.sucuriscan-diff-instructions').html();
32
  $('.sucuriscan-diff-utility-modal .sucuriscan-modal-inside').html(data);
33
- $('.sucuriscan-diff-content').before(instructions);
34
  });
35
  });
36
  });
1
 
2
  <div class="sucuriscan-integrity-diff-utility">
 
 
 
 
 
 
 
 
3
  %%%SUCURI.DiffUtility.Modal%%%
4
 
5
  <script type="text/javascript">
6
  /* global jQuery */
7
  /* jshint camelcase: false */
8
  jQuery(function ($) {
9
+ $('.sucuriscan-integrity-table th .sucuriscan-tooltip').removeClass('sucuriscan-hidden');
10
+
11
  $('.sucuriscan-integrity-table .sucuriscan-integrity-filepath').on('click', function (event) {
12
  event.preventDefault();
13
 
22
  form_action: 'integrity_diff_utility',
23
  filepath: filepath,
24
  }, function (data) {
 
25
  $('.sucuriscan-diff-utility-modal .sucuriscan-modal-inside').html(data);
26
+ $('.sucuriscan-diff-content').before('<p>@@SUCURI.DiffUtilityInstructions@@</p>');
27
  });
28
  });
29
  });
inc/tpl/integrity-incorrect.html.tpl CHANGED
@@ -26,7 +26,43 @@
26
  <table class="wp-list-table widefat sucuriscan-table sucuriscan-integrity-table">
27
  <thead>
28
  <tr>
29
- <th colspan="5">@@SUCURI.IntegrityTitle@@ (%%SUCURI.Integrity.ListCount%%)</th>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  </tr>
31
 
32
  <tr>
@@ -46,10 +82,6 @@
46
  </tbody>
47
  </table>
48
 
49
- <div class="sucuriscan-inline-alert-info">
50
- <p>@@SUCURI.MarkFixedDescription@@</p>
51
- </div>
52
-
53
  <p>
54
  <label>
55
  <input type="hidden" name="sucuriscan_process_form" value="0" />
@@ -60,12 +92,48 @@
60
 
61
  <fieldset class="sucuriscan-clearfix">
62
  <label>@@SUCURI.Action@@:</label>
 
63
  <select name="sucuriscan_integrity_action">
64
  <option value="fixed">@@SUCURI.MarkFixed@@</option>
65
  <option value="restore">@@SUCURI.RestoreFile@@</option>
66
  <option value="delete">@@SUCURI.DeleteFile@@</option>
67
  </select>
 
68
  <button type="submit" class="button button-primary">@@SUCURI.Submit@@</button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  </fieldset>
70
  </form>
71
  </div>
26
  <table class="wp-list-table widefat sucuriscan-table sucuriscan-integrity-table">
27
  <thead>
28
  <tr>
29
+ <th colspan="5">
30
+ <span>@@SUCURI.IntegrityTitle@@ (%%SUCURI.Integrity.ListCount%%)</span>
31
+
32
+ <span class="sucuriscan-tooltip sucuriscan-hidden" content="@@SUCURI.DiffUtilityInfo@@">
33
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14" height="14">
34
+ <path fill="#000000" d="m6.998315,0.033333c-3.846307,0 -6.964982,
35
+ 3.118675 -6.964982,6.964982s3.118675,6.965574 6.964982,6.965574s6.965574,
36
+ -3.119267 6.965574,-6.965574s-3.119267,-6.964982 -6.965574,-6.964982zm1.449957,
37
+ 10.794779c-0.358509,0.141517 -0.643901,0.248833 -0.857945,0.32313c-0.213455,
38
+ 0.074296 -0.461699,0.111444 -0.744143,0.111444c-0.433985,0 -0.771855,
39
+ -0.106137 -1.012434,-0.317823s-0.360279,-0.479978 -0.360279,-0.806055c0,
40
+ -0.126776 0.008845,-0.256499 0.026534,-0.388581c0.018281,-0.132082 0.047174,
41
+ -0.280675 0.086679,-0.447547l0.448727,-1.584988c0.039507,-0.152131 0.073707,
42
+ -0.296596 0.100831,-0.431036c0.027123,-0.135621 0.040097,-0.260037 0.040097,
43
+ -0.37325c0,-0.201661 -0.041865,-0.343178 -0.125008,-0.422782c-0.08432,
44
+ -0.079603 -0.242937,-0.11852 -0.479388,-0.11852c-0.115572,0 -0.234682,
45
+ 0.0171 -0.35674,0.05307c-0.120879,0.037148 -0.225837,0.070758 -0.311926,
46
+ 0.103779l0.118521,-0.488235c0.293647,-0.119699 0.574911,-0.222299 0.843204,
47
+ -0.307209c0.268291,-0.086089 0.521842,-0.128543 0.760652,-0.128543c0.431036,
48
+ 0 0.7636,0.104959 0.997693,0.312517c0.232913,0.208147 0.350253,0.478797 0.350253,
49
+ 0.811363c0,0.068989 -0.008255,0.190458 -0.024174,0.363815c-0.015921,
50
+ 0.173947 -0.045994,0.332565 -0.089628,0.478209l-0.446368,1.580269c-0.036558,
51
+ 0.126776 -0.068988,0.271831 -0.098472,0.433985c-0.028893,0.162156 -0.043043,
52
+ 0.285983 -0.043043,0.369123c0,0.209916 0.046582,0.353202 0.140926,
53
+ 0.429268c0.093164,0.076064 0.256498,0.114392 0.487643,0.114392c0.109086,
54
+ 0 0.231144,-0.019459 0.369124,-0.057197c0.136799,-0.037737 0.23586,
55
+ -0.071349 0.298364,-0.100241l-0.119699,0.487643zm-0.079014,-6.414247c-0.208148,
56
+ 0.193407 -0.45875,0.290109 -0.751808,0.290109c-0.292469,0 -0.54484,
57
+ -0.096702 -0.754756,-0.290109c-0.208737,-0.193406 -0.314285,-0.428678 -0.314285,
58
+ -0.703457c0,-0.274188 0.106138,-0.51005 0.314285,-0.705225c0.208148,
59
+ -0.195175 0.462287,-0.293058 0.754756,-0.293058c0.293058,0 0.54425,
60
+ 0.097293 0.751808,0.293058c0.208146,0.195175 0.312516,0.431036 0.312516,
61
+ 0.705225c0,0.275368 -0.10437,0.510051 -0.312516,0.703457z">
62
+ </path>
63
+ </svg>
64
+ </span>
65
+ </th>
66
  </tr>
67
 
68
  <tr>
82
  </tbody>
83
  </table>
84
 
 
 
 
 
85
  <p>
86
  <label>
87
  <input type="hidden" name="sucuriscan_process_form" value="0" />
92
 
93
  <fieldset class="sucuriscan-clearfix">
94
  <label>@@SUCURI.Action@@:</label>
95
+
96
  <select name="sucuriscan_integrity_action">
97
  <option value="fixed">@@SUCURI.MarkFixed@@</option>
98
  <option value="restore">@@SUCURI.RestoreFile@@</option>
99
  <option value="delete">@@SUCURI.DeleteFile@@</option>
100
  </select>
101
+
102
  <button type="submit" class="button button-primary">@@SUCURI.Submit@@</button>
103
+
104
+ <span class="sucuriscan-tooltip" content="@@SUCURI.MarkFixedDescription@@">
105
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14" height="14">
106
+ <path fill="#000000" d="m6.998315,0.033333c-3.846307,0 -6.964982,
107
+ 3.118675 -6.964982,6.964982s3.118675,6.965574 6.964982,6.965574s6.965574,
108
+ -3.119267 6.965574,-6.965574s-3.119267,-6.964982 -6.965574,-6.964982zm1.449957,
109
+ 10.794779c-0.358509,0.141517 -0.643901,0.248833 -0.857945,0.32313c-0.213455,
110
+ 0.074296 -0.461699,0.111444 -0.744143,0.111444c-0.433985,0 -0.771855,
111
+ -0.106137 -1.012434,-0.317823s-0.360279,-0.479978 -0.360279,-0.806055c0,
112
+ -0.126776 0.008845,-0.256499 0.026534,-0.388581c0.018281,-0.132082 0.047174,
113
+ -0.280675 0.086679,-0.447547l0.448727,-1.584988c0.039507,-0.152131 0.073707,
114
+ -0.296596 0.100831,-0.431036c0.027123,-0.135621 0.040097,-0.260037 0.040097,
115
+ -0.37325c0,-0.201661 -0.041865,-0.343178 -0.125008,-0.422782c-0.08432,
116
+ -0.079603 -0.242937,-0.11852 -0.479388,-0.11852c-0.115572,0 -0.234682,
117
+ 0.0171 -0.35674,0.05307c-0.120879,0.037148 -0.225837,0.070758 -0.311926,
118
+ 0.103779l0.118521,-0.488235c0.293647,-0.119699 0.574911,-0.222299 0.843204,
119
+ -0.307209c0.268291,-0.086089 0.521842,-0.128543 0.760652,-0.128543c0.431036,
120
+ 0 0.7636,0.104959 0.997693,0.312517c0.232913,0.208147 0.350253,0.478797 0.350253,
121
+ 0.811363c0,0.068989 -0.008255,0.190458 -0.024174,0.363815c-0.015921,
122
+ 0.173947 -0.045994,0.332565 -0.089628,0.478209l-0.446368,1.580269c-0.036558,
123
+ 0.126776 -0.068988,0.271831 -0.098472,0.433985c-0.028893,0.162156 -0.043043,
124
+ 0.285983 -0.043043,0.369123c0,0.209916 0.046582,0.353202 0.140926,
125
+ 0.429268c0.093164,0.076064 0.256498,0.114392 0.487643,0.114392c0.109086,
126
+ 0 0.231144,-0.019459 0.369124,-0.057197c0.136799,-0.037737 0.23586,
127
+ -0.071349 0.298364,-0.100241l-0.119699,0.487643zm-0.079014,-6.414247c-0.208148,
128
+ 0.193407 -0.45875,0.290109 -0.751808,0.290109c-0.292469,0 -0.54484,
129
+ -0.096702 -0.754756,-0.290109c-0.208737,-0.193406 -0.314285,-0.428678 -0.314285,
130
+ -0.703457c0,-0.274188 0.106138,-0.51005 0.314285,-0.705225c0.208148,
131
+ -0.195175 0.462287,-0.293058 0.754756,-0.293058c0.293058,0 0.54425,
132
+ 0.097293 0.751808,0.293058c0.208146,0.195175 0.312516,0.431036 0.312516,
133
+ 0.705225c0,0.275368 -0.10437,0.510051 -0.312516,0.703457z">
134
+ </path>
135
+ </svg>
136
+ </span>
137
  </fieldset>
138
  </form>
139
  </div>
inc/tpl/settings-alerts-events.html.tpl CHANGED
@@ -3,6 +3,10 @@
3
  <h3 class="sucuriscan-title">@@SUCURI.SecurityAlerts@@</h3>
4
 
5
  <div class="inside">
 
 
 
 
6
  <form action="%%SUCURI.URL.Settings%%#alerts" method="post">
7
  <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
8
 
3
  <h3 class="sucuriscan-title">@@SUCURI.SecurityAlerts@@</h3>
4
 
5
  <div class="inside">
6
+ <div class="sucuriscan-inline-alert-error sucuriscan-%%SUCURI.Alerts.NoAlertsVisibility%%">
7
+ <p>@@SUCURI.NoAlertsError@@</p>
8
+ </div>
9
+
10
  <form action="%%SUCURI.URL.Settings%%#alerts" method="post">
11
  <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
12
 
inc/tpl/settings-alerts-ignore-posts.html.tpl CHANGED
@@ -3,9 +3,9 @@
3
  <h3 class="sucuriscan-title">@@SUCURI.PostTypeAlerts@@</h3>
4
 
5
  <div class="inside">
6
- <p class="sucuriscan-inline-alert-error sucuriscan-%%SUCURI.IgnoreRules.MessageVisibility%%">
7
- @@SUCURI.PostTypeAlertsDisabled@@
8
- </p>
9
 
10
  <p>@@SUCURI.PostTypeAlertsInfo@@</p>
11
 
3
  <h3 class="sucuriscan-title">@@SUCURI.PostTypeAlerts@@</h3>
4
 
5
  <div class="inside">
6
+ <div class="sucuriscan-inline-alert-error sucuriscan-%%SUCURI.IgnoreRules.ErrorVisibility%%">
7
+ <p>@@SUCURI.PostTypeAlertsDisabled@@</p>
8
+ </div>
9
 
10
  <p>@@SUCURI.PostTypeAlertsInfo@@</p>
11
 
inc/tpl/settings-apiservice-checksums.html.tpl ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <div class="sucuriscan-panel">
3
+ <h3 class="sucuriscan-title">@@SUCURI.ChecksumsAPI@@</h3>
4
+
5
+ <div class="inside">
6
+ <p>@@SUCURI.ChecksumsAPIInfo@@</p>
7
+
8
+ <div class="sucuriscan-hstatus sucuriscan-hstatus-2">
9
+ <span>@@SUCURI.ChecksumsAPI@@ &mdash; <a target="_blank"
10
+ href="%%SUCURI.ChecksumsAPI%%">%%SUCURI.ChecksumsAPI%%</a>
11
+ </span>
12
+ </div>
13
+
14
+ <form action="%%SUCURI.URL.Settings%%#apiservice" method="post">
15
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
16
+ <fieldset class="sucuriscan-clearfix">
17
+ <label>@@SUCURI.ChecksumsAPI@@:</label>
18
+ <input type="text" name="sucuriscan_checksum_api" placeholder="e.g. URL — or — user/repo" size="30" />
19
+ <button type="submit" class="button button-primary">@@SUCURI.Submit@@</button>
20
+ </fieldset>
21
+ </form>
22
+ </div>
23
+ </div>
inc/tpl/{settings-general-auditlogstats.html.tpl → settings-general-timezone.html.tpl} RENAMED
@@ -1,16 +1,19 @@
1
 
2
  <div class="sucuriscan-panel">
3
- <h3 class="sucuriscan-title">@@SUCURI.LogsReport@@</h3>
4
 
5
  <div class="inside">
6
- <p>@@SUCURI.LogsReportDescription@@</p>
7
 
8
  <form action="%%SUCURI.URL.Settings%%" method="post">
9
  <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
10
  <fieldset class="sucuriscan-clearfix">
11
- <label>@@SUCURI.LogsReport@@:</label>
12
- <input type="text" name="sucuriscan_logs4report" value="%%SUCURI.AuditLogStats.Limit%%" placeholder="e.g. 500" />
 
 
13
  <button type="submit" class="button button-primary">@@SUCURI.Submit@@</button>
 
14
  </fieldset>
15
  </form>
16
  </div>
1
 
2
  <div class="sucuriscan-panel">
3
+ <h3 class="sucuriscan-title">@@SUCURI.TimezoneTitle@@</h3>
4
 
5
  <div class="inside">
6
+ <p>@@SUCURI.TimezoneInfo@@</p>
7
 
8
  <form action="%%SUCURI.URL.Settings%%" method="post">
9
  <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
10
  <fieldset class="sucuriscan-clearfix">
11
+ <label>@@SUCURI.TimezoneTitle@@:</label>
12
+ <select name="sucuriscan_timezone">
13
+ %%%SUCURI.Timezone.Dropdown%%%
14
+ </select>
15
  <button type="submit" class="button button-primary">@@SUCURI.Submit@@</button>
16
+ <span><em>(%%SUCURI.Timezone.Example%%)</em></span>
17
  </fieldset>
18
  </form>
19
  </div>
inc/tpl/settings-webinfo-wpconfig.html.tpl DELETED
@@ -1,19 +0,0 @@
1
-
2
- <div class="sucuriscan-panel">
3
- <h3 class="sucuriscan-title">@@SUCURI.ConfigVariables@@</h3>
4
-
5
- <div class="inside">
6
- <table class="wp-list-table widefat sucuriscan-table">
7
- <thead>
8
- <tr>
9
- <th>@@SUCURI.Name@@</th>
10
- <th>@@SUCURI.Value@@</th>
11
- </tr>
12
- </thead>
13
-
14
- <tbody>
15
- %%%SUCURI.WordpressConfig.Rules%%%
16
- </tbody>
17
- </table>
18
- </div>
19
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
inc/tpl/settings-webinfo-wpconfig.snippet.tpl DELETED
@@ -1,6 +0,0 @@
1
-
2
- <tr>
3
- <td><span class="sucuriscan-monospace">%%SUCURI.WordpressConfig.VariableName%%</span></td>
4
-
5
- <td><span class="sucuriscan-monospace sucuriscan-wraptext">%%SUCURI.WordpressConfig.VariableValue%%</span></td>
6
- </tr>
 
 
 
 
 
 
inc/tpl/settings.html.tpl CHANGED
@@ -22,7 +22,7 @@
22
 
23
  %%%SUCURI.Settings.General.IPDiscoverer%%%
24
 
25
- %%%SUCURI.Settings.General.AuditLogStats%%%
26
 
27
  %%%SUCURI.Settings.General.ImportExport%%%
28
 
@@ -103,13 +103,15 @@
103
  %%%SUCURI.Settings.APIService.Status%%%
104
 
105
  %%%SUCURI.Settings.APIService.Proxy%%%
 
 
 
 
106
  </div>
107
 
108
  <div id="sucuriscan-tabs-webinfo">
109
  %%%SUCURI.Settings.Webinfo.Details%%%
110
 
111
- %%%SUCURI.Settings.Webinfo.WPConfig%%%
112
-
113
  %%%SUCURI.Settings.Webinfo.HTAccess%%%
114
  </div>
115
  </div>
22
 
23
  %%%SUCURI.Settings.General.IPDiscoverer%%%
24
 
25
+ %%%SUCURI.Settings.General.Timezone%%%
26
 
27
  %%%SUCURI.Settings.General.ImportExport%%%
28
 
103
  %%%SUCURI.Settings.APIService.Status%%%
104
 
105
  %%%SUCURI.Settings.APIService.Proxy%%%
106
+
107
+ %%%SUCURI.Settings.SiteCheck.Target%%%
108
+
109
+ %%%SUCURI.Settings.APIService.Checksums%%%
110
  </div>
111
 
112
  <div id="sucuriscan-tabs-webinfo">
113
  %%%SUCURI.Settings.Webinfo.Details%%%
114
 
 
 
115
  %%%SUCURI.Settings.Webinfo.HTAccess%%%
116
  </div>
117
  </div>
inc/tpl/sitecheck-links.html.tpl DELETED
@@ -1,6 +0,0 @@
1
-
2
- <table class="wp-list-table widefat sucuriscan-table">
3
- <tbody>
4
- %%%SUCURI.SiteCheck.Resources%%%
5
- </tbody>
6
- </table>
 
 
 
 
 
 
inc/tpl/sitecheck-links.snippet.tpl DELETED
@@ -1,7 +0,0 @@
1
-
2
- <tr>
3
- <td>
4
- <a href="%%SUCURI.SiteCheck.URL%%" target="_blank"
5
- class="sucuriscan-monospace">%%SUCURI.SiteCheck.URL%%</a>
6
- </td>
7
- </tr>
 
 
 
 
 
 
 
inc/tpl/sitecheck-target.html.tpl ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <div class="sucuriscan-panel">
3
+ <h3 class="sucuriscan-title">@@SUCURI.SiteCheckTarget@@</h3>
4
+
5
+ <div class="inside">
6
+ <p>@@SUCURI.SiteCheckTargetInfo@@</p>
7
+
8
+ <div class="sucuriscan-hstatus sucuriscan-hstatus-2">
9
+ <span>@@SUCURI.SiteCheckTarget@@ &mdash; <a target="_blank"
10
+ href="https://sitecheck.sucuri.net/results/%%SUCURI.SiteCheck.Target%%">
11
+ https://sitecheck.sucuri.net/results/%%SUCURI.SiteCheck.Target%%</a>
12
+ </span>
13
+ </div>
14
+
15
+ <form action="%%SUCURI.URL.Settings%%#apiservice" method="post">
16
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
17
+ <fieldset class="sucuriscan-clearfix">
18
+ <label>@@SUCURI.SiteCheckTarget@@:</label>
19
+ <input type="text" name="sucuriscan_sitecheck_target" />
20
+ <button type="submit" class="button button-primary">@@SUCURI.Submit@@</button>
21
+ </fieldset>
22
+ </form>
23
+ </div>
24
+ </div>
languages/sucuri-scanner-en_US.mo CHANGED
Binary file
languages/sucuri-scanner-en_US.po CHANGED
@@ -29,12 +29,12 @@ msgstr "Settings"
29
  msgid "AuditLogs"
30
  msgstr "Audit Logs"
31
 
32
- msgid "Statistics"
33
- msgstr "Statistics"
34
-
35
  msgid "ClearCache"
36
  msgstr "Clear Cache"
37
 
 
 
 
38
  msgid "GenerateAPIKey"
39
  msgstr "Generate API Key"
40
 
@@ -183,7 +183,7 @@ msgid "SelfHostingDisabled"
183
  msgstr "The log exporter feature has been disabled"
184
 
185
  msgid "SelfHostingInfo"
186
- msgstr "This option allows you to export the WordPress audit logs to a local log file that can be read by a SIEM or any log analysis software <em>(we recommend OSSEC)</em>. That will give visibility from within WordPress to complement your log monitoring infrastructure."
187
 
188
  msgid "SelfHostingFallback"
189
  msgstr "You don't have a valid API key to communicate with the remote API service. However, the self-hosting monitor is enabled, the plugin will read the logs from that file and display the data here. Notice that only the latest logs will be processed to keep a low memory footprint. Consider to generate a free API key to get a better coverage of the activity in your website."
@@ -209,8 +209,8 @@ msgstr "WordPress version is not supported."
209
  msgid "NoWordPressFile"
210
  msgstr "File is not part of the official WordPress installation."
211
 
212
- msgid "CannotCheckMissingFile"
213
- msgstr "Cannot check the integrity of a non-existing file."
214
 
215
  msgid "ScheduledTask"
216
  msgstr "%1$s (every %2$d seconds)"
@@ -464,6 +464,9 @@ msgstr "The plugin has no permission to restore this file because its directory
464
  msgid "SecurityAlerts"
465
  msgstr "Security Alerts"
466
 
 
 
 
467
  msgid "AlertSettingsUpdated"
468
  msgstr "The alert settings have been updated"
469
 
@@ -494,6 +497,9 @@ msgstr "Receive email alerts for successful login attempts"
494
  msgid "OptionNotifyFailedLogin"
495
  msgstr "Receive email alerts for failed login attempts <em>(you may receive tons of emails)</em>"
496
 
 
 
 
497
  msgid "OptionNotifyBruteforceAttack"
498
  msgstr "Receive email alerts for password guessing attacks <em>(summary of failed logins per hour)</em>"
499
 
@@ -603,7 +609,7 @@ msgid "DiffUtilityDescription"
603
  msgstr "If your server allows the execution of system commands, you can configure the plugin to use the <a href=\"https://en.wikipedia.org/wiki/Diff_utility\" target=\"_blank\" rel=\"noopener\">Unix Diff Utility</a> to compare the actual content of the file installed in the website and the original file provided by WordPress. This will show the differences between both files and then you can act upon the information provided."
604
 
605
  msgid "DiffUtilityInfo"
606
- msgstr "The Unix Diff Utility is enabled. You can click the files marked as modified <em>(the ones with the purple flag)</em> to see the differences detected by the scanner. If you consider the differences to be harmless you can mark the file as fixed, otherwise it is adviced to restore the original content immediately."
607
 
608
  msgid "DiffUtilityInstructions"
609
  msgstr "Lines with a <b>minus</b> sign as the prefix <em>(here in red)</em> show the original code. Lines with a <b>plus</b> sign as the prefix <em>(here in green)</em> show the modified code. You can read more about the DIFF format from the WikiPedia article about the <a target=\"_blank\" href=\"https://en.wikipedia.org/wiki/Diff_utility\" rel=\"noopener\">Unix Diff Utility</a>."
@@ -830,6 +836,9 @@ msgstr "Most of the tools in this plugin can be used without a specific configur
830
  msgid "APIKeyTerms"
831
  msgstr "Generating an API key implies that you agree to send the information collected by the plugin to the Sucuri API service which is a remote server where the information for the audit logs is stored, this is to prevent malicious users to delete the logs during an attack which may affect an investigation if you suspect that your website was hacked. We also use this information to display <a href=\"https://sucuri.net/security-reports/brute-force/\" target=\"_blank\">statistics</a> and try to use the data in an anonymous way as we are concerned about your privacy too. Please do not generate an API key if you do not agree with this, you can keep using the plugin without it anyway."
832
 
 
 
 
833
  msgid "APIKeyInvalidDomain"
834
  msgstr "Your domain <code>%%SUCURI.CleanDomain%%</code> does not seems to have a DNS <code>A</code> record so it will be considered as <em>invalid</em> by the API interface when you request the generation of a new key. Adding <code>www</code> at the beginning of the domain name may fix this issue. If you do not understand what is this then send an email to our support team requesting the key."
835
 
@@ -1080,7 +1089,7 @@ msgid "IntegrityBadDescription"
1080
  msgstr "We identified that some of your WordPress core files were modified. That might indicate a hack or a broken file on your installation. If you are experiencing other malware issues, please use a <a href=\"https://sucuri.net/website-security/malware-removal\" target=\"_blank\">Server Side Scanner</a>."
1081
 
1082
  msgid "MarkFixedDescription"
1083
- msgstr "Marking one or more files as fixed will force the plugin to ignore them during the next scan, very useful when you find false positives. Additionally you can restore the original content of the core files that appear as modified or deleted, this will tell the plugin to download a copy of the original files from the official <a href=\"https://core.svn.wordpress.org/tags/\" target=\"_blank\" rel=\"noopener\">WordPress repository</a>. Deleting a file is an irreversible action, be careful."
1084
 
1085
  msgid "Action"
1086
  msgstr "Action"
@@ -1154,6 +1163,18 @@ msgstr "The firewall logs every request involved in an attack and separates them
1154
  msgid "FirewallLogsNote"
1155
  msgstr "Note that non-blocked requests are hidden from the logs, this is intentional."
1156
 
 
 
 
 
 
 
 
 
 
 
 
 
1157
  msgid "FirewallCacheTitle"
1158
  msgstr "Clear Cache"
1159
 
@@ -1169,6 +1190,9 @@ msgstr "Note that the firewall has <a href=\"https://kb.sucuri.net/firewall/Perf
1169
  msgid "FirewallCacheWiki"
1170
  msgstr "A web cache (or HTTP cache) is an information technology for the temporary storage (caching) of web documents, such as HTML pages and images, to reduce bandwidth usage, server load, and perceived lag. A web cache system stores copies of documents passing through it; subsequent requests may be satisfied from the cache if certain conditions are met. A web cache system can refer either to an appliance, or to a computer program. &mdash; <a href=\"https://en.wikipedia.org/wiki/Web_cache\" target=\"_blank\" rel=\"noopener\">WikiPedia - Web Cache</a>"
1171
 
 
 
 
1172
  msgid "LoginsAdmins"
1173
  msgstr "Successful Logins (admins)"
1174
 
@@ -1223,6 +1247,12 @@ msgstr "Recomendations"
1223
  msgid "SiteCheckNoResults"
1224
  msgstr "If our free scanner did not detect any issue, you may have a more complicated and hidden problem. You can <a target=\"_blank\" href=\"https://sucuri.net/website-security-platform/signup\">sign up with Sucuri</a> for a complete and in-depth scan + cleanup (not included in the free checks)."
1225
 
 
 
 
 
 
 
1226
  msgid "PasswordAttack"
1227
  msgstr "Password Guessing Brute Force Attacks"
1228
 
@@ -1460,14 +1490,23 @@ msgstr "Data Storage"
1460
  msgid "DataStorageInfo"
1461
  msgstr "This is the directory where the plugin will store the security logs, the list of files marked as fixed in the core integrity tool, the cache for the malware scanner and 3rd-party plugin metadata. The plugin requires write permissions in this directory as well as the files contained in it. If you prefer to keep these files in a non-public directory <em>(one level up the document root) </em> please define a constant in the <em>\"wp-config.php\"</em> file named <em>\"SUCURI_DATA_STORAGE\"</em> with the absolute path to the new directory."
1462
 
1463
- msgid "LogsReport"
1464
- msgstr "Audit Log Statistics"
 
 
 
 
 
 
 
 
 
1465
 
1466
- msgid "LogsReportLimit"
1467
- msgstr "The number of logs that will be used to generate the audit report has been changed"
1468
 
1469
- msgid "LogsReportInfo"
1470
- msgstr "The data used to generate these charts comes from the last <b>%%SUCURI.AuditReport.Logs4Report%% audit logs</b>, you can configure this number from the plugin settings page."
1471
 
1472
- msgid "LogsReportDescription"
1473
- msgstr "Enabling this option allows you to have a quick view of the range of the activity of your users and/or the attacks directed against your website. By default, the plugin uses the latest entries in the audit logs and uses that information to draw bar and pie charts in the dashboard. The statistic are generated with a limited number of logs to reduce the memory consumption of the parser. You can increase the limit at your own discretion considering the amount of memory and maximum execution time that your PHP installation is allowed to use."
29
  msgid "AuditLogs"
30
  msgstr "Audit Logs"
31
 
 
 
 
32
  msgid "ClearCache"
33
  msgstr "Clear Cache"
34
 
35
+ msgid "IPAccess"
36
+ msgstr "IP Access"
37
+
38
  msgid "GenerateAPIKey"
39
  msgstr "Generate API Key"
40
 
183
  msgstr "The log exporter feature has been disabled"
184
 
185
  msgid "SelfHostingInfo"
186
+ msgstr "This option allows you to export the WordPress audit logs to a local log file that can be read by a SIEM or any log analysis software <em>(we recommend OSSEC)</em>. That will give visibility from within WordPress to complement your log monitoring infrastructure. <b>NOTE:</b> Do not use a publicly accessible file, you must use a file at least one level up the document root to prevent leaks of information."
187
 
188
  msgid "SelfHostingFallback"
189
  msgstr "You don't have a valid API key to communicate with the remote API service. However, the self-hosting monitor is enabled, the plugin will read the logs from that file and display the data here. Notice that only the latest logs will be processed to keep a low memory footprint. Consider to generate a free API key to get a better coverage of the activity in your website."
209
  msgid "NoWordPressFile"
210
  msgstr "File is not part of the official WordPress installation."
211
 
212
+ msgid "ThereAreNoDifferences"
213
+ msgstr "There are no differences between the installed and original files"
214
 
215
  msgid "ScheduledTask"
216
  msgstr "%1$s (every %2$d seconds)"
464
  msgid "SecurityAlerts"
465
  msgstr "Security Alerts"
466
 
467
+ msgid "NoAlertsError"
468
+ msgstr "You have installed a plugin or theme that is not fully compatible with our plugin, some of the security alerts (like the successful and failed logins) will not be sent to you. To prevent an infinite loop while detecting these changes in the website and sending the email alerts via a custom SMTP plugin, we have decided to stop any attempt to send the emails to prevent fatal errors."
469
+
470
  msgid "AlertSettingsUpdated"
471
  msgstr "The alert settings have been updated"
472
 
497
  msgid "OptionNotifyFailedLogin"
498
  msgstr "Receive email alerts for failed login attempts <em>(you may receive tons of emails)</em>"
499
 
500
+ msgid "OptionNotifyFailedPassword"
501
+ msgstr "Receive email alerts for failed login attempts including the submitted password"
502
+
503
  msgid "OptionNotifyBruteforceAttack"
504
  msgstr "Receive email alerts for password guessing attacks <em>(summary of failed logins per hour)</em>"
505
 
609
  msgstr "If your server allows the execution of system commands, you can configure the plugin to use the <a href=\"https://en.wikipedia.org/wiki/Diff_utility\" target=\"_blank\" rel=\"noopener\">Unix Diff Utility</a> to compare the actual content of the file installed in the website and the original file provided by WordPress. This will show the differences between both files and then you can act upon the information provided."
610
 
611
  msgid "DiffUtilityInfo"
612
+ msgstr "The Unix Diff Utility is enabled. You can click the files in the table to see the differences detected by the scanner. If you consider the differences to be harmless you can mark the file as fixed, otherwise it is adviced to restore the original content immediately."
613
 
614
  msgid "DiffUtilityInstructions"
615
  msgstr "Lines with a <b>minus</b> sign as the prefix <em>(here in red)</em> show the original code. Lines with a <b>plus</b> sign as the prefix <em>(here in green)</em> show the modified code. You can read more about the DIFF format from the WikiPedia article about the <a target=\"_blank\" href=\"https://en.wikipedia.org/wiki/Diff_utility\" rel=\"noopener\">Unix Diff Utility</a>."
836
  msgid "APIKeyTerms"
837
  msgstr "Generating an API key implies that you agree to send the information collected by the plugin to the Sucuri API service which is a remote server where the information for the audit logs is stored, this is to prevent malicious users to delete the logs during an attack which may affect an investigation if you suspect that your website was hacked. We also use this information to display <a href=\"https://sucuri.net/security-reports/brute-force/\" target=\"_blank\">statistics</a> and try to use the data in an anonymous way as we are concerned about your privacy too. Please do not generate an API key if you do not agree with this, you can keep using the plugin without it anyway."
838
 
839
+ msgid "APIKeyMissing"
840
+ msgstr "API key is missing"
841
+
842
  msgid "APIKeyInvalidDomain"
843
  msgstr "Your domain <code>%%SUCURI.CleanDomain%%</code> does not seems to have a DNS <code>A</code> record so it will be considered as <em>invalid</em> by the API interface when you request the generation of a new key. Adding <code>www</code> at the beginning of the domain name may fix this issue. If you do not understand what is this then send an email to our support team requesting the key."
844
 
1089
  msgstr "We identified that some of your WordPress core files were modified. That might indicate a hack or a broken file on your installation. If you are experiencing other malware issues, please use a <a href=\"https://sucuri.net/website-security/malware-removal\" target=\"_blank\">Server Side Scanner</a>."
1090
 
1091
  msgid "MarkFixedDescription"
1092
+ msgstr "Marking one or more files as fixed will force the plugin to ignore them during the next scan, very useful when you find false positives. Additionally you can restore the original content of the core files that appear as modified or deleted, this will tell the plugin to download a copy of the original files from the official WordPress repository. Deleting a file is an irreversible action, be careful."
1093
 
1094
  msgid "Action"
1095
  msgstr "Action"
1163
  msgid "FirewallLogsNote"
1164
  msgstr "Note that non-blocked requests are hidden from the logs, this is intentional."
1165
 
1166
+ msgid "FirewallIPAccessTitle"
1167
+ msgstr "IP Address Access"
1168
+
1169
+ msgid "FirewallIPAccessInfo"
1170
+ msgstr "This tool allows you to whitleist and blacklist one or more IP addresses from accessing your website. You can also configure the plugin to automatically blacklist any IP address involved in a password guessing brute-force attack. If a legitimate user fails to submit the correct credentials of their account they will have to log into the Firewall dashboard in order to delete their IP address from the blacklist, or try to login once again through a VPN."
1171
+
1172
+ msgid "WhitelistIP"
1173
+ msgstr "Whitelist IP"
1174
+
1175
+ msgid "BlacklistIP"
1176
+ msgstr "Blacklist IP"
1177
+
1178
  msgid "FirewallCacheTitle"
1179
  msgstr "Clear Cache"
1180
 
1190
  msgid "FirewallCacheWiki"
1191
  msgstr "A web cache (or HTTP cache) is an information technology for the temporary storage (caching) of web documents, such as HTML pages and images, to reduce bandwidth usage, server load, and perceived lag. A web cache system stores copies of documents passing through it; subsequent requests may be satisfied from the cache if certain conditions are met. A web cache system can refer either to an appliance, or to a computer program. &mdash; <a href=\"https://en.wikipedia.org/wiki/Web_cache\" target=\"_blank\" rel=\"noopener\">WikiPedia - Web Cache</a>"
1192
 
1193
+ msgid "FirewallAutoClearCache"
1194
+ msgstr "Clear cache automatically when a post or page is updated"
1195
+
1196
  msgid "LoginsAdmins"
1197
  msgstr "Successful Logins (admins)"
1198
 
1247
  msgid "SiteCheckNoResults"
1248
  msgstr "If our free scanner did not detect any issue, you may have a more complicated and hidden problem. You can <a target=\"_blank\" href=\"https://sucuri.net/website-security-platform/signup\">sign up with Sucuri</a> for a complete and in-depth scan + cleanup (not included in the free checks)."
1249
 
1250
+ msgid "SiteCheckTarget"
1251
+ msgstr "Malware Scan Target"
1252
+
1253
+ msgid "SiteCheckTargetInfo"
1254
+ msgstr "The remote malware scanner provided by the plugin is powered by <a href=\"https://sitecheck.sucuri.net/\" target=\"_blank\">Sucuri SiteCheck</a>, a service that takes a publicly accessible URL and scans it for malicious code. If your website is not visible to the Internet, for example, if it is hosted in a local development environment or a restricted network, the scanner will not be able to work on it. Additionally, if the website was installed in a non-standard directory the scanner will report a \"404 Not Found\" error. You can use this option to change the URL that will be scanned."
1255
+
1256
  msgid "PasswordAttack"
1257
  msgstr "Password Guessing Brute Force Attacks"
1258
 
1490
  msgid "DataStorageInfo"
1491
  msgstr "This is the directory where the plugin will store the security logs, the list of files marked as fixed in the core integrity tool, the cache for the malware scanner and 3rd-party plugin metadata. The plugin requires write permissions in this directory as well as the files contained in it. If you prefer to keep these files in a non-public directory <em>(one level up the document root) </em> please define a constant in the <em>\"wp-config.php\"</em> file named <em>\"SUCURI_DATA_STORAGE\"</em> with the absolute path to the new directory."
1492
 
1493
+ msgid "TimezoneTitle"
1494
+ msgstr "Timezone"
1495
+
1496
+ msgid "TimezoneInfo"
1497
+ msgstr "This option defines the timezone that will be used through out the entire plugin to print the dates and times whenever is necessary. This option also affects the date and time of the logs visible in the audit logs panel which is data that comes from a remote server configured to use Eastern Daylight Time (EDT). WordPress offers an option in the general settings page to allow you to configure the timezone for the entire website, however, if you are experiencing problems with the time in the audit logs, this option will help you fix them."
1498
+
1499
+ msgid "TimezoneStatus"
1500
+ msgstr "The timezone for the date and time in the audit logs has been changed"
1501
+
1502
+ msgid "ChecksumsAPI"
1503
+ msgstr "WordPress Checksums API"
1504
 
1505
+ msgid "ChecksumsAPIInfo"
1506
+ msgstr "The WordPress integrity tool uses a remote API service maintained by the WordPress organization to determine which files in the installation were added, removed or modified. The API returns a list of files with their respective checksums, this information guarantees that the installation is not corrupt. You can, however, point the integrity tool to a GitHub repository in case that you are using a custom version of WordPress like the <a href=\"https://github.com/WordPress/WordPress\" target=\"_blank\">development version of the code</a>."
1507
 
1508
+ msgid "ChecksumsAPIChanged"
1509
+ msgstr "The URL to retrieve the WordPress checksums has been changed"
1510
 
1511
+ msgid "MaxExecutionTimeAlert"
1512
+ msgstr "Server is not fast enough to process this action; maximum execution time reached"
languages/sucuri-scanner-es_ES.mo CHANGED
Binary file
languages/sucuri-scanner-es_ES.po CHANGED
@@ -10,9 +10,10 @@ msgstr ""
10
  "PO-Revision-Date: \n"
11
  "POT-Creation-Date: 2017-06-01 09:00-0700\n"
12
  "Project-Id-Version: Sucuri Scanner\n"
 
13
 
14
  msgid "Review"
15
- msgstr "Review"
16
 
17
  msgid "Dashboard"
18
  msgstr "Inicio"
@@ -29,12 +30,12 @@ msgstr "Ajustes"
29
  msgid "AuditLogs"
30
  msgstr "Registros"
31
 
32
- msgid "Statistics"
33
- msgstr "Estadísticas"
34
-
35
  msgid "ClearCache"
36
  msgstr "Limpiar Cache"
37
 
 
 
 
38
  msgid "GenerateAPIKey"
39
  msgstr "Generar Llave"
40
 
@@ -48,13 +49,13 @@ msgid "AccessDenied"
48
  msgstr "Accesso denegado por Sucuri Inc."
49
 
50
  msgid "NonceFailure"
51
- msgstr "Error al verificar el código Nonce del formulario, verifique los datos e intente de nuevo."
52
 
53
  msgid "NewsletterInvitation"
54
- msgstr "¿Desea recibir información sobre vulnerabilidades descubiertas? Subscríbase a nuestro newsletter <a href=\"http://sucuri.hs-sites.com/subscribe-to-security\" target=\"_blank\" rel=\"noopener\">aquí</a>"
55
 
56
  msgid "EnableAPIServiceAgain"
57
- msgstr "La comunicación con la API de Sucuri está deshabilitada, si usted acaba de actualizar el plugin esta podría ser una buena oportunidad para probar esta herramienta una vez más con el nuevo código. Habilite la comunicación con la API desde la página de ajustes."
58
 
59
  msgid "Save"
60
  msgstr "Guardar"
@@ -69,13 +70,13 @@ msgid "ErrorNoInfo"
69
  msgstr "Error desconocido, no hay más información."
70
 
71
  msgid "ErrorLogFileNotFound"
72
- msgstr "; esto generalmente sucede cuando una llave inválida es agregada al plugin, la llave será eliminada automáticamente para reducir la cantidad de errores, si usted quiere recuperarla utilice el botón de recuperación en la página de ajustes, recibirá un correo con las instrucciones de activación: %1$s"
73
 
74
  msgid "ErrorWrongAPIKey"
75
  msgstr "; la llave del Firewall es inválida: %1$s"
76
 
77
  msgid "ErrorSSLCertificate"
78
- msgstr ". Su sitio web para estar usando una versión desactualizada de la librería OpenSSL o el módulo de CURL ha sido compilado sin soporte para el algoritmo usado para establecer un enlace de comunicación segura con la API. Contácte a su proveedor de hosting para solucionar el problema."
79
 
80
  msgid "ErrorInvalidEmail"
81
  msgstr "El correo electrónico tiene un formato inválido o el dominio asociado no tiene asociado un servidor MX."
@@ -183,10 +184,10 @@ msgid "SelfHostingDisabled"
183
  msgstr "La herramienta para exportar los registros de seguridad ha sido desactivada"
184
 
185
  msgid "SelfHostingInfo"
186
- msgstr "Esta opción le permite guardar una copia de los registros de seguridad en un archivo ubicado en su servidor que puede ser leido por un SIEM o cualquier otro sistema de análisis <em>(le recomendamos OSSEC)</em>. Esto le dará visibilidad de lo que sucede en su sitio web para complementar su infraestructura de monitoreo."
187
 
188
  msgid "SelfHostingFallback"
189
- msgstr "Usted no tiene una llave para comunicarse con la API. Sin embargo, la herramienta para exportar los registros de seguridad está activada, el plugin leerá el contenido de este archivo y mostrará esa información aquí. Tenga en cuenta que solo los últimos registros serán procesados para mantener un consumo de memoria bajo. Considere generar una llave para obtener una mayor covertura en la actividad de su sitio web."
190
 
191
  msgid "AuditLogsCache"
192
  msgstr "Los registros son guardados por %%SUCURI.AuditLogs.Lifetime%% segundos"
@@ -209,8 +210,8 @@ msgstr "esta versión de WordPress no tiene soporte."
209
  msgid "NoWordPressFile"
210
  msgstr "El archivo no hace parte de la instalación oficial de WordPress."
211
 
212
- msgid "CannotCheckMissingFile"
213
- msgstr "No se pueden revisar archivos que no existen."
214
 
215
  msgid "ScheduledTask"
216
  msgstr "%1$s (cada %2$d segundos)"
@@ -303,7 +304,7 @@ msgid "EmailSubject.password_change"
303
  msgstr "Cambio de Contraseña"
304
 
305
  msgid "FailedLoginFooter"
306
- msgstr "<br><br><em>Explanación: Alguien intentó ingresar al sistema de administración de su sitio web. Si usted está recibiendo muchas de estas alertas, es posible que alguien esté utilizando un ataque de fuerza bruta para vulnerar su sitio [1]. Puede desactivar estas alertas desde aquí [2]. También puede considerar la instalación de un Firewall para filtrar el tráfico malicioso y ataques como este [3].</em><br><br>[1] <a href='https://kb.sucuri.net/definitions/attacks/brute-force/password-guessing'>https://kb.sucuri.net/definitions/attacks/brute-force/password-guessing</a><br>[2] <a href='%1$s'>%2$s</a> <br>[3] <a href='https://sucuri.net/website-firewall/?wpalert'>https://sucuri.net/website-firewall/</a><br>"
307
 
308
  msgid "FirewallAPIKeySet"
309
  msgstr "La llave del Firewall ha sido guardada"
@@ -333,10 +334,10 @@ msgid "FirewallNoCacheAtAll"
333
  msgstr "Desactivada (use con precaución)"
334
 
335
  msgid "FirewallNotEnabled"
336
- msgstr "El Firewall no ha sido activado en su sitio o la llave de autenticación es inválida."
337
 
338
  msgid "FirewallClearCacheFailure"
339
- msgstr "No se pudo actualizar la cache de su sitio, intente más tarde."
340
 
341
  msgid "Active"
342
  msgstr "activo"
@@ -429,7 +430,7 @@ msgid "AttemptDatetime"
429
  msgstr "Fecha/Hora"
430
 
431
  msgid "ConfirmOperation"
432
- msgstr "Debe confirmar que entiende el riesgo de esta operación."
433
 
434
  msgid "UnderstandTheRisk"
435
  msgstr "Entiendo que esta operación no puede ser revertida."
@@ -453,17 +454,20 @@ msgid "SomeItemsProcessed"
453
  msgstr "Solo <b>%1$d</b> de <b>%2$d</b> archivos fueron procesados."
454
 
455
  msgid "ErrorIntegrityAdded"
456
- msgstr "El plugin no tiene permiso para eliminar este archivo porque fué creado por otro usuario del sistema con más privilegios que su cuenta. Conéctese a su sitio a través de FTP para eliminarlo."
457
 
458
  msgid "ErrorIntegrityModified"
459
- msgstr "El plugin no tiene permiso para restablecer el contenido de este archivo porque fué modificado por otro usuario del sistema con más privilegios que su cuenta. Conéctese a su sitio a través de FTP para restablecerlo."
460
 
461
  msgid "ErrorIntegrityRemoved"
462
- msgstr "El plugin no tiene permiso para restablecer el contenido de este archivo porque el directorio donde está ubicado pertenece a otro usuario del sistema con más privilegios que su cuenta. Conéctese a su sitio a través de FTP para restablecerlo."
463
 
464
  msgid "SecurityAlerts"
465
  msgstr "Alertas de Seguridad"
466
 
 
 
 
467
  msgid "AlertSettingsUpdated"
468
  msgstr "La configuración para las alertas de seguridad ha sido actualizada"
469
 
@@ -471,13 +475,13 @@ msgid "OptionNotifyPluginChange"
471
  msgstr "Recibir alertas por cambios en la configuración del plugin de Sucuri"
472
 
473
  msgid "OptionPrettifyMails"
474
- msgstr "Recibir alertas en HTML <em>(puede experimentar problemas con su servicio de correo electrónico)</em>"
475
 
476
  msgid "OptionUseWordPressMail"
477
- msgstr "Usar funciones nativas de WordPress para enviar las alertas <em>(deseleccione para usar funciones nativas de PHP)</em>"
478
 
479
  msgid "OptionLastLoginRedirection"
480
- msgstr "Permitir redirección durante el login para reportar información acerca de la última autenticación exitosa de su cuenta de usuario"
481
 
482
  msgid "OptionNotifyScanChecksums"
483
  msgstr "Recibir alertas por diferencias en los archivos originales de WordPress"
@@ -492,19 +496,22 @@ msgid "OptionNotifySuccessLogin"
492
  msgstr "Recibir alertas por autenticaciones exitosas de usuario"
493
 
494
  msgid "OptionNotifyFailedLogin"
495
- msgstr "Recibir alertas por autenticaciones de usuario fallidas <em>(si su sitio está siendo atacado usted recibirá multiples alertas por segundo, deseleccione para reducir el Spam)</em>"
 
 
 
496
 
497
  msgid "OptionNotifyBruteforceAttack"
498
  msgstr "Recibir un resumen con todos los intentos de autenticación de usuario fallidos durante la misma hora. El reporte será eliminado del servidor una vez la información sea enviada a su correo"
499
 
500
  msgid "OptionNotifyPostPublication"
501
- msgstr "Recibir alertas por cambios en el estado de las publicaciones y páginas <em>(puede configurar qué alertas serán monitoreadas desde el panel \"Ignorar Cambios en Publicaciones\")</em>"
502
 
503
  msgid "OptionNotifyWebsiteUpdated"
504
- msgstr "Recibir alertas cuando su sitio web sea actualizado"
505
 
506
  msgid "OptionNotifySettingsUpdated"
507
- msgstr "Recibir alertas por cambios en la configuración general de su sitio web"
508
 
509
  msgid "OptionNotifyThemeEditor"
510
  msgstr "Recibir alertas cuando un archivo sea modificado a través del editor de Plugins/Plantillas"
@@ -525,10 +532,10 @@ msgid "OptionNotifyPluginDeleted"
525
  msgstr "Recibir alertas cuando un <b>plugin sea eliminado</b>"
526
 
527
  msgid "OptionNotifyWidgetAdded"
528
- msgstr "Recibir alertas cuando un <b>widget sea agregado</b> a su sitio web"
529
 
530
  msgid "OptionNotifyWidgetDeleted"
531
- msgstr "Recibir alertas cuando un <b>widget sea eliminado</b> de su sitio web"
532
 
533
  msgid "OptionNotifyThemeInstalled"
534
  msgstr "Recibir alertas cuando una <b>plantilla sea instalada</b>"
@@ -567,7 +574,7 @@ msgid "OptionPerHour160"
567
  msgstr "Máximo 160 por hora"
568
 
569
  msgid "BruteForceAlertSuccess"
570
- msgstr "El plugin asumirá que su sitio web eatá siendo atacado después de %1$s autenticaciones de usuario fallidas durante la misma hora"
571
 
572
  msgid "BruteForceAlertFailure"
573
  msgstr "Ese número no está soportado por el plugin, use uno de la lista"
@@ -600,13 +607,13 @@ msgid "DiffUtility"
600
  msgstr "Herramienta de Integridad de Archivos"
601
 
602
  msgid "DiffUtilityDescription"
603
- msgstr "Si su proveedor de hosting permite la ejecución de comandos del sistema a través de PHP, puede configurar el plugin para usar el comando <a href=\"https://en.wikipedia.org/wiki/Diff_utility\" target=\"_blank\" rel=\"noopener\">Diff de UNIX</a> para comparar el contenido actual de sus archivos con los archivos originales de WordPress. Esta herramienta le permitirá ver las diferencias entre ambos repositorios y actuar dependiendo de la información encontrada."
604
 
605
  msgid "DiffUtilityInfo"
606
- msgstr "El comand <b>diff</b> de Unix está activado. Puede hacer clic en los archivos marcados como modificados <em>(señalados con la bandera violeta)</em> para ver las diferencias detectadas por el escaner. Si usted considera que las diferencias no causan daño a su sitio puede marcar el archivo como revisado, de otra forma se le sugiere restaurar el contenido original inmediatamente."
607
 
608
  msgid "DiffUtilityInstructions"
609
- msgstr "Las lineas con un signo <b>negativo</b> como prefijo <em>(marcadas en rojo)</em> muestran el código original. Las lineas con un signo <b>positivo</b> como prefijo <em>(marcadas en verde)</em> muestran el código actual. Puede leer más acerca del formato DIFF en el artículo de WikiPedia <a target=\"_blank\" href=\"https://en.wikipedia.org/wiki/Diff_utility\" rel=\"noopener\">Unix Diff Utility</a>."
610
 
611
  msgid "AccountsWereBlocked"
612
  msgstr "Las cuentas de usuario seleccionadas han sido bloqueadas"
@@ -615,7 +622,7 @@ msgid "AccountsWereUnblocked"
615
  msgstr "Las cuentas de usuario seleccionadas han sido desbloqueadas"
616
 
617
  msgid "LastLoginMessage"
618
- msgstr "El último acceso de su cuenta fué en <b>%1$s</b> desde <b>%2$s</b> <em>(%3$s)</em> <a href='%4$s'>ver todos los registros</a>"
619
 
620
  msgid "LastLoginsNotWritable"
621
  msgstr "El archivo para los registros de autenticaciones de usuario no es modificable: <code>%1$s</code>"
@@ -630,13 +637,13 @@ msgid "ReverseProxyStatus"
630
  msgstr "El soporte para túneles proxy ha sido cambiado a <b>%1$s</b>"
631
 
632
  msgid "ReverseProxyInfo"
633
- msgstr "El plugin utiliza la dirección IP de cada usuario para registrar los eventos ejecutados, el plugin utiliza dos métodos para obtener esta dirección: el método principal usa una variable global del servidor llamada <em>Remote-Addr</em> disponible en la mayoría de servidores web, un método alternativo usa cabeceras de HTTP personalizadas <em>(que son consideradas inseguras por defecto)</em>. No es necesario que usted se preocupe por esta opción a menos que su sitio web esté detrás de un túnel proxy. Servicios como el <a href=\"https://sucuri.net/website-firewall/\" target=\"_blank\">Firewall de Sucuri</a> &mdash; una vez activo &mdash; forzan el paso del tráfico de red a través de ellos para filtrar amenazas de seguridad que podrían afectar el servidor original. Un efecto secundario del uso de estos servicios es que la dirección IP de los usuarios ya no está disponible entre las variables globales del servidor sino que es enviada a través de una cabecera HTTP personalizada."
634
 
635
  msgid "IPDiscoverer"
636
  msgstr "Detección de Direcciones IP"
637
 
638
  msgid "IPDiscovererInfo"
639
- msgstr "La detección de direcciones IP hace uso de DNS para detectar si el sitio web está detrás del <a href=\"https://sucuri.net/website-firewall/\" target=\"_blank\">Firewall de Sucuri</a> en cuyo caso modificará las variables globales del servidor para configurar la dirección IP real de cada visitante del sitio. Este proceso es ejecutado con cada proceso de WordPress y es posible que la velocidad de su sitio sea afectada ya que algunos proveedores de hosting utilizan servidores DNS lentos lo que hace que esta operación tome más tiempo de lo que se espera."
640
 
641
  msgid "HTTPHeader"
642
  msgstr "Cabecera de HTTP"
@@ -735,7 +742,7 @@ msgid "WillNotReceiveAlerts"
735
  msgstr "Estos correos no recibirán más alertas de seguridad: <code>%1$s</code>"
736
 
737
  msgid "TestAlertSent"
738
- msgstr "Un correo de prueba ha sido enviado a su dirección, revise su bandeja de entrada"
739
 
740
  msgid "InvalidEmail"
741
  msgstr "Formato de correo electrónico inválido."
@@ -795,7 +802,7 @@ msgid "Cronjobs"
795
  msgstr "Acciones Automatizadas"
796
 
797
  msgid "CronjobsInfo"
798
- msgstr "Acciones automatizadas son reglas registradas en su base de datos por un plugin, plantilla o WordPress; estas reglas son usadas para ejecutar automáticamente acciones definidas en el código con un intervalo de tiempo definido. Un buen uso de estas reglas es la generación de copias de seguridad, la ejecución de escáneres de seguridad o la remoción de elementos innecesarios de la base de datos como borradores de publicaciones. <b>Nota:</b> Las acciones automatizadas pueden ser re-instaladas por cualquier plugin/plantilla automáticamente, considere desactivar el plugin completamente si quiere eliminar una de estas acciones."
799
 
800
  msgid "CronjobRunNow"
801
  msgstr "Ejecutar Ahora (en +10 segundos)"
@@ -813,7 +820,7 @@ msgid "CronjobsWereNotSelected"
813
  msgstr "Ninguna acción automatizada ha sido seleccionada de la lista"
814
 
815
  msgid "DNSLookupStatus"
816
- msgstr "El estado las conexiones via DNS para detectar el uso de túneles proxy ha sido cambiado"
817
 
818
  msgid "IncorrectEncoding"
819
  msgstr "Los datos han sido codificados incorrectamente"
@@ -825,19 +832,22 @@ msgid "APIKey"
825
  msgstr "Llave de Autenticación"
826
 
827
  msgid "APIKeyInfo"
828
- msgstr "La mayoría de herramientas en este plugin pueden ser usadas sin una configuración específica, pero las herramientas más importantes requieren de una <b>llave de autenticación</b> para establecer un túnel de comunicación segura con los servidores de Sucuri. La llave es generada usando su correo electrónico y el nombre dominio de su sitio web, esto le permitirá tener acceso a la herramienta de monitoreo y opciones extra."
829
 
830
  msgid "APIKeyTerms"
831
- msgstr "Tenga en cuenta que generar una llave implica que usted está de acuerdo con enviar la información recolectada por el plugin a los servidores de Sucuri, esto le permite mantener los registros de seguridad fuera del alcance de usuarios maliciosos que podrían intentar eliminarlos para limpiar sus huellas durante un ataque. Nosotros además usamos esta información de forma anónima para generar <a href=\"https://sucuri.net/security-reports/brute-force/\" target=\"_blank\">estadísticas</a>. Por favor, no genere la llave de autenticación si usted está en desacuerdo con esto, usted puede seguir usando el plugin sin la llave."
 
 
 
832
 
833
  msgid "APIKeyInvalidDomain"
834
- msgstr "Su sitio web <code>%%SUCURI.CleanDomain%%</code> parece no tener un registro de DNS tipo <code>A</code> así que la API lo considerará inválido durante el proceso de generación su la llave. Agregue <code>www</code> al inicio del dominio para intentar solucionar el problema. Envíe un mensaje a nuestro servicio de soporte si no entiende qué significa esto."
835
 
836
  msgid "APIKeyRecoverButton"
837
  msgstr "Recuperar Por Correo Electrónico"
838
 
839
  msgid "APIKeyRecoveryCondition"
840
- msgstr "Si usted no tiene acceso al correo electrónico usado para generar la llave pero tiene una copia de la misma a la mano, haga <a target=\"_self\" href=\"%%SUCURI.URL.Settings%%&recover\">clic aquí</a> para activar el plugin manualmente. Tenga en cuenta que si la llave es inválida el plugin la eliminará inmediatamente."
841
 
842
  msgid "ApplyHardening"
843
  msgstr "Aplicar Hardening"
@@ -849,16 +859,16 @@ msgid "HardeningFirewallTitle"
849
  msgstr "Firewall Para Aplicaciones Web"
850
 
851
  msgid "HardeningFirewallDescription"
852
- msgstr "Un WAF (Web Application Firewall) es una capa de protección para su sitio web que bloquea todo tipo de ataques (fuerza bruta, denegación de servicios, inyecciones a base de datos, etc) y le ayuda a permanecer limpio de código malicioso y fuera de listas negras. Esta opción verifica si su sitio web está usando el Firewall de Sucuri como su capa de protección primaria."
853
 
854
  msgid "HardeningFirewallPurchase"
855
- msgstr "El Firewall de Sucuri es un servicio premium que puede comprar aquí - <a href='https://goo.gl/qfNkMq' target='_blank'>Sucuri Firewall</a>"
856
 
857
  msgid "HardeningVersionTitle"
858
  msgstr "Verificar la Versión de WordPress"
859
 
860
  msgid "HardeningVersionDescription"
861
- msgstr "¿Por qué mantener su sitio web actualizado? WordPress es un proyecto de código libre lo que significa que todos los cambios hechos al código son hechos de forma pública, si alguno de esos cambios hace parte de una solución para un problema de seguridad, cualquier persona puede utilizar esta información para atacar su sitio web si este aún no ha aplicado el parche de seguridad."
862
 
863
  msgid "HardeningPHPVersionTitle"
864
  msgstr "Verificar la Versión de PHP"
@@ -867,31 +877,31 @@ msgid "HardeningPHPVersionDescription"
867
  msgstr "PHP %1$s está instalado."
868
 
869
  msgid "HardeningPHPVersionLifetime"
870
- msgstr "Comuníquese con su proveedor de hosting para instalar una version actualizada de PHP - <a href='http://php.net/supported-versions.php' target='_blank' rel='noopener'>Lista de Versiones de PHP Soportadas</a>"
871
 
872
  msgid "HardeningGeneratorTitle"
873
  msgstr "Eliminar Versión de WordPress"
874
 
875
  msgid "HardeningGeneratorDescription"
876
- msgstr "Esta opción verifica si la versión de WordPress usada en su sitio web está siendo expuesta de forma pública a través del código HTML. Muchos escáneres de vulnerabilidades web utilizan esta información para determinar si su página web tiene vulnerabilidades para luego ser explotadas. Tenga en cuenta que aún sin esta información un escáner inteligente puede detectar la versión de WordPress en uso comparando los Checksums de algunos archivos estáticos distribuidos con cada instalación."
877
 
878
  msgid "HardeningNginxTitle"
879
  msgstr "Bloquear Algunos Archivos PHP"
880
 
881
  msgid "HardeningNginxDescription"
882
- msgstr "Esta opción bloquea la ejecución de archivos PHP en directorios sensitivos. Sea cuidadoso cuando aplique esta opción ya que algunos plugins y plantillas requieren de acceso público a este directorio para algunas de sus herramientas, por ejemplo, para generar imágenes o guardar información temporalmente. Agrégue los archivos que están siendo bloqueados a la lista blanca de archivos PHP."
883
 
884
  msgid "HardeningNginxField"
885
  msgstr "Verificar Hardening"
886
 
887
  msgid "HardeningNginxSuggestion"
888
- msgstr "Léa las instrucciones oficiales de WordPress para aprender como restringir el acceso a archivos PHP en directorios sensitivos - <a href='https://codex.wordpress.org/Nginx#Global_restrictions_file' target='_blank' rel='noopener'>Restricciones Globales para Nginx y WordPress</a>"
889
 
890
  msgid "HardeningUploadsTitle"
891
  msgstr "Bloquear Archivos PHP en el Directorio de Subidas"
892
 
893
  msgid "HardeningUploadsDescription"
894
- msgstr "Esta opción bloquea la ejecución de archivos PHP en directorios sensitivos. Sea cuidadoso cuando aplique esta opción ya que algunos plugins y plantillas requieren de acceso público a este directorio para algunas de sus herramientas, por ejemplo, para generar imágenes o guardar información temporalmente. Agrégue los archivos que están siendo bloqueados a la lista blanca de archivos PHP."
895
 
896
  msgid "HardeningUploadsApplySuccess"
897
  msgstr "Hardening aplicado al directorio de subidas"
@@ -909,7 +919,7 @@ msgid "HardeningContentTitle"
909
  msgstr "Bloquear Archivos PHP en el Directorio de Contenido"
910
 
911
  msgid "HardeningContentDescription"
912
- msgstr "Esta opción bloquea la ejecución de archivos PHP en directorios sensitivos. Sea cuidadoso cuando aplique esta opción ya que algunos plugins y plantillas requieren de acceso público a este directorio para algunas de sus herramientas, por ejemplo, para generar imágenes o guardar información temporalmente. Agrégue los archivos que están siendo bloqueados a la lista blanca de archivos PHP."
913
 
914
  msgid "HardeningContentApplySuccess"
915
  msgstr "Hardening aplicado al directorio de contenido"
@@ -927,7 +937,7 @@ msgid "HardeningIncludesTitle"
927
  msgstr "Bloquear Archivos PHP en el Directorio de Inclusiones"
928
 
929
  msgid "HardeningIncludesDescription"
930
- msgstr "Esta opción bloquea la ejecución de archivos PHP en directorios sensitivos. Sea cuidadoso cuando aplique esta opción ya que algunos plugins y plantillas requieren de acceso público a este directorio para algunas de sus herramientas, por ejemplo, para generar imágenes o guardar información temporalmente. Agrégue los archivos que están siendo bloqueados a la lista blanca de archivos PHP."
931
 
932
  msgid "HardeningIncludesApplySuccess"
933
  msgstr "Hardening aplicado al directory de inclusiones"
@@ -945,7 +955,7 @@ msgid "HardeningReadmeTitle"
945
  msgstr "Exposición de Información"
946
 
947
  msgid "HardeningReadmeDescription"
948
- msgstr "Esta opción verifica si el archivo README todavía existe. La información en este archivo puede ser usada por personas maliciosas para encontrar vulnerabilidades asociadas con la versión de WordPress que usted ha instalado. Tenga en cuenta que este archivo is re-creado cada vez que una actualización es ejecutada."
949
 
950
  msgid "HardeningReadmeApplySuccess"
951
  msgstr "Hardening aplicado sobre el archivo README"
@@ -957,7 +967,7 @@ msgid "HardeningAdminUserTitle"
957
  msgstr "Cuenta de Administración Primaria"
958
 
959
  msgid "HardeningAdminUserDescription"
960
- msgstr "Esta opción verifica si la cuenta de administración primaria está usando un nombre fácil de adivinar como \"admin\". Esto permite a personas maliciosas identicar fácilmente qué cuenta tiene los privilegios más altos entre todos los usuarios registrados."
961
 
962
  msgid "HardeningFileEditorTitle"
963
  msgstr "Editor de Plugins y Plantillas"
@@ -972,7 +982,7 @@ msgid "HardeningFileEditorRevertSuccess"
972
  msgstr "Hardening revertido en el editor de plugins y plantillas"
973
 
974
  msgid "HardeningFileEditorRevertFailure"
975
- msgstr "El editor de plugins y plantillas no fue desactivado usando el plugin de Sucuri. Usted debe escanear su sitio web por una constante definida como \"DISALLOW_FILE_EDIT\" cuando la encuentre debe eliminarla o cambiar su valor a \"False\". Tenga en cuenta que cualquier otro plugin o plantilla puede desactivar el editor, así que es imposible determinar el origen de la constante."
976
 
977
  msgid "PHPWhitelistSuccess"
978
  msgstr "El archivo ha sido agregado a la lista blanca de archivos PHP"
@@ -987,7 +997,7 @@ msgid "DiffUtilityStatus"
987
  msgstr "El estado de la herramienta de integridad ha sido cambiado"
988
 
989
  msgid "DiffUtilityMissing"
990
- msgstr "Su proveedor de hosting no permite la ejecución de comandos del sistema a través de archivos PHP."
991
 
992
  msgid "IntegrityLanguage"
993
  msgstr "El idioma para la herramienta de integridad de archivos de WordPress ha sido cambiado"
@@ -1032,22 +1042,22 @@ msgid "NotBlacklisted"
1032
  msgstr "Sin Lista Negra"
1033
 
1034
  msgid "APIKeyExplanation"
1035
- msgstr "Una llave de autenticación es necesaria para activar herramientas adicionales disponibles en el plugin. Las llaves son gratuitas y puede generar un número ilimitado de ellas siempre y cuando el nombre del sitio web y el correo electrónico sean únicos. La llave es usada para autenticar las conexiones a través de HTTP hechas a la API administrada por Sucuri Inc. No genere la llave si usted está en desacuerdo con el envío de información a nuestros servidores."
1036
 
1037
  msgid "APIKeyHelp"
1038
- msgstr "Si experimenta problemas con la generación de la llave, puede solicitar una enviando la dirección de su sitio web y el correo electrónico que desea usar para la asociacón a <a href=\"mailto:info@sucuri.net\">info@sucuri.net</a>. Tenga en cuenta que generar una llave para un sitio web que no es público en Internet no es posible ya que la API necesita validar que el nombre del host existe, sin embargo, si usted desea probar el plugin en un ambiente de desarrollo por favor contáctenos para poder generar una llave manualmente."
1039
 
1040
  msgid "APIKeyGenerated"
1041
- msgstr "Felicitaciones! Todas las herramientas disponibles en el plugin han sido habilitadas. Este producto está diseñado para suplementar productos de seguridad existentes en su sitio web. El plugin no provee una solución completa a sus necesidades de seguridad, pero le ofrece más herramientas para controlar el funcionamiento de su sitio y tener una mejor postura con respecto a ataques que pueda sufrir en el futuro, todo esto con la intensión de reducir riesgos."
1042
 
1043
  msgid "APIKeyContinueSetup"
1044
- msgstr "Sucuri Inc. ha generado una llave única para su sitio web, esta llave fué asociada al correo electrónico que seleccionó anteriormente, correo que puede utilizar para recuperar dicha llave si llega a perderla en el futuro. Le invitamos a revisar el resto de opciones disponibles en la página de ajustes paraque configure el plugin a la medida de su sitio."
1045
 
1046
  msgid "APIKeyRecoveryExplanation"
1047
- msgstr "Si esta operación fué exitosa, usted recibirá un mensaje en el correo electrónico que usó durante la generación de la llave <em>(usualmente este correo es el mismo asociado a la cuenta de administración primaria)</em>. Este mensaje contiene una copia de la llave, por favor copie y péguela en el formulario de abajo. El plugin verificará la autenticidad de la misma, si esta verificación falla la llave será eliminada automáticamente y usted deberá iniciar el proceso de recuperación nuevamente."
1048
 
1049
  msgid "APIKeyRecoveryPossibleFailures"
1050
- msgstr "Existen casos en los que esta operación puede fallar, un ejemplo sería cuando el correo electrónico ya no está asociado al sitio web, esto sucede cuando la base de la URL cambia <em>(de www a nada y viceversa)</em>. Si está teniendo problemas con el proceso de recuperación de la llave, por favor envíe un mensaje explicando la situación a <a href=\"mailto:info@sucuri.net\">info@sucuri.net</a>"
1051
 
1052
  msgid "DNSLookups"
1053
  msgstr "Conexiones DNS"
@@ -1056,7 +1066,7 @@ msgid "DNSLookupsLabel"
1056
  msgstr "Activar conexiones DNS al inicio de cada proceso"
1057
 
1058
  msgid "DNSLookupsText"
1059
- msgstr "Active esta opción si su sitio web está destrás de un Firewall, esto garantizará que la dirección IP de sus visitantes será detectada correctamente para los registros de seguridad. Usted puede cambiar esto después desde la página de configuraciones del plugin."
1060
 
1061
  msgid "IntegrityTitle"
1062
  msgstr "Integridad de la Instalación"
@@ -1071,16 +1081,16 @@ msgid "IntegrityGoodTitle"
1071
  msgstr "Todos los Archivos Están Intáctos"
1072
 
1073
  msgid "IntegrityGoodDescription"
1074
- msgstr "No hemos detectado archivos adicionales, eliminados or cambios relevantes en los archivos originales de WordPress. Si usted está experimentando otros problemas, por favor use un <a target=\"_blank\" href=\"https://sucuri.net/website-security/malware-removal\">servicio de limpieza de malware</a>."
1075
 
1076
  msgid "IntegrityBadTitle"
1077
  msgstr "Archivos de WordPress Modificados"
1078
 
1079
  msgid "IntegrityBadDescription"
1080
- msgstr "Hemos identificado que algunos de los archivos de WordPress han sido modificados. Esto podría indicar un ataque o la existencia de un archivo corrupto en su instalación. Si usted está experimentando otros problemas, por favor use un <a target=\"_blank\" href=\"https://sucuri.net/website-security/malware-removal\">servicio de limpieza de malware</a>."
1081
 
1082
  msgid "MarkFixedDescription"
1083
- msgstr "Marcar uno o más archivos como revisado forzará al plugin a ignorar dichos archivos durante futuros escaneos, esto es útil cuando un archivo contiene falsos/positivos. Adicionalmente, puede restaurar el contenido original si estos han sido modificados o eliminados, el plugin descargará una copia del código desde el <a href=\"https://core.svn.wordpress.org/tags/\" target=\"_blank\" rel=\"noopener\">repositorio oficial de WordPress</a>. La eliminación de archivos es una operación irreversible, sea cuidadoso."
1084
 
1085
  msgid "Action"
1086
  msgstr "Acción"
@@ -1134,40 +1144,55 @@ msgid "FirewallSettingsTitle"
1134
  msgstr "Ajustes del Firewall"
1135
 
1136
  msgid "FirewallSettingsInfo"
1137
- msgstr "Un poderoso Firewall para aplicaciones web y <b>Sistema para la Detección de Intrusiones</b> para cualquier usuario de WordPress y cualquier otra plataforma. Esta página le ayudará a configurar y monitorear su sitio web a través del <b>Firewall de Sucuri</b>. Una vez activado, nuestro Firewall actuará como un escudo, protegiendo su sitio de ataques y previniendo infecciones de malware y reinfecciones. El Firewall también bloqueará inyecciones a bases de datos, ataques de fuerza bruta, XSS, RFI, puertas traseras y muchas otras amenazas en contra de su sitio web."
1138
 
1139
  msgid "FirewallKey"
1140
  msgstr "Llave del Firewall"
1141
 
1142
  msgid "FirewallAddKey"
1143
- msgstr "Agregue la <a href=\"https://waf.sucuri.net/?settings&panel=api\" target=\"_blank\">llave del Firewall</a> en el formulario para iniciar una conexión con la API."
1144
 
1145
  msgid "FirewallFootNote"
1146
- msgstr "<em>[1]</em> Más información acerca del <a href=\"https://sucuri.net/website-firewall/\" target=\"_blank\">Firewall de Sucuri</a>, herramientas disponibles y precios.<br><em>[2]</em> Instrucciones y videos en la <a href=\"https://kb.sucuri.net/firewall\" target=\"_blank\">Wiki de Sucuri</a>.<br><em>[3]</em> <a href=\"https://login.sucuri.net/signup2/create?CloudProxy\" target=\"_blank\">Registre</a> una cuenta nueva y empiece a proteger su sitio web."
1147
 
1148
  msgid "FirewallLogsTitle"
1149
  msgstr "Registros de Seguridad del Firewall"
1150
 
1151
  msgid "FirewallLogsInfo"
1152
- msgstr "El Firewall de Sucuri registra todas las conexiones HTTP involucradas en un ataque y las separa de las conexiones legítimas. Puede usar esta herramienta para analizar la información de las últimas conexiones y tomar acción y sea activando las herramientas avanzadas del IDS <em>(Intrusion Detection System)</em> desde el <a target=\"_blank\" href=\"https://waf.sucuri.net/?settings\">panel de administración del Firewall</a> y/o bloquear las direcciones IP y URL directamente desde la <a href=\"https://waf.sucuri.net/?audit\" target=\"_blank\">página de registros de seguridad del Firewall</a>."
1153
 
1154
  msgid "FirewallLogsNote"
1155
- msgstr "Las conexiones que no fueron bloqueadas son omitidas en la lista, esto es intensional."
 
 
 
 
 
 
 
 
 
 
 
 
1156
 
1157
  msgid "FirewallCacheTitle"
1158
- msgstr "Cache del Firewall"
1159
 
1160
  msgid "FirewallCacheButton"
1161
- msgstr "Limpiar Cache"
1162
 
1163
  msgid "FirewallCacheInfo"
1164
- msgstr "El Firewall ofrece multiples opciones para configurar el nivel de cache aplicado a su sitio web. Puede considerar activar la covertura total de la cache <em>(que es lo recomendado)</em>, o puede configurar la cache a un nivel mínimo, o forzar el uso de las cabeceras HTTP <em>(solo para usuarios avanzados)</em>, o en casos extremos donde usted no necesita la cache puede desactivarla completamente. Puede encontrar más información acerca de estas opciones <a target=\"_blank\" href=\"https://kb.sucuri.net/firewall/Performance/caching-options\">aquí</a>."
1165
 
1166
  msgid "FirewallCacheNote"
1167
- msgstr "Tenga en cuenta que el Firewall tiene unas <a href=\"https://kb.sucuri.net/firewall/Performance/cache-exceptions\" target=\"_blank\">reglas especiales para la cache</a> de imágenes, archivos CSS, archivos PDF, archivos de texto, código JavaScript, archivos audio visuales y algunas otros formatos de archivo que son guardados en nuestros <a href=\"https://en.wikipedia.org/wiki/Edge_device\" target=\"_blank\" rel=\"noopener\">Edge Devices</a>. La única forma de limpiar la cache de estos archivos es haciendo uso de parámetros aleatorios en la URL, puede agregar un parametro como este <code>?ver=1.2.3</code> e incrementar el número con cada actualización."
1168
 
1169
  msgid "FirewallCacheWiki"
1170
- msgstr "La cache web es una tecnología para el almacenamiento temporal (caching) de documentos web, como páginas en HTML e imágenes, para reducir el uso de ancho de banda, la carga del servidor, y retrasos en las descargas. Un sistema de cache web guarda copias de los documentos que pasan a través de él; conexiones subsecuentes pueden devolver el contenido desde la cache si las condiciones lo permiten. &mdash; <a href=\"https://en.wikipedia.org/wiki/Web_cache\" target=\"_blank\" rel=\"noopener\">WikiPedia - Web Cache</a>"
 
 
 
1171
 
1172
  msgid "LoginsAdmins"
1173
  msgstr "Autenticaciones Exitosas (admins)"
@@ -1200,28 +1225,34 @@ msgid "BlockedUsersInfo"
1200
  msgstr "Todo intento de autenticación que haga uso de las funciones nativas de WordPress será interceptado y analizado por el plugin, si el nombre de usuario coincide con alguno en esta lista la conexión al servidor será inmediatamente detenida. Estos intentos no serán registrados y ninguna alerta de seguridad será enviada."
1201
 
1202
  msgid "BlockedUsersNote"
1203
- msgstr "Tenga en cuenta que esta herramienta no intenta proveer una protección completa para bloquear autenticaciones indeseadas de usuarios maliciosos. Dependiendo de la configuración de su sitio web, los plugins o plantillas que sean instalados, o inclusive la versión de WordPress que esté usando, habrán huecos en el sistema que usuarios maliciosos pueden utilizar para evadir estos bloqueos e iniciar un ataque por fuerza bruta. <a target=\"_blank\" href=\"https://sucuri.net/website-firewall/?wp=bu\">Instale un Firewall</a> para tener protección completa y mitigar este y otros ataques en contra de su sitio web."
1204
 
1205
  msgid "BlockedUsersByIP"
1206
- msgstr "El bloqueo de usuarios por dirección IP es una opción disponible en el <a href=\"https://sucuri.net/website-firewall/\" target=\"_blank\">Firewall de Sucuri</a>; para evitar la duplicación de código y reducir la cantidad de falsos/positivos esta opción nunca será implementada en este plugin."
1207
 
1208
  msgid "FailedLogins"
1209
  msgstr "Autenticaciones Fallidas"
1210
 
1211
  msgid "FailedLoginsInfo"
1212
- msgstr "Esta información será usada para determinar si su sitio es víctima de un <a href=\"https://kb.sucuri.net/definitions/attacks/brute-force/password-guessing\" target=\"_blank\">Password Guessing Brute Force Attacks</a>. Estos registros serán acumulados, si más de <code>%%SUCURI.FailedLogins.MaxFailedLogins%%</code> autenticaciones fallidas son registradas durante la misma hora, el plugin enviará un correo electrónico con un resumen del ataque <em>(debe activar esta opción desde la página de ajustes, sección alertas)</em>. <b>NOTE:</b> Algunos plugins que ofrecen la opción de <em>\"Autenticación por Dos-Pasos\"</em> no usan las funciones nativas de WordPress, motivo por el cual algunos intentos de autenticación no podrán ser interceptados ni analizados."
1213
 
1214
  msgid "LoggedInUsers"
1215
  msgstr "Usuarios Activos"
1216
 
1217
  msgid "LoggedInUsersInfo"
1218
- msgstr "Aquí puede encontrar una lista de usuarios que han iniciado una sesión en los últimos minutos."
1219
 
1220
  msgid "Recomendations"
1221
  msgstr "Recomendaciones"
1222
 
1223
  msgid "SiteCheckNoResults"
1224
- msgstr "Si nuestro escáner gratuito no ha detectado algún problema, es posible que su sitio tenga un problema más complicado y la infección esté escondida. Puede <a target=\"_blank\" href=\"https://sucuri.net/website-security-platform/signup\">registrar una cuenta con Sucuri</a> para obtener un escaneo más detallado y eventualmente una limpieza absoluta de su sitio web (no incluido con el plan gratuito)."
 
 
 
 
 
 
1225
 
1226
  msgid "PasswordAttack"
1227
  msgstr "Ataque De Fuerza Bruta En Contra De Contraseñas"
@@ -1230,7 +1261,7 @@ msgid "PasswordAttackAfter"
1230
  msgstr "Considerar Ataque Después De"
1231
 
1232
  msgid "PasswordAttackInfo"
1233
- msgstr "Los <a href=\"https://kb.sucuri.net/definitions/attacks/brute-force/password-guessing\" target=\"_blank\">ataques de fuerza bruta en contra de contraseñas</a> son muy comunes en sitios web y páneles de administración. Estos son uno de los vectores más comunes usado para comprometer sitios web. El proceso es muy simple, los atacantes básicamente intentan múltiple combinaciones de usuario y contraseña hasta que encuentran una que funciona. Una vez el acceso al sitio es obtenido, ellos inyectan código malicioso en el código para generar spam, crear páginas fraudulentas, etc."
1234
 
1235
  msgid "PostTypeAlerts"
1236
  msgstr "Alerts Para Diferentes Tipos de Publicaciones"
@@ -1242,13 +1273,13 @@ msgid "PostType"
1242
  msgstr "Tipo de Publicación"
1243
 
1244
  msgid "PostTypeAlertsDisabled"
1245
- msgstr "Usted ha desactivado las alertas de seguridad cuando una publicación es creada o modificada, esta herramienta espera que esa opción esté activa para poder filtrar los tipos de publicaciones que no son relevantes para el administrador del sitio."
1246
 
1247
  msgid "PostTypeAlertsInfo"
1248
- msgstr "Esta es una lista de <a href=\"https://codex.wordpress.org/Post_Types\" target=\"_blank\" rel=\"noopener\">tipos de publicaciones</a> registradas. Usted recibirá alertas de seguridad cuando una página o publicación sea creada o modificada. Algunos de estos tipos son nativos de WordPress pero la mayoria son creados por plugins y plantillas que usted ha instalado. Si usted no quiere recibir alertas por cambios en uno o más de estos tipos puede usar este panel para desactivarlas."
1249
 
1250
  msgid "PostTypeAlertsInvisible"
1251
- msgstr "Si usted está recibiendo alertas por cambios en tipos de publicaciones que no aparecen en la lista, es posible que estas hayan sido creadas dinámicamente por un plugin o plantilla sin usar las funciones nativas de WordPress. Si conoce el identificador único del tipo de publicación puede ingresarlo en el formulario y el plugin de Sucuri hará lo mejor posible para ignorar estas alertas."
1252
 
1253
  msgid "PostTypeAlertsStop"
1254
  msgstr "Ignorar Cambios En Este Tipo De Publicaciones"
@@ -1260,7 +1291,7 @@ msgid "AlertsPerHourMaximum"
1260
  msgstr "Número Máximo De Alertas Por Hora"
1261
 
1262
  msgid "AlertsPerHourInfo"
1263
- msgstr "Utilice esta opción para configurar el número máximo de alertas de seguridad por hora. Si el número es excedido y el plugin detecta mas eventos durante la misma hora, estos serán agregados al registro de seguridad pero no serán enviados por correo electrónico. Tenga cuidado con esta opción ya que puede perder información importante."
1264
 
1265
  msgid "TestAlerts"
1266
  msgstr "Probar Alertas"
@@ -1269,7 +1300,7 @@ msgid "AlertsRecipient"
1269
  msgstr "Quién Recibirá Alertas"
1270
 
1271
  msgid "AlertsRecipientInfo"
1272
- msgstr "Por defecto, el plugin enviará las alertas de seguridad a la cuenta de administración primaria, la misma cuenta que fué creada durante el proceso de instalación de WordPress en su servidor web. Usted puede agregar más direcciones de correo a la lista, ellos recibirán una copia de las mismas alertas de seguridad."
1273
 
1274
  msgid "CustomFormat"
1275
  msgstr "Formato Personalizado"
@@ -1278,7 +1309,7 @@ msgid "AlertsSubject"
1278
  msgstr "Asunto de la Alerta"
1279
 
1280
  msgid "AlertsSubjectInfo"
1281
- msgstr "El formato para el asunto de las alertas de seguridad, por defecto las alertas incluirán el nombre del sitio web y el identificador del evento, usted puede usar este panel para agregar la dirección IP del usuario o cualquier otra información adicional. También puede crear filtros en su cliente de correo electrónico agregando etiquetas personalizadas en el formulario."
1282
 
1283
  msgid "TrustedIPs"
1284
  msgstr "Direcciones IP Seguras"
@@ -1290,13 +1321,13 @@ msgid "IPAddedAt"
1290
  msgstr "Dirección Agregada en"
1291
 
1292
  msgid "TrustedIPsInfo"
1293
- msgstr "Si usted está trabajando en una red de área local, puede querer includir las direcciones IP de todos los nodos de la red en esta lista, esto hará que el plugin ignore todos los eventos originados desde estas direcciones para reducir la cantidad de falsos/positivos. Puede usar el formato CIDR <em>(Classless Inter Domain Routing)</em> para especificar un rango de direcciones IP <em>(solo 8, 16, y 24)</em>."
1294
 
1295
  msgid "APIViaProxy"
1296
  msgstr "API a Través de un Proxy"
1297
 
1298
  msgid "APIViaProxyInfo"
1299
- msgstr "Todas las conexiones a través de HTTP usadas para comunicarse con la API utilizan las funciones nativas de WordPress, esto significa que usted puede usar el mismo mecanismo sugerido por WordPress para establecer estas conexiones a través de un proxy. De acuerdo a la <a href=\"https://developer.wordpress.org/reference/classes/wp_http_proxy/\" target=\"_blank\" rel=\"noopener\">documentación oficial</a> usted debe agregar estas constantes en el archivo de configuración: <em>WP_PROXY_HOST, WP_PROXY_PORT, WP_PROXY_USERNAME, WP_PROXY_PASSWORD</em>."
1300
 
1301
  msgid "ProxyHostname"
1302
  msgstr "Dirección del Servidor Proxy"
@@ -1314,10 +1345,10 @@ msgid "APICommunication"
1314
  msgstr "Conexión con la API"
1315
 
1316
  msgid "APICommunicationInfo"
1317
- msgstr "Una vez la llave para la API haya sido generada, el plugin establecerá una comunicación con un servicio remoto que actuará como una caja fuerte para almacenar los registros de seguridad generados cuando algo sospechoso sucede en su sitio web. Si el sitio es comprometido, el hacker no podrá eliminar los registros de seguridad para encubrir sus huellas, de esta forma usted podrá investigar el ataque y prevenir futuros problemas."
1318
 
1319
  msgid "APICommunicationDisabled"
1320
- msgstr "Desactivar la comunicación entre el plugin y la API detendrá el monitor de eventos de seguridad. Considere activar el exportador de registros desde la página general de ajustes para mantener el monitor de eventos funcionando sin enviar datos a la API, de lo contrario, un usuario malicioso podrá ejecutar acciones sin que un administrador se de cuenta de lo que está sucediendo."
1321
 
1322
  msgid "APITimeout"
1323
  msgstr "Tiempo de Espera para la API"
@@ -1329,7 +1360,7 @@ msgid "APITimeoutValue"
1329
  msgstr "Esperar <b>%%SUCURI.RequestTimeout%%</b> antes de terminar la conexión"
1330
 
1331
  msgid "APITimeoutInfo"
1332
- msgstr "El plugin envía a la API información asociada a los eventos generados por WordPress que sean considerados sospechosos. El envío de estos datos sea hace a través de HTTP usando uno de los protocolos de comunicación disponibles en el sistema y <a target=\"_blank\" href=\"https://developer.wordpress.org/reference/functions/wp_remote_post/\" rel=\"noopener\">funciones nativas de WordPress</a>. Si la conexión o el servicio remoto excede la cantidad de segundos configurados en esta opción, la operación es cancelada. Si usted experimenta problemas de conexión por favor comuníquese con su proveedor de hosting para investigar los bloqueos."
1333
 
1334
  msgid "HTAccessTitle"
1335
  msgstr "Integridad del Archivo .htaccess"
@@ -1344,22 +1375,22 @@ msgid "HTAccessNotFound"
1344
  msgstr "El sitio web no tiene un archivo <code>.htaccess</code> o no se encuentra en la ubicación esperada."
1345
 
1346
  msgid "HTAccessStandard"
1347
- msgstr "El archivo <code>.htaccess</code> principal contiene las reglas estándares de WordPress generadas durante la instalación del sitio web. Usted puede modificar estas reglas para aumentar el rendimiento del servidor o para generar redirecciones a otras páginas. Para obtener más información al respecto visite la página oficial con la documentación en <a target=\"_blank\" rel=\"noopener\" href=\"https://codex.wordpress.org/Using_Permalinks#Creating_and_editing_.28.htaccess.29\"> Codex WordPress - Creating and editing (.htaccess)</a>"
1348
 
1349
  msgid "ScannerDescription"
1350
- msgstr "El plugin escanea su sitio web en busca de cambios que son eventualmente reportados a la API y visualizados a través de los registros de seguridad. Este escáner es ejecutado automáticamente cada día pero usted puede cambiar la frecuencia dependiendo de sus necesidades. Tenga en cuenta que si su sitio contiene una gran cantidad de archivos es posible que el escáner sea bloqueado por su proveedor de hosting si este excede el límite de ejecución que ellos hayan impuesto sobre su cuenta."
1351
 
1352
  msgid "ScannerWithoutSPL"
1353
- msgstr "El escáner hace uso de las librerías <a href=\"http://php.net/manual/en/class.splfileobject.php\" target=\"_blank\" rel=\"noopener\">SPL</a> y <a target=\"_blank\" href=\"http://php.net/manual/en/class.filesystemiterator.php\" rel=\"noopener\">Filesystem Iterator</a> de PHP para escanear el árbol de directorios de su sitio web. Esta librería solo está disponible en PHP 5 >= 5.3.0 &mdash; y &mdash; PHP 7; si su servidor hace uso de una versión antigua el plugin no funcionará como se espera. Por favor, contacte a su proveedor de hosting para obtener ayuda al respecto."
1354
 
1355
  msgid "IntegrityLanguageTitle"
1356
  msgstr "Integridad de WordPress (Idioma)"
1357
 
1358
  msgid "IntegrityInfo"
1359
- msgstr "La información necesaria para verificar la integridad de su instalación de WordPress proviene de la <a href=\"http://codex.wordpress.org/WordPress.org_API\" target=\"_blank\" rel=\"noopener\">API Oficial de WordPress</a>. El plugin compara esta información con los archivos instalados en su sitio web. Por defecto, la API provee una copia de los archivos en Inglés, si usted ha instalado un idioma diferente por favor selecciónelo en esta opción para reducir la cantidad de falsos/positivos que el escáner pueda encontrar."
1360
 
1361
  msgid "IntegrityNote"
1362
- msgstr "<b>Nota:</b> No todos los idiomas están soportados por la API de WordPress. Es posible que tenga que usar la versión en Inglés para reducir la cantidad de falsos/positivos arrojados por el escáner durante su ejecución. Como alternativa, puede seleccionar dichos archivos y marcarlos como revisados paraque el escáner los ignore."
1363
 
1364
  msgid "Reason"
1365
  msgstr "Motivo"
@@ -1371,7 +1402,7 @@ msgid "FalsePositivesUnignore"
1371
  msgstr "No Ignorar Estos Archivos"
1372
 
1373
  msgid "FalsePositivesInfo"
1374
- msgstr "El escáner de archivos no lee el contenido de estos sino que compara el Checksum para saber si han sido modificados. Un falso/positivo ocurre cuando la modificación no hace parte de una inyección de código malicioso, estas modificaciones pueden ser consideradas inofencivas. Los archivos en esta lista han sido marcados como falsos/positivos y serán ignorados durante los próximos escaneos del sistema."
1375
 
1376
  msgid "IgnoreFiles"
1377
  msgstr "Ignorar Archivos Durante Los Escaneos"
@@ -1380,34 +1411,34 @@ msgid "IgnoreFilesSingle"
1380
  msgstr "Ignorar Un Solo Archivo"
1381
 
1382
  msgid "IgnoreFilesInfo"
1383
- msgstr "Utilice esta herramienta para seleccionar directorios que contienen muchos archivos o archivos que son muy pesados para ser procesados por el escáner de seguridad. Esto usualmente incluye directorios con imágenes, archivos multimedia y en general cualquier archivo que no tenga código. Ignorar estos archivos mejorará el rendimiento del plugin y mantendrá el consumo de memoria a niveles mínimos."
1384
 
1385
  msgid "SecretKeys"
1386
  msgstr "Llaves de Seguridad"
1387
 
1388
  msgid "SecretKeysUpdated"
1389
- msgstr "Las llaves de seguridad han sido cambiadas (abajo puede encontrar un resumen de la operación)."
1390
 
1391
  msgid "SecretKeysGenerate"
1392
  msgstr "Generar Nuevas Llaves de Seguridad"
1393
 
1394
  msgid "SecretKeysExpiration"
1395
- msgstr "Su sesión de usuario expirará inmediatamente cuando las nuevas llaves de seguridad sean generadas."
1396
 
1397
  msgid "SecretKeysInfo"
1398
- msgstr "Last llaves secretas o de seguridad son una lista de constantes aleatorias agregadas a su sitio web para mejorar el proceso de encriptación de las cookies para cada usuario. Las llaves hacen que su sitio sea más difícil de vulnerar al agregar elementos aleatorios en las contraseñas. Usted no necesita memorizar estas llaves, ellas serán guardadas en el archivo de configuración de WordPress. Usted puede cambiarlas en cualquier momento para invalidar sesiones de usuario existentes, forzando a todos los usuarios a autenticar sus cuentas nuevamente."
1399
 
1400
  msgid "PluginReinstall"
1401
  msgstr "Re-Instalar Plugins"
1402
 
1403
  msgid "PluginReinstallInfo"
1404
- msgstr "En el caso de que usted sospeche que su sitio web está infectado con código maliciosos o incluso después de limpiar su sitio, es una buena idea reinstalar todos los plugins y plantillas incluso aquellos que no están activados para asegurar que el código es el original. Tenga en cuenta que plugins y plantillas premium no puede ser reinstaladas por motivos de compatibilidad con sus licensias."
1405
 
1406
  msgid "PluginReinstallCache"
1407
- msgstr "La información mostrada aquí es guardada en cache por %%SUCURI.ResetPlugin.CacheLifeTime%% segundos, esto es necesario para reducir el número de conexiones HTTP y subsecuentemente el consumo de ancho de banda de su servidor. Actualmente no existe una opción para limpiar esta cache, usted debe esperar a que el plugin la regenere automáticamente."
1408
 
1409
  msgid "PluginReinstallWarning"
1410
- msgstr "<b>ADVERTENCIA!</b> La reinstalación de uno o más plugin puede ocacionar daños irreversibles a su sitio web, proceda con cuidado y asegúrese de mantener una copia de seguridad actualizada del sitio a la mano. Esta herramienta no tendrá ningún efecto sobre la base de datos."
1411
 
1412
  msgid "Roles"
1413
  msgstr "Privilegios"
@@ -1419,10 +1450,10 @@ msgid "PasswordChange"
1419
  msgstr "Cambiar la Contraseña de Usuario"
1420
 
1421
  msgid "PasswordChangeInfo"
1422
- msgstr "Usted puede generar una nueva contraseña aleatoria para las cuentas de usuario que seleccione de la lista. Un correo será enviado a cada usuario. Si usted decide cambiar su propia contraseña, su sesión de usuario expirará inmediatamente. Necesitará autenticar su cuenta nuevamente con la nueva contraseña que recibirá en su correo electrónico."
1423
 
1424
  msgid "PasswordChangeAlert"
1425
- msgstr "WordPress ha generado una nueva contraseña de forma aleatoria para su cuenta de usuario <b>%%SUCURI.ResetPassword.UserName%%</b> en este sitio web <a target=\"_blank\" href=\"http://%%SUCURI.ResetPassword.Website%%\">%%SUCURI.ResetPassword.Website%%</a>. El cambio ha sido solicitado por uno de los administradores del sitio por motivos de seguridad. Su nueva contraseña es &mdash; <span style=\"font-family:Menlo, Monaco, monospace, serif;font-weight:700\">%%%SUCURI.ResetPassword.Password%%%</span> &mdash; por favor cámbiela lo antes posible."
1426
 
1427
  msgid "Update"
1428
  msgstr "Actualización"
@@ -1434,40 +1465,49 @@ msgid "AvailableUpdates"
1434
  msgstr "Actualizaciones Disponibles"
1435
 
1436
  msgid "AvailableUpdatesInfo"
1437
- msgstr "WordPress tiene una acogida muy grande en Internet, esto atrae la atención de personas maliciosas para encontrar vulnerabilidades en el código al igual que en el código de plugins y plantillas que otras empreas desarrollan. Es recomendable mantener plugins y plantillas actualizadas para prevenir ataques tan pronto como vulnerabilidades sean descubiertas."
1438
 
1439
  msgid "WhitelistScript"
1440
  msgstr "Desbloquear Archivos PHP"
1441
 
1442
  msgid "WhitelistScriptInfo"
1443
- msgstr "Después de aplicar el hardening en los directorios soportados por el plugin, un archivo .htaccess será creado con reglas para bloquear el acceso directo a todos los archivos PHP contenidos en dichos directorios, esta es una buena precaución para evitar la ejecución de código malicioso; con algunas excepciones el archivo <em>\"index.php\"</em> es el único que debería tener acceso público, sin embargo muchos plugins y plantillas requieren de este acceso también, utilice esta herramienta para desbloquearlos."
1444
 
1445
  msgid "Uninstall"
1446
  msgstr "Eliminar Registros de Seguridad, Hardening y Configuraciones"
1447
 
1448
  msgid "UninstallInfo"
1449
- msgstr "Esta acción iniciará el proceso de desactivación / desinstalación del plugin. Todos los registro de seguridad guardados en el disco local, las reglas de hardening y las configuraciones serán eliminadas. Tenga en cuenta que los registros de seguridad guardados en el servidor de Sucuri no serán eliminados, esto es para prevenir que usuarios maliciosos intenten borrar sus huellas después de ejecutar un ataque en contra del sitio web."
1450
 
1451
  msgid "ImportExport"
1452
  msgstr "Importar Y Exportar Ajustes"
1453
 
1454
  msgid "ImportExportInfo"
1455
- msgstr "Copie la información codificada en JSON que aparece en la caja de abajo, pague esta información en la misma caja en el sitio web donde desea importar esta configuración. Tenga en cuenta que algunas opciones serán omitidas ya que estas contienen información irrelevante para otros sitios. Para importar la configuración de otro sitio web a este, reemplace el contenido de la caja con los datos codificados en JSON de otro sitio, luego presione el boton para continuar. Tenga en cuenta que algunas opciones no serán importadas para reducir el riesgo de insertar datos arbitrarios en el disco."
1456
 
1457
  msgid "DataStorage"
1458
  msgstr "Almacenamiento de Datos"
1459
 
1460
  msgid "DataStorageInfo"
1461
- msgstr "Este es el directorio donde el plugin guardará los registros de seguridad, el archivo con las configuraciones, la cache y datos adicionales de otras herramientas. El plugin require de permisos de escritura en este directorio así como en los archivos contenidos allí. Si usted prefiere mantener estos archivos en un directorio diferente al especificado, por favor defina una constante llamada <em>\"SUCURI_DATA_STORAGE\"</em> en el archivo de configuración de WordPress con la ruta absoluta del nuevo directorio."
 
 
 
 
 
 
 
 
 
1462
 
1463
- msgid "LogsReport"
1464
- msgstr "Estadísticas De Seguridad"
1465
 
1466
- msgid "LogsReportLimit"
1467
- msgstr "El número máximo de registros que serán usados para la generación de gráficas con estadísticas de seguridad ha sido cambiado"
1468
 
1469
- msgid "LogsReportInfo"
1470
- msgstr "Los datos usados para generar estas estadísticas son los últimos <b>%%SUCURI.AuditReport.Logs4Report%% eventos</b> en el registro de seguridad, usted puede configurar este número desde la página de ajustes."
1471
 
1472
- msgid "LogsReportDescription"
1473
- msgstr "Activar esta opción le permite visualizar estadísticas de los eventos ejecutados en su sitio web incluyendo la actividad de los usuarios y posibles ataques dirigidos a su sitio web. Por defecto, el plugin utiliza los últimos registros de seguridad para generar las gráficas, el número de registros seleccionados es limitado para reducir el consumo de memoria por parte del analizador de datos. Usted puede incrementar este número bajo su propio riesgo considerando la cantidad de recursos disponibles en su servidor y el tiempo de ejecución máxima de archivos PHP configurado por su proveedor de hosting."
10
  "PO-Revision-Date: \n"
11
  "POT-Creation-Date: 2017-06-01 09:00-0700\n"
12
  "Project-Id-Version: Sucuri Scanner\n"
13
+ "X-Generator: Poedit 1.8.12\n"
14
 
15
  msgid "Review"
16
+ msgstr "Revisión"
17
 
18
  msgid "Dashboard"
19
  msgstr "Inicio"
30
  msgid "AuditLogs"
31
  msgstr "Registros"
32
 
 
 
 
33
  msgid "ClearCache"
34
  msgstr "Limpiar Cache"
35
 
36
+ msgid "IPAccess"
37
+ msgstr "Acceso Por IP"
38
+
39
  msgid "GenerateAPIKey"
40
  msgstr "Generar Llave"
41
 
49
  msgstr "Accesso denegado por Sucuri Inc."
50
 
51
  msgid "NonceFailure"
52
+ msgstr "Error al verificar el código Nonce del formulario, verifica los datos e inténtalo de nuevo."
53
 
54
  msgid "NewsletterInvitation"
55
+ msgstr "¿Te gustaría recibir información sobre vulnerabilidades descubiertas? Subscríbete a nuestro newsletter <a href=\"http://sucuri.hs-sites.com/subscribe-to-security\" target=\"_blank\" rel=\"noopener\">aquí</a>"
56
 
57
  msgid "EnableAPIServiceAgain"
58
+ msgstr "La comunicación con la API de Sucuri está deshabilitada, si acabas de actualizar el plugin esta podría ser una buena oportunidad para probar esta herramienta una vez más con el nuevo código. Habilite la comunicación con la API desde la página de ajustes."
59
 
60
  msgid "Save"
61
  msgstr "Guardar"
70
  msgstr "Error desconocido, no hay más información."
71
 
72
  msgid "ErrorLogFileNotFound"
73
+ msgstr "; esto generalmente sucede cuando una llave inválida es agregada al plugin, la llave será eliminada automáticamente para reducir la cantidad de errores, si quieres recuperarla, utiliza el botón de recuperación en la página de ajustes, y recibirás un correo con las instrucciones de activación: %1$s"
74
 
75
  msgid "ErrorWrongAPIKey"
76
  msgstr "; la llave del Firewall es inválida: %1$s"
77
 
78
  msgid "ErrorSSLCertificate"
79
+ msgstr ". Tu sitio web parece estar usando una versión desactualizada de la librería OpenSSL o el módulo de CURL ha sido compilado sin soporte para el algoritmo usado para establecer un enlace de comunicación segura con la API. Contácta a tu proveedor de hosting para solucionar el problema."
80
 
81
  msgid "ErrorInvalidEmail"
82
  msgstr "El correo electrónico tiene un formato inválido o el dominio asociado no tiene asociado un servidor MX."
184
  msgstr "La herramienta para exportar los registros de seguridad ha sido desactivada"
185
 
186
  msgid "SelfHostingInfo"
187
+ msgstr "Esta opción te permite guardar una copia de los registros de seguridad en un archivo ubicado en tu servidor que puede ser leído por un SIEM o cualquier otro sistema de análisis (le recomendamos OSSEC). Esto te dará visibilidad de lo que sucede en tu sitio web para complementar tu infraestructura de monitoreo. <b>NOTA:</b> No use archivos que sean accesibles de forma pública, use un archivo que esté por lo menos un nivel arriva de la raíz del sitio web para evitar fugas de información."
188
 
189
  msgid "SelfHostingFallback"
190
+ msgstr "No tienes una llave para comunicarte con la API. Sin embargo, la herramienta para exportar los registros de seguridad está activada, el plugin leerá el contenido de este archivo y mostrará esa información aquí. Ten en cuenta que solo los últimos registros serán procesados para mantener un consumo de memoria bajo. Considera generar una llave para obtener una mayor cobertura en la actividad de tu sitio web."
191
 
192
  msgid "AuditLogsCache"
193
  msgstr "Los registros son guardados por %%SUCURI.AuditLogs.Lifetime%% segundos"
210
  msgid "NoWordPressFile"
211
  msgstr "El archivo no hace parte de la instalación oficial de WordPress."
212
 
213
+ msgid "ThereAreNoDifferences"
214
+ msgstr "No existen diferencias entre el archivo instalado y el original"
215
 
216
  msgid "ScheduledTask"
217
  msgstr "%1$s (cada %2$d segundos)"
304
  msgstr "Cambio de Contraseña"
305
 
306
  msgid "FailedLoginFooter"
307
+ msgstr "<br><br><em>Explicación: Alguien intentó ingresar al sistema de administración de tu sitio web. Si estás recibiendo muchas de estas alertas, es posible que alguien esté utilizando un ataque de fuerza bruta para vulnerar tu sitio [1]. Puedes desactivar estas alertas desde aquí [2]. También puedes considerar la instalación de un Firewall para filtrar el tráfico malicioso y ataques como este [3].</em><br><br>[1] <a href='https://kb.sucuri.net/definitions/attacks/brute-force/password-guessing'>https://kb.sucuri.net/definitions/attacks/brute-force/password-guessing</a><br>[2] <a href='%1$s'>%2$s</a> <br>[3] <a href='https://sucuri.net/es/firewall-de-sitios-web/?wpalert'>https://sucuri.net/es/firewall-de-sitios-web/</a><br>"
308
 
309
  msgid "FirewallAPIKeySet"
310
  msgstr "La llave del Firewall ha sido guardada"
334
  msgstr "Desactivada (use con precaución)"
335
 
336
  msgid "FirewallNotEnabled"
337
+ msgstr "El Firewall no ha sido activado en tu sitio o la llave de autenticación es inválida."
338
 
339
  msgid "FirewallClearCacheFailure"
340
+ msgstr "No se pudo actualizar la cache de tu sitio, inténtalo más tarde."
341
 
342
  msgid "Active"
343
  msgstr "activo"
430
  msgstr "Fecha/Hora"
431
 
432
  msgid "ConfirmOperation"
433
+ msgstr "Debes confirmar que entiendes el riesgo de esta operación."
434
 
435
  msgid "UnderstandTheRisk"
436
  msgstr "Entiendo que esta operación no puede ser revertida."
454
  msgstr "Solo <b>%1$d</b> de <b>%2$d</b> archivos fueron procesados."
455
 
456
  msgid "ErrorIntegrityAdded"
457
+ msgstr "El plugin no tiene permiso para eliminar este archivo porque fué creado por otro usuario del sistema con más privilegios que tu cuenta. Conéctate a tu sitio a través de FTP para eliminarlo."
458
 
459
  msgid "ErrorIntegrityModified"
460
+ msgstr "El plugin no tiene permiso para restablecer el contenido de este archivo porque fué modificado por otro usuario del sistema con más privilegios que tu cuenta. Conéctate a tu sitio a través de FTP para restablecerlo."
461
 
462
  msgid "ErrorIntegrityRemoved"
463
+ msgstr "El plugin no tiene permiso para restablecer el contenido de este archivo porque el directorio donde está ubicado pertenece a otro usuario del sistema con más privilegios que tu cuenta. Conéctate a tu sitio a través de FTP para restablecerlo."
464
 
465
  msgid "SecurityAlerts"
466
  msgstr "Alertas de Seguridad"
467
 
468
+ msgid "NoAlertsError"
469
+ msgstr "Usted ha instalado un plugin o plantilla que no es completamente compatible con nuestro plugin, algunas de las alertas de seguridad (como las autenticaciones exitosas y fallidas de usuario) no serán enviadas. Para prevenir un ciclo infinito mientras el plugin detecta cambios en el sitio y envía las alertas de seguridad a través de un plugin de SMTP personalizado, hemos decidido detener cualquier intento de enviar los correos para prevenir errores fatales."
470
+
471
  msgid "AlertSettingsUpdated"
472
  msgstr "La configuración para las alertas de seguridad ha sido actualizada"
473
 
475
  msgstr "Recibir alertas por cambios en la configuración del plugin de Sucuri"
476
 
477
  msgid "OptionPrettifyMails"
478
+ msgstr "Recibir alertas en HTML <em>(podrías experimentar problemas con tu servicio de correo electrónico)</em>"
479
 
480
  msgid "OptionUseWordPressMail"
481
+ msgstr "Usar funciones nativas de WordPress para enviar las alertas <em>(deselecciona para usar funciones nativas de PHP)</em>"
482
 
483
  msgid "OptionLastLoginRedirection"
484
+ msgstr "Permitir redirección durante el login para reportar información acerca de la última autenticación exitosa de tu cuenta de usuario"
485
 
486
  msgid "OptionNotifyScanChecksums"
487
  msgstr "Recibir alertas por diferencias en los archivos originales de WordPress"
496
  msgstr "Recibir alertas por autenticaciones exitosas de usuario"
497
 
498
  msgid "OptionNotifyFailedLogin"
499
+ msgstr "Recibir alertas por autenticaciones de usuario fallidas <em>(si tu sitio está siendo atacado recibirás multiples alertas por segundo, deselecciona para reducir el Spam)</em>"
500
+
501
+ msgid "OptionNotifyFailedPassword"
502
+ msgstr "Recibir alertas por autenticaciones de usuario fallidas incluyendo la contraseña enviada"
503
 
504
  msgid "OptionNotifyBruteforceAttack"
505
  msgstr "Recibir un resumen con todos los intentos de autenticación de usuario fallidos durante la misma hora. El reporte será eliminado del servidor una vez la información sea enviada a su correo"
506
 
507
  msgid "OptionNotifyPostPublication"
508
+ msgstr "Recibir alertas por cambios en el estado de las publicaciones y páginas <em>(puedes configurar qué alertas serán monitoreadas desde el panel \"Ignorar Cambios en Publicaciones\")</em>"
509
 
510
  msgid "OptionNotifyWebsiteUpdated"
511
+ msgstr "Recibir alertas cuando tu sitio web sea actualizado"
512
 
513
  msgid "OptionNotifySettingsUpdated"
514
+ msgstr "Recibir alertas por cambios en la configuración general de tu sitio web"
515
 
516
  msgid "OptionNotifyThemeEditor"
517
  msgstr "Recibir alertas cuando un archivo sea modificado a través del editor de Plugins/Plantillas"
532
  msgstr "Recibir alertas cuando un <b>plugin sea eliminado</b>"
533
 
534
  msgid "OptionNotifyWidgetAdded"
535
+ msgstr "Recibir alertas cuando un <b>widget sea agregado</b> a tu sitio web"
536
 
537
  msgid "OptionNotifyWidgetDeleted"
538
+ msgstr "Recibir alertas cuando un <b>widget sea eliminado</b> de tu sitio web"
539
 
540
  msgid "OptionNotifyThemeInstalled"
541
  msgstr "Recibir alertas cuando una <b>plantilla sea instalada</b>"
574
  msgstr "Máximo 160 por hora"
575
 
576
  msgid "BruteForceAlertSuccess"
577
+ msgstr "El plugin asumirá que tu sitio web está siendo atacado después de %1$s autenticaciones de usuario fallidas durante la misma hora"
578
 
579
  msgid "BruteForceAlertFailure"
580
  msgstr "Ese número no está soportado por el plugin, use uno de la lista"
607
  msgstr "Herramienta de Integridad de Archivos"
608
 
609
  msgid "DiffUtilityDescription"
610
+ msgstr "Si tu proveedor de hosting permite la ejecución de comandos del sistema a través de PHP, puedes configurar el plugin para usar el comando <a href=\"https://en.wikipedia.org/wiki/Diff_utility\" target=\"_blank\" rel=\"noopener\">Diff de UNIX</a> para comparar el contenido actual de tus archivos con los archivos originales de WordPress. Esta herramienta te permitirá ver las diferencias entre ambos repositorios y actuar dependiendo de la información encontrada."
611
 
612
  msgid "DiffUtilityInfo"
613
+ msgstr "El comando diff de Unix está activado. Puedes hacer clic en los archivos en la tabla para ver las diferencias detectadas por el escáner. Si consideras que las diferencias no causan daño a tu sitio, puedes marcar el archivo como revisado, de otra forma se te sugiere restaurar el contenido original inmediatamente."
614
 
615
  msgid "DiffUtilityInstructions"
616
+ msgstr "Las lineas con un signo <b>negativo</b> como prefijo <em>(marcadas en rojo)</em> muestran el código original. Las lineas con un signo <b>positivo</b> como prefijo <em>(marcadas en verde)</em> muestran el código actual. Puedes leer más acerca del formato DIFF en el artículo de WikiPedia <a target=\"_blank\" href=\"https://en.wikipedia.org/wiki/Diff_utility\" rel=\"noopener\">Unix Diff Utility</a>."
617
 
618
  msgid "AccountsWereBlocked"
619
  msgstr "Las cuentas de usuario seleccionadas han sido bloqueadas"
622
  msgstr "Las cuentas de usuario seleccionadas han sido desbloqueadas"
623
 
624
  msgid "LastLoginMessage"
625
+ msgstr "El último acceso de tu cuenta fué en <b>%1$s</b> desde <b>%2$s</b> <em>(%3$s)</em> <a href='%4$s'>ver todos los registros</a>"
626
 
627
  msgid "LastLoginsNotWritable"
628
  msgstr "El archivo para los registros de autenticaciones de usuario no es modificable: <code>%1$s</code>"
637
  msgstr "El soporte para túneles proxy ha sido cambiado a <b>%1$s</b>"
638
 
639
  msgid "ReverseProxyInfo"
640
+ msgstr "El plugin utiliza la dirección IP de cada usuario para registrar los eventos ejecutados, el plugin utiliza dos métodos para obtener esta dirección: el método principal usa una variable global del servidor llamada <em>Remote-Addr</em> disponible en la mayoría de servidores web, un método alternativo usa cabeceras de HTTP personalizadas <em>(que son consideradas inseguras por defecto)</em>. No es necesario que te preocupes por esta opción a menos que tu sitio web esté detrás de un túnel proxy. Servicios como el <a href=\"https://sucuri.net/es/firewall-de-sitios-web/\" target=\"_blank\">Firewall de Sucuri</a> &mdash; una vez activo &mdash; fuerzan el paso del tráfico de red a través de ellos para filtrar amenazas de seguridad que podrían afectar el servidor original. Un efecto secundario del uso de estos servicios es que la dirección IP de los usuarios ya no está disponible entre las variables globales del servidor sino que es enviada a través de una cabecera HTTP personalizada."
641
 
642
  msgid "IPDiscoverer"
643
  msgstr "Detección de Direcciones IP"
644
 
645
  msgid "IPDiscovererInfo"
646
+ msgstr "La detección de direcciones IP hace uso de DNS para detectar si el sitio web está detrás del <a href=\"https://sucuri.net/es/firewall-de-sitios-web/\" target=\"_blank\">Firewall de Sucuri</a> en cuyo caso modificará las variables globales del servidor para configurar la dirección IP real de cada visitante del sitio. Este proceso es ejecutado con cada proceso de WordPress, y es posible que la velocidad de tu sitio sea afectada ya que algunos proveedores de hosting utilizan servidores DNS lentos, lo que hace que esta operación tome más tiempo de lo que se espera."
647
 
648
  msgid "HTTPHeader"
649
  msgstr "Cabecera de HTTP"
742
  msgstr "Estos correos no recibirán más alertas de seguridad: <code>%1$s</code>"
743
 
744
  msgid "TestAlertSent"
745
+ msgstr "Un correo de prueba ha sido enviado a tu dirección, revisa tu bandeja de entrada"
746
 
747
  msgid "InvalidEmail"
748
  msgstr "Formato de correo electrónico inválido."
802
  msgstr "Acciones Automatizadas"
803
 
804
  msgid "CronjobsInfo"
805
+ msgstr "Acciones automatizadas son reglas registradas en tu base de datos por un plugin, plantilla o WordPress; estas reglas son usadas para ejecutar automáticamente acciones definidas en el código con un intervalo de tiempo definido. Un buen uso de estas reglas es la generación de copias de seguridad, la ejecución de escáneres de seguridad o la remoción de elementos innecesarios de la base de datos como borradores de publicaciones. <b>Nota:</b> Las acciones automatizadas pueden ser re-instaladas por cualquier plugin/plantilla automáticamente, considera desactivar el plugin completamente si quieres eliminar una de estas acciones."
806
 
807
  msgid "CronjobRunNow"
808
  msgstr "Ejecutar Ahora (en +10 segundos)"
820
  msgstr "Ninguna acción automatizada ha sido seleccionada de la lista"
821
 
822
  msgid "DNSLookupStatus"
823
+ msgstr "El estado de las conexiones vía DNS para detectar el uso de túneles proxy ha sido cambiado"
824
 
825
  msgid "IncorrectEncoding"
826
  msgstr "Los datos han sido codificados incorrectamente"
832
  msgstr "Llave de Autenticación"
833
 
834
  msgid "APIKeyInfo"
835
+ msgstr "La mayoría de herramientas en este plugin pueden ser usadas sin una configuración específica, pero las herramientas más importantes requieren de una <b>llave de autenticación</b> para establecer un túnel de comunicación segura con los servidores de Sucuri. La llave es generada usando tu correo electrónico y el nombre de dominio de tu sitio web, esto te permitirá tener acceso a la herramienta de monitoreo y opciones extra."
836
 
837
  msgid "APIKeyTerms"
838
+ msgstr "Ten en cuenta que generar una llave implica que estás de acuerdo con enviar la información recolectada por el plugin a los servidores de Sucuri, esto te permite mantener los Tem de seguridad fuera del alcance de usuarios maliciosos que podrían intentar eliminarlos para limpiar sus huellas durante un ataque. Nosotros además usamos esta información de forma anónima para generar <a href=\"https://sucuri.net/security-reports/brute-force/\" target=\"_blank\">estadísticas</a>. Por favor, no generes la llave de autenticación si estás en desacuerdo con esto, puedes seguir usando el plugin sin la llave."
839
+
840
+ msgid "APIKeyMissing"
841
+ msgstr "La llave no existe"
842
 
843
  msgid "APIKeyInvalidDomain"
844
+ msgstr "Tu sitio web <code>%%SUCURI.CleanDomain%%</code> parece no tener un registro de DNS tipo <code>A</code> así que la API lo considerará inválido durante el proceso de generación de la llave. Agrega <code>www</code> al inicio del dominio para intentar solucionar el problema. Envía un mensaje a nuestro servicio de soporte si no entiendes qué significa esto."
845
 
846
  msgid "APIKeyRecoverButton"
847
  msgstr "Recuperar Por Correo Electrónico"
848
 
849
  msgid "APIKeyRecoveryCondition"
850
+ msgstr "Si no tienes acceso al correo electrónico usado para generar la llave pero tienes una copia de la misma a la mano, haz <a target=\"_self\" href=\"%%SUCURI.URL.Settings%%&recover\">clic aquí</a> para activar el plugin manualmente. Ten en cuenta que si la llave es inválida el plugin la eliminará inmediatamente."
851
 
852
  msgid "ApplyHardening"
853
  msgstr "Aplicar Hardening"
859
  msgstr "Firewall Para Aplicaciones Web"
860
 
861
  msgid "HardeningFirewallDescription"
862
+ msgstr "Un WAF (Web Application Firewall) es una capa de protección para tu sitio web que bloquea todo tipo de ataques (fuerza bruta, denegación de servicios, inyecciones a base de datos, etc) y te ayuda a permanecer limpio de código malicioso y fuera de listas negras. Esta opción verifica si tu sitio web está usando el Firewall de Sucuri como tu capa de protección primaria."
863
 
864
  msgid "HardeningFirewallPurchase"
865
+ msgstr "El Firewall de Sucuri es un servicio premium que puedes comprar aquí - <a href='https://goo.gl/qfNkMq' target='_blank'>Sucuri Firewall</a>"
866
 
867
  msgid "HardeningVersionTitle"
868
  msgstr "Verificar la Versión de WordPress"
869
 
870
  msgid "HardeningVersionDescription"
871
+ msgstr "¿Por qué mantener tu sitio web actualizado? WordPress es un proyecto de código libre lo que significa que todos los cambios hechos al código son hechos de forma pública, si alguno de esos cambios hace parte de una solución para un problema de seguridad, cualquier persona puede utilizar esta información para atacar tu sitio web si este aún no ha aplicado el parche de seguridad."
872
 
873
  msgid "HardeningPHPVersionTitle"
874
  msgstr "Verificar la Versión de PHP"
877
  msgstr "PHP %1$s está instalado."
878
 
879
  msgid "HardeningPHPVersionLifetime"
880
+ msgstr "Comunícate con tu proveedor de hosting para instalar una versión actualizada de PHP - <a href='http://php.net/supported-versions.php' target='_blank' rel='noopener'>Lista de Versiones de PHP Soportadas</a>"
881
 
882
  msgid "HardeningGeneratorTitle"
883
  msgstr "Eliminar Versión de WordPress"
884
 
885
  msgid "HardeningGeneratorDescription"
886
+ msgstr "Esta opción verifica si la versión de WordPress usada en tu sitio web está siendo expuesta de forma pública a través del código HTML. Muchos escáneres de vulnerabilidades web utilizan esta información para determinar si tu página web tiene vulnerabilidades para luego ser explotadas. Ten en cuenta que aún sin esta información un escáner inteligente puede detectar la versión de WordPress en uso comparando los Checksums de algunos archivos estáticos distribuidos con cada instalación."
887
 
888
  msgid "HardeningNginxTitle"
889
  msgstr "Bloquear Algunos Archivos PHP"
890
 
891
  msgid "HardeningNginxDescription"
892
+ msgstr "Esta opción bloquea la ejecución de archivos PHP en directorios sensitivos. Se cuidadoso cuando apliques esta opción, ya que algunos plugins y plantillas requieren de acceso público a este directorio para algunas de sus herramientas, por ejemplo, para generar imágenes o guardar información temporalmente. Agrega los archivos que están siendo bloqueados a la lista blanca de archivos PHP."
893
 
894
  msgid "HardeningNginxField"
895
  msgstr "Verificar Hardening"
896
 
897
  msgid "HardeningNginxSuggestion"
898
+ msgstr "Lee las instrucciones oficiales de WordPress para aprender como restringir el acceso a archivos PHP en directorios sensitivos - <a href='https://codex.wordpress.org/Nginx#Global_restrictions_file' target='_blank' rel='noopener'>Restricciones Globales para Nginx y WordPress</a>"
899
 
900
  msgid "HardeningUploadsTitle"
901
  msgstr "Bloquear Archivos PHP en el Directorio de Subidas"
902
 
903
  msgid "HardeningUploadsDescription"
904
+ msgstr "Esta opción bloquea la ejecución de archivos PHP en directorios sensitivos. Se cuidadoso cuando aplique esta opción ya que algunos plugins y plantillas requieren de acceso público a este directorio para algunas de sus herramientas, por ejemplo, para generar imágenes o guardar información temporalmente. Agrega los archivos que están siendo bloqueados a la lista blanca de archivos PHP."
905
 
906
  msgid "HardeningUploadsApplySuccess"
907
  msgstr "Hardening aplicado al directorio de subidas"
919
  msgstr "Bloquear Archivos PHP en el Directorio de Contenido"
920
 
921
  msgid "HardeningContentDescription"
922
+ msgstr "Esta opción bloquea la ejecución de archivos PHP en directorios sensitivos. Se cuidadoso cuando aplique esta opción ya que algunos plugins y plantillas requieren de acceso público a este directorio para algunas de sus herramientas, por ejemplo, para generar imágenes o guardar información temporalmente. Agrega los archivos que están siendo bloqueados a la lista blanca de archivos PHP."
923
 
924
  msgid "HardeningContentApplySuccess"
925
  msgstr "Hardening aplicado al directorio de contenido"
937
  msgstr "Bloquear Archivos PHP en el Directorio de Inclusiones"
938
 
939
  msgid "HardeningIncludesDescription"
940
+ msgstr "Esta opción bloquea la ejecución de archivos PHP en directorios sensitivos. Se cuidadoso cuando aplique esta opción ya que algunos plugins y plantillas requieren de acceso público a este directorio para algunas de sus herramientas, por ejemplo, para generar imágenes o guardar información temporalmente. Agrega los archivos que están siendo bloqueados a la lista blanca de archivos PHP."
941
 
942
  msgid "HardeningIncludesApplySuccess"
943
  msgstr "Hardening aplicado al directory de inclusiones"
955
  msgstr "Exposición de Información"
956
 
957
  msgid "HardeningReadmeDescription"
958
+ msgstr "Esta opción verifica si el archivo README todavía existe. La información en este archivo puede ser usada por personas maliciosas para encontrar vulnerabilidades asociadas con la versión de WordPress que has instalado. Ten en cuenta que este archivo is re-creado cada vez que una actualización es ejecutada."
959
 
960
  msgid "HardeningReadmeApplySuccess"
961
  msgstr "Hardening aplicado sobre el archivo README"
967
  msgstr "Cuenta de Administración Primaria"
968
 
969
  msgid "HardeningAdminUserDescription"
970
+ msgstr "Esta opción verifica si la cuenta de administración primaria está usando un nombre fácil de adivinar como \"admin\". Esto permite a personas maliciosas identificar fácilmente qué cuenta tiene los privilegios más altos entre todos los usuarios registrados."
971
 
972
  msgid "HardeningFileEditorTitle"
973
  msgstr "Editor de Plugins y Plantillas"
982
  msgstr "Hardening revertido en el editor de plugins y plantillas"
983
 
984
  msgid "HardeningFileEditorRevertFailure"
985
+ msgstr "El editor de plugins y plantillas no fue desactivado usando el plugin de Sucuri. Debes escanear tu sitio web por una constante definida como \"DISALLOW_FILE_EDIT\" cuando la encuentres, debes eliminarla o cambiar su valor a \"False\". Ten en cuenta que cualquier otro plugin o plantilla puede desactivar el editor, así que es imposible determinar el origen de la constante."
986
 
987
  msgid "PHPWhitelistSuccess"
988
  msgstr "El archivo ha sido agregado a la lista blanca de archivos PHP"
997
  msgstr "El estado de la herramienta de integridad ha sido cambiado"
998
 
999
  msgid "DiffUtilityMissing"
1000
+ msgstr "Tu proveedor de hosting no permite la ejecución de comandos del sistema a través de archivos PHP."
1001
 
1002
  msgid "IntegrityLanguage"
1003
  msgstr "El idioma para la herramienta de integridad de archivos de WordPress ha sido cambiado"
1042
  msgstr "Sin Lista Negra"
1043
 
1044
  msgid "APIKeyExplanation"
1045
+ msgstr "Una llave de autenticación es necesaria para activar herramientas adicionales disponibles en el plugin. Las llaves son gratuitas y puedes generar un número ilimitado de ellas siempre y cuando el nombre del sitio web y el correo electrónico sean únicos. La llave es usada para autenticar las conexiones a través de HTTP hechas a la API administrada por Sucuri Inc. No generes la llave si estás en desacuerdo con el envío de información a nuestros servidores."
1046
 
1047
  msgid "APIKeyHelp"
1048
+ msgstr "Si experimentas problemas con la generación de la llave, puedes solicitar una enviando la dirección de tu sitio web y el correo electrónico que deseas usar para la asociación a <a href=\"mailto:info@sucuri.net\">info@sucuri.net</a>. Ten en cuenta que generar una llave para un sitio web que no es público en Internet no es posible, ya que la API necesita validar que el nombre del host existe, sin embargo, si deseas probar el plugin en un ambiente de desarrollo, por favor contáctanos para poder generar una llave manualmente."
1049
 
1050
  msgid "APIKeyGenerated"
1051
+ msgstr "¡Felicitaciones! Todas las herramientas disponibles en el plugin han sido habilitadas. Este producto está diseñado para suplementar productos de seguridad existentes en tu sitio web. El plugin no provee una solución completa a tus necesidades de seguridad, pero te ofrece más herramientas para controlar el funcionamiento de tu sitio y tener una mejor postura con respecto a ataques que puedas sufrir en el futuro, todo esto con la intensión de reducir riesgos."
1052
 
1053
  msgid "APIKeyContinueSetup"
1054
+ msgstr "Sucuri Inc. ha generado una llave única para tu sitio web, esta llave fue asociada al correo electrónico que seleccionaste anteriormente, correo que puedes utilizar para recuperar dicha llave si llegaras a perderla en el futuro. Te invitamos a revisar el resto de opciones disponibles en la página de ajustes para que configures el plugin a la medida de tu sitio."
1055
 
1056
  msgid "APIKeyRecoveryExplanation"
1057
+ msgstr "Si esta operación fue exitosa, recibirás un mensaje en el correo electrónico que usaste durante la generación de la llave <em>(usualmente este correo es el mismo asociado a la cuenta de administración primaria)</em>. Este mensaje contiene una copia de la llave, por favor copia y pega la llave en el formulario de abajo. El plugin verificará la autenticidad de la misma, si esta verificación falla, la llave será eliminada automáticamente y deberás iniciar el proceso de recuperación nuevamente."
1058
 
1059
  msgid "APIKeyRecoveryPossibleFailures"
1060
+ msgstr "Existen casos en los que esta operación puede fallar, un ejemplo sería cuando el correo electrónico ya no está asociado al sitio web, esto sucede cuando la base de la URL cambia <em>(de www a nada y viceversa)</em>. Si estás teniendo problemas con el proceso de recuperación de la llave, por favor envía un mensaje explicando la situación a <a href=\"mailto:info@sucuri.net\">info@sucuri.net</a>"
1061
 
1062
  msgid "DNSLookups"
1063
  msgstr "Conexiones DNS"
1066
  msgstr "Activar conexiones DNS al inicio de cada proceso"
1067
 
1068
  msgid "DNSLookupsText"
1069
+ msgstr "Activa esta opción si tu sitio web está detrás de un Firewall, esto garantizará que la dirección IP de tus visitantes será detectada correctamente para los registros de seguridad. Puedes cambiar esto después desde la página de configuraciones del plugin."
1070
 
1071
  msgid "IntegrityTitle"
1072
  msgstr "Integridad de la Instalación"
1081
  msgstr "Todos los Archivos Están Intáctos"
1082
 
1083
  msgid "IntegrityGoodDescription"
1084
+ msgstr "No hemos detectado archivos adicionales, eliminados o cambios relevantes en los archivos originales de WordPress. Si estás experimentando otros problemas, por favor usa un <a target=\"_blank\" href=\"https://sucuri.net/es/seguridad-de-sitios-web/remocion-de-malware\">servicio de limpieza de malware</a>."
1085
 
1086
  msgid "IntegrityBadTitle"
1087
  msgstr "Archivos de WordPress Modificados"
1088
 
1089
  msgid "IntegrityBadDescription"
1090
+ msgstr "Hemos identificado que algunos de los archivos de WordPress han sido modificados. Esto podría indicar un ataque o la existencia de un archivo corrupto en tu instalación. Si estás experimentando otros problemas, por favor usa un <a target=\"_blank\" href=\"https://sucuri.net/es/seguridad-de-sitios-web/remocion-de-malware\">servicio de limpieza de malware</a>."
1091
 
1092
  msgid "MarkFixedDescription"
1093
+ msgstr "Marcar uno o más archivos como revisado forzará al plugin a ignorar dichos archivos durante futuros escaneos, esto es útil cuando un archivo contiene falsos/positivos. Adicionalmente, puedes restaurar el contenido original si estos han sido modificados o eliminados, el plugin descargará una copia del código desde el repositorio oficial de WordPress. La eliminación de archivos es una operación irreversible, ten cuidado."
1094
 
1095
  msgid "Action"
1096
  msgstr "Acción"
1144
  msgstr "Ajustes del Firewall"
1145
 
1146
  msgid "FirewallSettingsInfo"
1147
+ msgstr "Un poderoso Firewall para aplicaciones web y <b>Sistema para la Detección de Intrusiones</b> para cualquier usuario de WordPress y cualquier otra plataforma. Esta página te ayudará a configurar y monitorear tu sitio web a través del <b>Firewall de Sucuri</b>. Una vez activado, nuestro Firewall actuará como un escudo, protegiendo tu sitio de ataques y previniendo infecciones de malware y reinfecciones. El Firewall también bloqueará inyecciones a bases de datos, ataques de fuerza bruta, XSS, RFI, puertas traseras y muchas otras amenazas en contra de tu sitio web."
1148
 
1149
  msgid "FirewallKey"
1150
  msgstr "Llave del Firewall"
1151
 
1152
  msgid "FirewallAddKey"
1153
+ msgstr "Agrega la <a href=\"https://waf.sucuri.net/?settings&panel=api\" target=\"_blank\">llave del Firewall</a> en el formulario para iniciar una conexión con la API."
1154
 
1155
  msgid "FirewallFootNote"
1156
+ msgstr "<em>[1]</em> Más información acerca del <a href=\"https://sucuri.net/es/firewall-de-sitios-web/\" target=\"_blank\">Firewall de Sucuri</a>, herramientas disponibles y precios.<br><em>[2]</em> Instrucciones y videos en la <a href=\"https://kb.sucuri.net/firewall\" target=\"_blank\">Wiki de Sucuri</a>.<br><em>[3]</em> <a href=\"https://login.sucuri.net/signup2/create?CloudProxy\" target=\"_blank\">Registra</a> una cuenta nueva y empieza a proteger tu sitio web."
1157
 
1158
  msgid "FirewallLogsTitle"
1159
  msgstr "Registros de Seguridad del Firewall"
1160
 
1161
  msgid "FirewallLogsInfo"
1162
+ msgstr "El Firewall de Sucuri registra todas las conexiones HTTP involucradas en un ataque y las separa de las conexiones legítimas. Puedes usar esta herramienta para analizar la información de las últimas conexiones y tomar acción. O sea, activando las herramientas avanzadas del IDS <em>(Intrusion Detection System)</em> desde el <a target=\"_blank\" href=\"https://waf.sucuri.net/?settings\">panel de administración del Firewall</a> y/o bloquear las direcciones IP y URL directamente desde la <a href=\"https://waf.sucuri.net/?audit\" target=\"_blank\">página de registros de seguridad del Firewall</a>."
1163
 
1164
  msgid "FirewallLogsNote"
1165
+ msgstr "Las conexiones que no fueron bloqueadas son omitidas de la lista, esto es intencional."
1166
+
1167
+ msgid "FirewallIPAccessTitle"
1168
+ msgstr "Dirección IP (Acceso)"
1169
+
1170
+ msgid "FirewallIPAccessInfo"
1171
+ msgstr "Esta herramienta le permite bloquear y desbloquear el acceso a su sitio web de una o mas direcciones IP. Además, puede bloquear direcciones IP automáticamente cuando estas están involucradas en un ataque de fuerza bruta para adivinar la contraseña de uno o más usuarios registrados. Si un usuario legítimo es bloqueado después de enviar las credenciales incorrectas de su cuenta más de tres veces, ellos deberán ingresar al panel de control del Firewall para eliminar su dirección IP de la lista negra, o intentar acceder al sitio a través de una VPN."
1172
+
1173
+ msgid "WhitelistIP"
1174
+ msgstr "Desbloquear Dirección IP"
1175
+
1176
+ msgid "BlacklistIP"
1177
+ msgstr "Bloquear Dirección IP"
1178
 
1179
  msgid "FirewallCacheTitle"
1180
+ msgstr "Caché del Firewall"
1181
 
1182
  msgid "FirewallCacheButton"
1183
+ msgstr "Limpiar Caché"
1184
 
1185
  msgid "FirewallCacheInfo"
1186
+ msgstr "El Firewall ofrece multiples opciones para configurar el nivel de caché aplicado a tu sitio web. Puedes considerar activar la cobertura total de la caché <em>(que es lo recomendado)</em>, o puedes configurar la caché a un nivel mínimo, o forzar el uso de las cabeceras HTTP <em>(solo para usuarios avanzados)</em>, o en casos extremos donde no necesitas la caché, puedes desactivarla completamente. Puedes encontrar más información acerca de estas opciones <a target=\"_blank\" href=\"https://kb.sucuri.net/firewall/Performance/caching-options\">aquí</a>."
1187
 
1188
  msgid "FirewallCacheNote"
1189
+ msgstr "Tenga en cuenta que el Firewall tiene unas <a href=\"https://kb.sucuri.net/firewall/Performance/cache-exceptions\" target=\"_blank\">reglas especiales para la caché</a> de imágenes, archivos CSS, archivos PDF, archivos de texto, código JavaScript, archivos audio visuales y algunas otros formatos de archivo que son guardados en nuestros <a href=\"https://en.wikipedia.org/wiki/Edge_device\" target=\"_blank\" rel=\"noopener\">Edge Devices</a>. La única forma de limpiar la caché de estos archivos es haciendo uso de parámetros aleatorios en la URL, puede agregar un parametro como este <code>?ver=1.2.3</code> e incrementar el número con cada actualización."
1190
 
1191
  msgid "FirewallCacheWiki"
1192
+ msgstr "La caché web es una tecnología para el almacenamiento temporal (caching) de documentos web, como páginas en HTML e imágenes, para reducir el uso de ancho de banda, la carga del servidor, y retrasos en las descargas. Un sistema de caché web guarda copias de los documentos que pasan a través de él; conexiones subsecuentes pueden devolver el contenido desde la caché si las condiciones lo permiten. &mdash; <a href=\"https://en.wikipedia.org/wiki/Web_cache\" target=\"_blank\" rel=\"noopener\">WikiPedia - Web Cache</a>"
1193
+
1194
+ msgid "FirewallAutoClearCache"
1195
+ msgstr "Limpiar cache automáticamente cuando una publicación o página sea modificada"
1196
 
1197
  msgid "LoginsAdmins"
1198
  msgstr "Autenticaciones Exitosas (admins)"
1225
  msgstr "Todo intento de autenticación que haga uso de las funciones nativas de WordPress será interceptado y analizado por el plugin, si el nombre de usuario coincide con alguno en esta lista la conexión al servidor será inmediatamente detenida. Estos intentos no serán registrados y ninguna alerta de seguridad será enviada."
1226
 
1227
  msgid "BlockedUsersNote"
1228
+ msgstr "Ten en cuenta que esta herramienta no intenta proveer una protección completa para bloquear autenticaciones indeseadas de usuarios maliciosos. Dependiendo de la configuración de tu sitio web, los plugins o plantillas que sean instalados, o inclusive la versión de WordPress que estés usando, habrán huecos en el sistema que usuarios maliciosos pueden utilizar para evadir estos bloqueos e iniciar un ataque por fuerza bruta. <a target=\"_blank\" href=\"https://sucuri.net/es/firewall-de-sitios-web/?wp=bu\">Instala un Firewall</a> para obtener protección completa y mitigar este y otros ataques en contra tu sitio web."
1229
 
1230
  msgid "BlockedUsersByIP"
1231
+ msgstr "El bloqueo de usuarios por dirección IP es una opción disponible en el <a href=\"https://sucuri.net/es/firewall-de-sitios-web/\" target=\"_blank\">Firewall de Sucuri</a>; para evitar la duplicación de código y reducir la cantidad de falsos/positivos esta opción nunca será implementada en este plugin."
1232
 
1233
  msgid "FailedLogins"
1234
  msgstr "Autenticaciones Fallidas"
1235
 
1236
  msgid "FailedLoginsInfo"
1237
+ msgstr "Esta información será usada para determinar si tu sitio es víctima de un <a href=\"https://kb.sucuri.net/definitions/attacks/brute-force/password-guessing\" target=\"_blank\">Password Guessing Brute Force Attacks</a>. Estos registros serán acumulados, si más de <code>%%SUCURI.FailedLogins.MaxFailedLogins%%</code> autenticaciones fallidas son registradas durante la misma hora, el plugin enviará un correo electrónico con un resumen del ataque <em>(debe activar esta opción desde la página de ajustes, sección alertas)</em>. <b>NOTA:</b> Algunos plugins que ofrecen la opción de <em>\"Autenticación por Dos-Pasos\"</em> no usan las funciones nativas de WordPress, motivo por el cual algunos intentos de autenticación no podrán ser interceptados ni analizados."
1238
 
1239
  msgid "LoggedInUsers"
1240
  msgstr "Usuarios Activos"
1241
 
1242
  msgid "LoggedInUsersInfo"
1243
+ msgstr "Aquí puedes encontrar una lista de usuarios que han iniciado una sesión en los últimos minutos."
1244
 
1245
  msgid "Recomendations"
1246
  msgstr "Recomendaciones"
1247
 
1248
  msgid "SiteCheckNoResults"
1249
+ msgstr "Si nuestro escáner gratuito no ha detectado ningún problema, es posible que tu sitio tenga un problema más complicado y la infección esté escondida. Puede <a target=\"_blank\" href=\"https://sucuri.net/es/plataforma-de-seguridad-de-sitios-web/signup\">registrar una cuenta con Sucuri</a> para obtener un escaneo más detallado y eventualmente una limpieza absoluta de tu sitio web (no incluido con el plan gratuito)."
1250
+
1251
+ msgid "SiteCheckTarget"
1252
+ msgstr "URL Para el Escáner de Malware"
1253
+
1254
+ msgid "SiteCheckTargetInfo"
1255
+ msgstr "El escáner remoto de malware funciona gracias a <a href=\"https://sitecheck.sucuri.net/\" target=\"_blank\">Sucuri SiteCheck</a>, un servicio que toma la dirección de un sitio web con acceso público y la escanea en busca de código malicioso. Si su sitio web no es visible a través de Internet, por ejemplo, si el sitio está en un ambiente de desarrollo local or una red restringida, el escáner no podrá trabajar en él. Adicionalmente, si el sitio web fué instalado en un directorio diferente al sugerido el escáner reportará un error \"404 Not Found\". Puedes usar esta opción para cambiar la dirección del sitio web que será escaneado."
1256
 
1257
  msgid "PasswordAttack"
1258
  msgstr "Ataque De Fuerza Bruta En Contra De Contraseñas"
1261
  msgstr "Considerar Ataque Después De"
1262
 
1263
  msgid "PasswordAttackInfo"
1264
+ msgstr "Los <a href=\"https://kb.sucuri.net/definitions/attacks/brute-force/password-guessing\" target=\"_blank\">ataques de fuerza bruta en contra de contraseñas</a> son muy comunes en sitios web y páneles de administración. Estos son uno de los vectores más comunes usado para comprometer sitios web. El proceso es muy simple, los atacantes básicamente intentan múltiple combinaciones de usuario y contraseña hasta que encuentran una que funciona. Una vez el acceso al sitio es obtenido, ellos inyectan código malicioso para generar spam, crear páginas fraudulentas, etc."
1265
 
1266
  msgid "PostTypeAlerts"
1267
  msgstr "Alerts Para Diferentes Tipos de Publicaciones"
1273
  msgstr "Tipo de Publicación"
1274
 
1275
  msgid "PostTypeAlertsDisabled"
1276
+ msgstr "Desactivaste las alertas de seguridad, cuando una publicación es creada o modificada, esta herramienta espera que esa opción esté activa para poder filtrar los tipos de publicaciones que no son relevantes para el administrador del sitio."
1277
 
1278
  msgid "PostTypeAlertsInfo"
1279
+ msgstr "Esta es una lista de <a href=\"https://codex.wordpress.org/Post_Types\" target=\"_blank\" rel=\"noopener\">tipos de publicaciones</a> registradas. Recibirás alertas de seguridad cuando una página o publicación sea creada o modificada. Algunos de estos tipos son nativos de WordPress pero la mayoría son creados por plugins y plantillas que tengas instalados. Si no quieres recibir alertas por cambios en uno o más de estos tipos, puedes usar este panel para desactivarlas."
1280
 
1281
  msgid "PostTypeAlertsInvisible"
1282
+ msgstr "Si estás recibiendo alertas por cambios en tipos de publicaciones que no aparecen en la lista, es posible que estas hayan sido creadas dinámicamente por un plugin o plantilla sin usar las funciones nativas de WordPress. Si conoce el identificador único del tipo de publicación, puedes ingresarlo en el formulario y el plugin de Sucuri hará lo mejor posible para ignorar estas alertas."
1283
 
1284
  msgid "PostTypeAlertsStop"
1285
  msgstr "Ignorar Cambios En Este Tipo De Publicaciones"
1291
  msgstr "Número Máximo De Alertas Por Hora"
1292
 
1293
  msgid "AlertsPerHourInfo"
1294
+ msgstr "Utiliza esta opción para configurar el número máximo de alertas de seguridad por hora. Si el número es excedido y el plugin detecta más eventos durante la misma hora, estos serán agregados al registro de seguridad pero no serán enviados por correo electrónico. Ten cuidado con esta opción, ya que puedes perder información importante."
1295
 
1296
  msgid "TestAlerts"
1297
  msgstr "Probar Alertas"
1300
  msgstr "Quién Recibirá Alertas"
1301
 
1302
  msgid "AlertsRecipientInfo"
1303
+ msgstr "Por defecto, el plugin enviará las alertas de seguridad a la cuenta de administración primaria, la misma cuenta que fue creada durante el proceso de instalación de WordPress en tu servidor web. Puedes agregar más direcciones de correo a la lista, ellos recibirán una copia de las mismas alertas de seguridad."
1304
 
1305
  msgid "CustomFormat"
1306
  msgstr "Formato Personalizado"
1309
  msgstr "Asunto de la Alerta"
1310
 
1311
  msgid "AlertsSubjectInfo"
1312
+ msgstr "El formato para el asunto de las alertas de seguridad, por defecto las alertas incluirán el nombre del sitio web y el identificador del evento, puedes usar este panel para agregar la dirección IP del usuario o cualquier otra información adicional. También puedes crear filtros en tu cliente de correo electrónico, agregando etiquetas personalizadas en el formulario."
1313
 
1314
  msgid "TrustedIPs"
1315
  msgstr "Direcciones IP Seguras"
1321
  msgstr "Dirección Agregada en"
1322
 
1323
  msgid "TrustedIPsInfo"
1324
+ msgstr "Si estás trabajando en una red de área local, puedes querer incluir las direcciones IP de todos los nodos de la red en esta lista, esto hará que el plugin ignore todos los eventos originados desde estas direcciones para reducir la cantidad de falsos/positivos. Puede usar el formato CIDR <em>(Classless Inter Domain Routing)</em> para especificar un rango de direcciones IP <em>(solo 8, 16, y 24)</em>."
1325
 
1326
  msgid "APIViaProxy"
1327
  msgstr "API a Través de un Proxy"
1328
 
1329
  msgid "APIViaProxyInfo"
1330
+ msgstr "Todas las conexiones a través de HTTP usadas para comunicarse con la API utilizan las funciones nativas de WordPress, esto significa que puedes usar el mismo mecanismo sugerido por WordPress para establecer estas conexiones a través de un proxy. De acuerdo a la <a href=\"https://developer.wordpress.org/reference/classes/wp_http_proxy/\" target=\"_blank\" rel=\"noopener\">documentación oficial</a>, debes agregar estas constantes en el archivo de configuración: <em>WP_PROXY_HOST, WP_PROXY_PORT, WP_PROXY_USERNAME, WP_PROXY_PASSWORD</em>."
1331
 
1332
  msgid "ProxyHostname"
1333
  msgstr "Dirección del Servidor Proxy"
1345
  msgstr "Conexión con la API"
1346
 
1347
  msgid "APICommunicationInfo"
1348
+ msgstr "Una vez la llave para la API haya sido generada, el plugin establecerá una comunicación con un servicio remoto que actuará como una caja fuerte para almacenar los registros de seguridad generados cuando algo sospechoso suceda en tu sitio web. Si el sitio es comprometido, el hacker no podrá eliminar los registros de seguridad para encubrir sus huellas, de esta forma podrás investigar el ataque y prevenir futuros problemas."
1349
 
1350
  msgid "APICommunicationDisabled"
1351
+ msgstr "Desactivar la comunicación entre el plugin y la API detendrá el monitor de eventos de seguridad. Considera activar el exportador de registros desde la página general de ajustes para mantener el monitor de eventos funcionando sin enviar datos a la API, de lo contrario, un usuario malicioso podrá ejecutar acciones sin que un administrador se de cuenta de lo que está sucediendo."
1352
 
1353
  msgid "APITimeout"
1354
  msgstr "Tiempo de Espera para la API"
1360
  msgstr "Esperar <b>%%SUCURI.RequestTimeout%%</b> antes de terminar la conexión"
1361
 
1362
  msgid "APITimeoutInfo"
1363
+ msgstr "El plugin envía a la API información asociada a los eventos generados por WordPress que sean considerados sospechosos. El envío de estos datos se hace a través de HTTP usando uno de los protocolos de comunicación disponibles en el sistema y <a target=\"_blank\" href=\"https://developer.wordpress.org/reference/functions/wp_remote_post/\" rel=\"noopener\">funciones nativas de WordPress</a>. Si la conexión o el servicio remoto excede la cantidad de segundos configurados en esta opción, la operación es cancelada. Si experimentas problemas de conexión, por favor comunícate con tu proveedor de hosting para investigar los bloqueos."
1364
 
1365
  msgid "HTAccessTitle"
1366
  msgstr "Integridad del Archivo .htaccess"
1375
  msgstr "El sitio web no tiene un archivo <code>.htaccess</code> o no se encuentra en la ubicación esperada."
1376
 
1377
  msgid "HTAccessStandard"
1378
+ msgstr "El archivo <code>.htaccess</code> principal contiene las reglas estándares de WordPress generadas durante la instalación del sitio web. Puedes modificar estas reglas para aumentar el rendimiento del servidor o para generar redirecciones a otras páginas. Para obtener más información al respecto visita la página oficial con la documentación en <a target=\"_blank\" rel=\"noopener\" href=\"https://codex.wordpress.org/Using_Permalinks#Creating_and_editing_.28.htaccess.29\"> Codex WordPress - Creating and editing (.htaccess)</a>"
1379
 
1380
  msgid "ScannerDescription"
1381
+ msgstr "El plugin escanea tu sitio web en busca de cambios que son eventualmente reportados a la API y visualizados a través de los registros de seguridad. Este escáner es ejecutado automáticamente cada día, pero puedes cambiar la frecuencia dependiendo de tus necesidades. Ten en cuenta que si tu sitio contiene una gran cantidad de archivos, es posible que el escáner sea bloqueado por tu proveedor de hosting si este excede el límite de ejecución que ellos hayan impuesto sobre su cuenta."
1382
 
1383
  msgid "ScannerWithoutSPL"
1384
+ msgstr "El escáner hace uso de las librerías <a href=\"http://php.net/manual/en/class.splfileobject.php\" target=\"_blank\" rel=\"noopener\">SPL</a> y <a target=\"_blank\" href=\"http://php.net/manual/en/class.filesystemiterator.php\" rel=\"noopener\">Filesystem Iterator</a> de PHP para escanear el árbol de directorios de tu sitio web. Esta librería solo está disponible en PHP 5 >= 5.3.0 &mdash; y &mdash; PHP 7; si tu servidor hace uso de una versión antigua, el plugin no funcionará como se espera. Por favor, contacta a tu proveedor de hosting para obtener ayuda al respecto."
1385
 
1386
  msgid "IntegrityLanguageTitle"
1387
  msgstr "Integridad de WordPress (Idioma)"
1388
 
1389
  msgid "IntegrityInfo"
1390
+ msgstr "La información necesaria para verificar la integridad de tu instalación de WordPress proviene de la <a href=\"http://codex.wordpress.org/WordPress.org_API\" target=\"_blank\" rel=\"noopener\">API Oficial de WordPress</a>. El plugin compara esta información con los archivos instalados en tu sitio web. Por defecto, la API provee una copia de los archivos en Inglés, si instalaste un idioma diferente, por favor selecciónalo en esta opción para reducir la cantidad de falsos/positivos que el escáner pueda encontrar."
1391
 
1392
  msgid "IntegrityNote"
1393
+ msgstr "<b>Nota:</b> No todos los idiomas están soportados por la API de WordPress. Es posible que tengas que usar la versión en Inglés para reducir la cantidad de falsos/positivos arrojados por el escáner durante su ejecución. Como alternativa, puede seleccionar dichos archivos y marcarlos como revisados para que el escáner los ignore."
1394
 
1395
  msgid "Reason"
1396
  msgstr "Motivo"
1402
  msgstr "No Ignorar Estos Archivos"
1403
 
1404
  msgid "FalsePositivesInfo"
1405
+ msgstr "El escáner de archivos no lee el contenido de estos, sino que compara el Checksum para saber si han sido modificados. Un falso/positivo ocurre cuando la modificación no hace parte de una inyección de código malicioso, estas modificaciones pueden ser consideradas inofencivas. Los archivos en esta lista han sido marcados como falsos/positivos y serán ignorados durante los próximos escaneos del sistema."
1406
 
1407
  msgid "IgnoreFiles"
1408
  msgstr "Ignorar Archivos Durante Los Escaneos"
1411
  msgstr "Ignorar Un Solo Archivo"
1412
 
1413
  msgid "IgnoreFilesInfo"
1414
+ msgstr "Utiliza esta herramienta para seleccionar directorios que contienen muchos archivos o archivos que son muy pesados para ser procesados por el escáner de seguridad. Esto usualmente incluye directorios con imágenes, archivos multimedia, y en general cualquier archivo que no tenga código. Ignorar estos archivos mejorará el rendimiento del plugin y mantendrá el consumo de memoria a niveles mínimos."
1415
 
1416
  msgid "SecretKeys"
1417
  msgstr "Llaves de Seguridad"
1418
 
1419
  msgid "SecretKeysUpdated"
1420
+ msgstr "Las llaves de seguridad han sido cambiadas (abajo puedes encontrar un resumen de la operación)."
1421
 
1422
  msgid "SecretKeysGenerate"
1423
  msgstr "Generar Nuevas Llaves de Seguridad"
1424
 
1425
  msgid "SecretKeysExpiration"
1426
+ msgstr "Tu sesión de usuario expirará inmediatamente cuando las nuevas llaves de seguridad sean generadas."
1427
 
1428
  msgid "SecretKeysInfo"
1429
+ msgstr "Las llaves secretas o de seguridad son una lista de constantes aleatorias agregadas a tu sitio web, para mejorar el proceso de encriptación de las cookies para cada usuario. Las llaves hacen que tu sitio sea más difícil de vulnerar, al agregar elementos aleatorios en las contraseñas. No necesitas memorizar estas llaves, ellas serán guardadas en el archivo de configuración de WordPress. Puede cambiarlas en cualquier momento para invalidar sesiones de usuario existentes, forzando a todos los usuarios a autenticar sus cuentas nuevamente."
1430
 
1431
  msgid "PluginReinstall"
1432
  msgstr "Re-Instalar Plugins"
1433
 
1434
  msgid "PluginReinstallInfo"
1435
+ msgstr "En el caso de que sospeches que tu sitio web está infectado con código maliciosos, o incluso después de limpiar tu sitio, es una buena idea reinstalar todos los plugins y plantillas, incluso aquellos que no están activados, para asegurar que el código es el original. Ten en cuenta que plugins y plantillas premium no pueden ser reinstaladas por motivos de compatibilidad con sus licencias."
1436
 
1437
  msgid "PluginReinstallCache"
1438
+ msgstr "La información mostrada aquí es guardada en cache por %%SUCURI.ResetPlugin.CacheLifeTime%% segundos, esto es necesario para reducir el número de conexiones HTTP y subsecuentemente el consumo de ancho de banda de tu servidor. Actualmente no existe una opción para limpiar esta caché, debes esperar a que el plugin la regenere automáticamente."
1439
 
1440
  msgid "PluginReinstallWarning"
1441
+ msgstr "<bADVERTENCIA!</b> La reinstalación de uno o más plugin puede ocasionar daños irreversibles a tu sitio web, procede con cuidado y asegúrate de mantener una copia de seguridad actualizada del sitio a la mano. Esta herramienta no tendrá ningún efecto sobre la base de datos."
1442
 
1443
  msgid "Roles"
1444
  msgstr "Privilegios"
1450
  msgstr "Cambiar la Contraseña de Usuario"
1451
 
1452
  msgid "PasswordChangeInfo"
1453
+ msgstr "Puedes generar una nueva contraseña aleatoria para las cuentas de usuario que selecciones de la lista. Un correo será enviado a cada usuario. Si decides cambiar tu propia contraseña, tu sesión de usuario expirará inmediatamente. Necesitarás autenticar tu cuenta nuevamente con la nueva contraseña que recibirás en tu correo electrónico."
1454
 
1455
  msgid "PasswordChangeAlert"
1456
+ msgstr "WordPress ha generado una nueva contraseña de forma aleatoria para tu cuenta de usuario <b>%%SUCURI.ResetPassword.UserName%%</b> en este sitio web <a target=\"_blank\" href=\"http://%%SUCURI.ResetPassword.Website%%\">%%SUCURI.ResetPassword.Website%%</a>. El cambio ha sido solicitado por uno de los administradores del sitio por motivos de seguridad. Tu nueva contraseña es &mdash; <span style=\"font-family:Menlo, Monaco, monospace, serif;font-weight:700\">%%%SUCURI.ResetPassword.Password%%%</span> &mdash; por favor cámbiala lo antes posible."
1457
 
1458
  msgid "Update"
1459
  msgstr "Actualización"
1465
  msgstr "Actualizaciones Disponibles"
1466
 
1467
  msgid "AvailableUpdatesInfo"
1468
+ msgstr "WordPress tiene una acogida muy grande en Internet, esto atrae la atención de personas maliciosas para encontrar vulnerabilidades en el código, al igual que en el código de plugins y plantillas que otras empresas desarrollan. Es recomendable mantener plugins y plantillas actualizadas para prevenir ataques tan pronto como vulnerabilidades sean descubiertas."
1469
 
1470
  msgid "WhitelistScript"
1471
  msgstr "Desbloquear Archivos PHP"
1472
 
1473
  msgid "WhitelistScriptInfo"
1474
+ msgstr "Después de aplicar el hardening en los directorios soportados por el plugin, un archivo .htaccess será creado con reglas para bloquear el acceso directo a todos los archivos PHP contenidos en dichos directorios, esta es una buena precaución para evitar la ejecución de código malicioso; con algunas excepciones, el archivo <em>\"index.php\"</em> es el único que debería tener acceso público, sin embargo muchos plugins y plantillas requieren de este acceso también, utilice esta herramienta para desbloquearlos."
1475
 
1476
  msgid "Uninstall"
1477
  msgstr "Eliminar Registros de Seguridad, Hardening y Configuraciones"
1478
 
1479
  msgid "UninstallInfo"
1480
+ msgstr "Esta acción iniciará el proceso de desactivación / desinstalación del plugin. Todos los registro de seguridad guardados en el disco local, las reglas de hardening y las configuraciones serán eliminadas. Ten en cuenta que los registros de seguridad guardados en el servidor de Sucuri no serán eliminados, esto es para prevenir que usuarios maliciosos intenten borrar sus huellas después de ejecutar un ataque en contra del sitio web."
1481
 
1482
  msgid "ImportExport"
1483
  msgstr "Importar Y Exportar Ajustes"
1484
 
1485
  msgid "ImportExportInfo"
1486
+ msgstr "Copie la información codificada en JSON que aparece en la caja de abajo, pegue esta información en la misma caja en el sitio web donde desea importar esta configuración. Ten en cuenta que algunas opciones serán omitidas, ya que estas contienen información irrelevante para otros sitios. Para importar la configuración de otro sitio web a este, reemplace el contenido de la caja con los datos codificados en JSON de otro sitio, luego presione el botón para continuar. Ten en cuenta que algunas opciones no serán importadas para reducir el riesgo de insertar datos arbitrarios en el disco."
1487
 
1488
  msgid "DataStorage"
1489
  msgstr "Almacenamiento de Datos"
1490
 
1491
  msgid "DataStorageInfo"
1492
+ msgstr "Este es el directorio donde el plugin guardará los registros de seguridad, el archivo con las configuraciones, la caché y datos adicionales de otras herramientas. El plugin requiere de permisos de escritura en este directorio, así como en los archivos contenidos allí. Si prefieres mantener estos archivos en un directorio diferente al especificado, por favor define una constante llamada <em>\"SUCURI_DATA_STORAGE\"</em> en el archivo de configuración de WordPress, con la ruta absoluta del nuevo directorio."
1493
+
1494
+ msgid "TimezoneTitle"
1495
+ msgstr "Zona Horaria"
1496
+
1497
+ msgid "TimezoneInfo"
1498
+ msgstr "Esta opción define la zona horaria que será usada a través de todo el plugin para mostrar las fechas y horas cuando sea necesario. Esta opción también afecta la fecha y hora de la información visible en el panel de registros de seguridad que viene de un servidor remoto configurado para usar Horario del este de Norteamérica (EDT por sus siglas en Inglés). WordPress ofrece una opción en la página de ajustes generales que te permite configurar la zona horaria para todo el sitio web, sin embargo, si estás experimentando problemas con la hora en los registros de seguridad, esta opción te ayudará a solucionarlos."
1499
+
1500
+ msgid "TimezoneStatus"
1501
+ msgstr "La zona horaria para la fecha y hora en los registros de seguridad ha sido cambiada"
1502
 
1503
+ msgid "ChecksumsAPI"
1504
+ msgstr "WordPress Checksums API"
1505
 
1506
+ msgid "ChecksumsAPIInfo"
1507
+ msgstr "La herramienta que verifica la integridad de la instalación usa un servicio remoto mantenido por WordPress.org para determinar qué archivos fueron agregados, eliminados o modificados. La API devuelve una lista de archivos con sus respectivos checksums, esta información garantiza que la instalación no está corrupta. Tu puedes, sin embargo, apuntar el plugin a un repositorio en GitHub en caso de que estés usando una versión personalizada de WordPress como la <a href=\"https://github.com/WordPress/WordPress\" target=\"_blank\">versión alpha del código</a>."
1508
 
1509
+ msgid "ChecksumsAPIChanged"
1510
+ msgstr "La dirección web para obtener los checksums de WordPress ha sido cambiada"
1511
 
1512
+ msgid "MaxExecutionTimeAlert"
1513
+ msgstr "El servidor no pudo procesar esta acción rápido; tiempo máximo de ejecución alcanzado"
readme.txt CHANGED
@@ -3,160 +3,114 @@ Contributors: dd@sucuri.net
3
  Donate Link: https://sucuri.net/
4
  Tags: malware, security, firewall, scan, spam, virus, sucuri, protection, WordPress Security, Login Security, Security Auditing, File Integrity, htaccess, phishing, backdoors, SQL Injection, RFI, LFI, XSS, CSRF, website firewall, Website Security, Performance Optimization, Zero Day, Software Vulnerability, Exploits, Hacks, Attackers, Bad Actors, Reverse Proxy, Two Factor Security, Two Factor Authentication, Security Logs, HeatBleed Vulnerability, Website Protection, Bash Vulnerability, RevSlider Vulnerability, MailPoet Vulnerability, Malware Prevention, Website Security, Website Firewall, Website AntiVirus, Security Response, Security Detection, Security Prevention
5
  Requires at least: 3.6
6
- Stable tag: 1.8.7
7
  Tested up to: 4.8.0
 
8
 
9
  The Sucuri WordPress Security plugin is a security toolset for security integrity monitoring, malware detection and security hardening.
10
 
11
-
12
  == Description ==
13
 
14
  Sucuri Inc. is a globally recognized authority in all matters related to website security, with specialization in WordPress Security.
15
 
16
  The Sucuri Security WordPress plugin is free to all WordPress users. It is a security suite meant to complement your existing security posture. It offers its users a set of security features for their website, each designed to have a positive affect on their security posture:
17
 
18
- <ol>
19
- <li>Security Activity Auditing</li>
20
- <li>File Integrity Monitoring</li>
21
- <li>Remote Malware Scanning</li>
22
- <li>Blacklist Monitoring</li>
23
- <li>Effective Security Hardening</li>
24
- <li>Post-Hack Security Actions</li>
25
- <li>Security Notifications</li>
26
- <li>Website Firewall (add on)</li>
27
- </ol>
28
-
29
 
30
- = Security Activity Monitoring =
31
 
32
- This is perhaps the most underutilized security function. It’s the act of monitoring all security related events within your WordPress install. The challenge is, what makes up a security event. In the eyes of Sucuri, any change that occurs within the application could be categorized as a security event, as such we try to record it.
33
 
34
- This is important because it allows you, the website owner, the ability to keep a good eye on the various changes occurring within your environment. Who is logging in? What changes are being made?
35
 
36
- [youtube https://www.youtube.com/watch?v=RwEwJgL2-m8]
 
 
 
 
 
37
 
38
- This feature is logging all activity to the Sucuri cloud, for safe keeping. This ensures that an attacker is not able to wipe your forensic data and prevent further security analysis after a compromise. If an attacker is able to bypass your security controls, your security logs will be kept safe within the Sucuri Security Operations Center (SOC).
39
 
40
- This feature is particularly important to website / system administrators and security experts looking to understand what is going on with their website and when it’s happening.
41
 
 
42
 
43
- = Security File Integrity Monitoring =
44
 
45
- Security File Integrity Monitoring has been fundamental to the world of security. It’s the act of comparing a known good with the current state. If the current state differs from the known good, you know you have a problem. This is the basis of a lot of host intrusion detection systems. It’s what we have built into the plugin.
46
 
47
- It will create a <strong>known good</strong> the minute the plugin is installed. This will be of all the directories at the root of the install, this includes plugins, themes and core files.
48
 
49
- [youtube https://www.youtube.com/watch?v=JGbHq7OFs3Q]
50
 
 
51
 
52
- = Remote Security Malware Scanning =
53
 
54
- This feature is powered by our scanning engine, found on our free security scanner - <a href="https://sitecheck.sucuri.net/" target="_blank">SiteCheck</a>. It’s important to take some time to <a href="https://blog.sucuri.net/2012/10/ask-sucuri-how-does-sitecheck-work.html" target="_blank">understand how this scanner works</a>.
55
 
56
- [youtube https://www.youtube.com/watch?v=JGbHq7OFs3Q]
57
 
58
- There are limitations with the way this scanner works, you can find more information in the FAQ section.
59
 
 
60
 
61
- = Security Blacklist Monitoring =
62
 
63
  Another very interesting feature of the Security Malware Scanner is that it incorporates various blacklist engines. Security blacklist engines include the following:
64
 
65
- <ol>
66
- <li>Sucuri Labs</li>
67
- <li>Google Safe Browsing</li>
68
- <li>Norton</li>
69
- <li>AVG</li>
70
- <li>Phish Tank</li>
71
- <li>ESET</li>
72
- <li>McAfee Site Advisor</li>
73
- <li>Yandex</li>
74
- <li>SpamHaus</li>
75
- <li>Bitdefender</li>
76
- </ol>
77
 
78
  These are some of the largest blacklisting entities, each having the ability to directly impact your brands online reputation. By synchronize with their environments we’re able to tell you, upon scan, whether any of them are negatively flagging your website with a security related issue. If they do, then via our website security product, we’re able to help you get off the their security blacklist.
79
 
80
-
81
- = Effective Security Hardening =
82
 
83
  It’s easy to get lost in the world of security hardening. At Sucuri we clean hundreds of websites a day, many with the various security hardening configurations you find in various WordPress Security presentations. In this section, we add those that we feel to be most effective, and that complement the entire Sucuri suite of products.
84
 
85
- [youtube https://www.youtube.com/watch?v=Nuksi7rMNV0]
86
-
87
-
88
- = Post-Hack Security Actions =
89
 
90
  Regardless of how good your security posture is, sometimes it’s impossible to prevent the inevitable. When this happens, we’ve included a section to help you walk through the three key things you should do after a compromise.
91
 
92
- [youtube https://www.youtube.com/watch?v=cEPxbe9hoHw]
93
-
94
-
95
- = Security Notifications =
96
 
97
  Having all these security features would be useless unless you were notified of the issues. This is why we have made available security alerts. We have also expanded the various security related events, to provide website owners more flexibility in regards to what they want to know about. As a website owner, you have the option to make these security alerts as quiet or noisy as you would like.
98
 
99
-
100
- = Sucuri Firewall (Add On Security Service) =
101
 
102
  This is by far the coolest security feature Sucuri has to offer everyday website owners. It’s an enterprise grade Website Firewall designed to give you the best security protection any website can hope for. It protects your website from a variety of website attacks and security events to include:
103
 
104
- <ol>
105
- <li>Denial of Service (DOS / DDOS) Attacks</li>
106
- <li>Exploitation of Software Vulnerabilities</li>
107
- <li>Zero Day Disclosure Patches</li>
108
- <li>Brute Force Attacks against your Access Control Mechanisms</li>
109
- </ol>
110
 
111
  This is coupled with a number of features like:
112
 
113
- <ol>
114
- <li>Performance Optimization</li>
115
- <li>Advanced Access Control Features</li>
116
- <li>Failover and Redundancy</li>
117
- </ol>
118
 
119
- This is <strong>not included as a free</strong> option to the plugin, but is integrated so that if purchased you are able to activate. If you prefer to leverage the Sucuri Firewall product by itself, you have the option to operate the <a href="https://wordpress.org/plugins/sucuri-cloudproxy-waf/" target="_blank" rel="noopener">Website Firewall WordPress Security</a> plugin in standalone mode.
120
-
121
- [youtube https://www.youtube.com/watch?v=fN-3DLObLF0]
122
 
123
  The Sucuri Security WordPress Security plugin is built by the team that is known for their proactive approach to security. It is built using intelligence gathered from thousands upon thousands of remediation cases, millions of unique domain scans and 10’s of millions of website security attack blocks.
124
 
125
-
126
- == Installation ==
127
-
128
- The installation of the Sucuri Security WordPress Security plugin is very simple and straight forward. <a href="https://sucuri.net/wordpress-security-plugin-installation" target="_blank">A detailed breakdown of the process is available, including images,</a> below however we outline the bare minimum steps.
129
-
130
- [youtube https://www.youtube.com/watch?v=KC3UC_Y27G0]
131
-
132
- To install Sucuri Security and complement your Security posture:
133
-
134
- 1. You will want to log into your WordPress administration panel - (e.g., https://example.com/wp-admin/),
135
- 2. Navigate to <strong>Plugins Menu</strong> option in your WordPress administration panel,
136
- 3. Select <strong>Add New</strong>,
137
- 4. Type <strong>Sucuri</strong> in the <strong>Search</strong> box, and click
138
- <strong>Search</strong> plugins,
139
- 5. The first option you get should be for <strong>Sucuri Security - Auditing,
140
- Malware Scanner and Hardening</strong>,
141
- 6. Select <strong>Install Now</strong>,
142
- 7. Now choose to <strong>Activate</strong> the plugin,
143
- 8. Once activated, you will need to create an API key, this is done automatically for you. Simply click on <strong>Generate API Key for [...]</strong>,
144
- 9. Once the API key is generated the page will redirect you to your dashboard and the plugin is automatically configured for you.
145
-
146
- To configure the Sucuri WordPress Security plugin for your specific Security needs:
147
-
148
- 1. Navigate to the <strong>Sucuri Security</strong> menu option (left hand side),
149
- 2. Hover or click on the name,
150
- 3. Click on <strong>Settings</strong>.
151
-
152
- The <strong>Settings</strong> page allows you to configure the website to your preferred security needs. Some of it’s features include changing the email alerts, via the <strong>alert settings</strong> tab or disabling integrity checking. We encourage you to visit this section and tune your security needs as you see fit.
153
-
154
-
155
- == Frequently Asked Questions ==
156
-
157
- More information can be found on the the Sucuri Security WordPress Security plugin via our free [Knowledge Base](https://kb.sucuri.net/plugins/WordPress+Plugin).
158
-
159
- = What does this plugin do that other WordPress security plugins don't do? =
160
 
161
  A few other security plugins provide activity monitoring features, but few do them well. The activity monitoring in this plugin is second to none, tying the activity into the Sucuri Security Operations Center (SOC) ensuring it's safe keeping.
162
 
@@ -176,27 +130,27 @@ Yes. This plugin compliments your existing security toolsets. It is not designed
176
 
177
  = Where do I get support for this plugin? =
178
 
179
- The best place is to engage us via the <a href="https://wordpress.org/support/plugin/sucuri-scanner" target="_blank" rel="noopener">Support Forum</a>. If you are a client, <a href="https://support.sucuri.net/support/?new" target="_blank">you can submit a ticket here</a>.
180
 
181
  = Does your plugin conflict with WordFence? =
182
 
183
  The plugin does not, but there might be issues with our scanners. If you get an “Unable to Properly Scan Your Site” It’s likely because the WordFence plugin is blocking our scanner as an invalid crawler. You would have to white list our IP address on the WordFence dashboard.
184
 
185
- = What are the Remote Security Malware Scanning Limitations? =
186
 
187
  Because the security malware scanner is remote, it is unable to see things that are on the server but that are not displaying on the browser. If you are interested in this, we encourage you to subscribe to our website security product. This issues includes things like Phishing pages, Backdoors, Mailer Scripts, etc.
188
 
189
  = Your plugin didn’t detect this malware? =
190
 
191
- This happens, reference the remote scanner limitations above. This should not be confused with our website security product. If you have malware, and you are a client, submit a ticket so that <a href="https://support.sucuri.net/support/?new&mremoval" target="_blank">we can help you get clean</a>.
192
 
193
- If you are not a client, and you want to share what you have found please send it to <a href="mailto:labs@sucuri.net">labs@sucuri.net</a>.
194
 
195
  The plugin is not performing application level malware / security scanning so this is not uncommon.
196
 
197
  = Is it free to enable the Website Firewall option? =
198
 
199
- No, it is not. To enable you must subscribe to the <a href="https://sucuri.net/website-firewall-signup" target="_blank">Website Firewall</a> service.
200
 
201
  = Will this plugin impact the performance of my website? =
202
 
@@ -210,17 +164,55 @@ No, it does not.
210
 
211
  Not that we are aware of.
212
 
213
- = Do I need to run this plugin to get the Website Firewall ad-on feature? =
214
 
215
  No, it is not required. The Website Firewall runs in the cloud without the need of anything installed. This plugin only helps see and manage the service from the WordPress dashboard.
216
 
 
 
 
 
 
 
 
 
 
 
 
217
  == Upgrade Notice ==
218
 
219
- = 1.8.7 =
220
  This version adds support for the latest version of WordPress. Introduces new features and fixes some bugs reported by the WordPress community as well as bugs found by our automated testing system.
221
 
222
  == Changelog ==
223
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  = 1.8.7 =
225
  * Fix multiple issues with the API calls
226
  * Add queue system to fix website performance
@@ -585,8 +577,3 @@ This version adds support for the latest version of WordPress. Introduces new fe
585
 
586
  = 1.1.1 =
587
  * First public release.
588
-
589
-
590
- == Credits ==
591
-
592
- * <a href="https://sucuri.net/" target="_blank">Sucuri Inc.</a>
3
  Donate Link: https://sucuri.net/
4
  Tags: malware, security, firewall, scan, spam, virus, sucuri, protection, WordPress Security, Login Security, Security Auditing, File Integrity, htaccess, phishing, backdoors, SQL Injection, RFI, LFI, XSS, CSRF, website firewall, Website Security, Performance Optimization, Zero Day, Software Vulnerability, Exploits, Hacks, Attackers, Bad Actors, Reverse Proxy, Two Factor Security, Two Factor Authentication, Security Logs, HeatBleed Vulnerability, Website Protection, Bash Vulnerability, RevSlider Vulnerability, MailPoet Vulnerability, Malware Prevention, Website Security, Website Firewall, Website AntiVirus, Security Response, Security Detection, Security Prevention
5
  Requires at least: 3.6
 
6
  Tested up to: 4.8.0
7
+ Stable tag: 1.8.8
8
 
9
  The Sucuri WordPress Security plugin is a security toolset for security integrity monitoring, malware detection and security hardening.
10
 
 
11
  == Description ==
12
 
13
  Sucuri Inc. is a globally recognized authority in all matters related to website security, with specialization in WordPress Security.
14
 
15
  The Sucuri Security WordPress plugin is free to all WordPress users. It is a security suite meant to complement your existing security posture. It offers its users a set of security features for their website, each designed to have a positive affect on their security posture:
16
 
17
+ * Security Activity Auditing
18
+ * File Integrity Monitoring
19
+ * Remote Malware Scanning
20
+ * Blacklist Monitoring
21
+ * Effective Security Hardening
22
+ * Post-Hack Security Actions
23
+ * Security Notifications
24
+ * Website Firewall (premium)
 
 
 
25
 
26
+ == Installation ==
27
 
28
+ The installation of the Sucuri Security WordPress Security plugin is very simple and straight forward. A detailed breakdown of the process is available [here](https://sucuri.net/wordpress-security-plugin-installation) (including images), however, below we outline the bare minimum steps.
29
 
30
+ To install Sucuri Security and complement your Security posture:
31
 
32
+ 1. Log into your WordPress administration panel,
33
+ 2. In the sidebar, choose "Plugins" and then "Add New",
34
+ 3. Type "sucuri" or "sucuri-scanner" in the search box,
35
+ 4. Install the option with the "By Sucuri Inc." at the foot,
36
+ 5. Once activated, you will find a new icon in the sidebar with the Sucuri logo, go to the plugin's dashboard and click the button that says "Generate API Key" to activate the event monitoring, this will generate an unique key to authenticate your website against the remote Sucuri WordPress API service,
37
+ 6. Feel free to visit the plugin' settings page to configure other options including the security alerts, hardening options, file system scanner paths, API service communication, among other things.
38
 
39
+ Visit the [Support Forum](https://wordpress.org/support/plugin/sucuri-scanner) to ask questions, suggest new features, or report bugs. And recommend the plugin to your friends and colleagues if you think it can help other people.
40
 
41
+ == Frequently Asked Questions ==
42
 
43
+ More information can be found on the the Sucuri Security WordPress Security plugin via our free [Knowledge Base](https://kb.sucuri.net/plugins/WordPress+Plugin).
44
 
45
+ = What is the security activity auditing? =
46
 
47
+ This is perhaps the most underutilized security function. It’s the act of monitoring all security related events within your WordPress install. The challenge is, what makes up a security event. In the eyes of Sucuri, any change that occurs within the application could be categorized as a security event, as such we try to record it.
48
 
49
+ This is important because it gives you, the website owner, the ability to keep a good eye on the various changes occurring within your environment. Who is logging in? What changes are being made?
50
 
51
+ This feature is logging all activity to the Sucuri cloud, for safe keeping. This ensures that an attacker is not able to wipe your forensic data and prevent further security analysis after a compromise. If an attacker is able to bypass your security controls, your security logs will be kept safe within the Sucuri Security Operations Center (SOC).
52
 
53
+ This feature is particularly important to website / system administrators and security experts looking to understand what is going on with their website and when it’s happening.
54
 
55
+ = What is the file integrity monitoring =
56
 
57
+ Security File Integrity Monitoring has been fundamental to the world of security. It’s the act of comparing a known good with the current state. If the current state differs from the known good, you know you have a problem. This is the basis of a lot of host intrusion detection systems. It’s what we have built into the plugin.
58
 
59
+ It will create a known good the minute the plugin is installed. This will be of all the directories at the root of the install, this includes plugins, themes and core files.
60
 
61
+ = What is the remote malware scanning? =
62
 
63
+ This feature is powered by our scanning engine, found on our free security scanner - [SiteCheck](https://sitecheck.sucuri.net/). It’s important to take some time to [understand how this scanner works](https://blog.sucuri.net/2012/10/ask-sucuri-how-does-sitecheck-work.html). There are limitations with the way this scanner works, you can find more information in the FAQ section.
64
 
65
+ = What is the blacklist monitoring? =
66
 
67
  Another very interesting feature of the Security Malware Scanner is that it incorporates various blacklist engines. Security blacklist engines include the following:
68
 
69
+ * Sucuri Labs
70
+ * Google Safe Browsing
71
+ * Norton
72
+ * AVG
73
+ * Phish Tank
74
+ * ESET
75
+ * McAfee Site Advisor
76
+ * Yandex
77
+ * SpamHaus
78
+ * Bitdefender
 
 
79
 
80
  These are some of the largest blacklisting entities, each having the ability to directly impact your brands online reputation. By synchronize with their environments we’re able to tell you, upon scan, whether any of them are negatively flagging your website with a security related issue. If they do, then via our website security product, we’re able to help you get off the their security blacklist.
81
 
82
+ = What is the effective security hardening =
 
83
 
84
  It’s easy to get lost in the world of security hardening. At Sucuri we clean hundreds of websites a day, many with the various security hardening configurations you find in various WordPress Security presentations. In this section, we add those that we feel to be most effective, and that complement the entire Sucuri suite of products.
85
 
86
+ = What are the post-hack security actions =
 
 
 
87
 
88
  Regardless of how good your security posture is, sometimes it’s impossible to prevent the inevitable. When this happens, we’ve included a section to help you walk through the three key things you should do after a compromise.
89
 
90
+ = What are the security notifications =
 
 
 
91
 
92
  Having all these security features would be useless unless you were notified of the issues. This is why we have made available security alerts. We have also expanded the various security related events, to provide website owners more flexibility in regards to what they want to know about. As a website owner, you have the option to make these security alerts as quiet or noisy as you would like.
93
 
94
+ = What is the website firewall (premium) =
 
95
 
96
  This is by far the coolest security feature Sucuri has to offer everyday website owners. It’s an enterprise grade Website Firewall designed to give you the best security protection any website can hope for. It protects your website from a variety of website attacks and security events to include:
97
 
98
+ * Denial of Service (DOS / DDOS) Attacks
99
+ * Exploitation of Software Vulnerabilities
100
+ * Zero Day Disclosure Patches
101
+ * Brute Force Attacks against your Access Control Mechanisms
 
 
102
 
103
  This is coupled with a number of features like:
104
 
105
+ * Performance Optimization
106
+ * Advanced Access Control Features
107
+ * Failover and Redundancy
 
 
108
 
109
+ This is **not included as a free** option to the plugin, but is integrated so that if purchased you are able to activate. If you prefer to leverage the Sucuri Firewall product by itself, you have the option to operate the [Website Firewall WordPress Security](https://wordpress.org/plugins/sucuri-cloudproxy-waf/) plugin in standalone mode.
 
 
110
 
111
  The Sucuri Security WordPress Security plugin is built by the team that is known for their proactive approach to security. It is built using intelligence gathered from thousands upon thousands of remediation cases, millions of unique domain scans and 10’s of millions of website security attack blocks.
112
 
113
+ = What does this plugin do that other security plugins don't do? =
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
 
115
  A few other security plugins provide activity monitoring features, but few do them well. The activity monitoring in this plugin is second to none, tying the activity into the Sucuri Security Operations Center (SOC) ensuring it's safe keeping.
116
 
130
 
131
  = Where do I get support for this plugin? =
132
 
133
+ The best place is to engage us via the [Support Forum](https://wordpress.org/support/plugin/sucuri-scanner). If you are a client, you can submit a ticket [here](https://support.sucuri.net/support/?new).
134
 
135
  = Does your plugin conflict with WordFence? =
136
 
137
  The plugin does not, but there might be issues with our scanners. If you get an “Unable to Properly Scan Your Site” It’s likely because the WordFence plugin is blocking our scanner as an invalid crawler. You would have to white list our IP address on the WordFence dashboard.
138
 
139
+ = What are the Remote Malware Scanner limitations? =
140
 
141
  Because the security malware scanner is remote, it is unable to see things that are on the server but that are not displaying on the browser. If you are interested in this, we encourage you to subscribe to our website security product. This issues includes things like Phishing pages, Backdoors, Mailer Scripts, etc.
142
 
143
  = Your plugin didn’t detect this malware? =
144
 
145
+ This happens, reference the remote scanner limitations above. This should not be confused with our website security product. If you have malware, and you are a client, submit a ticket so that [we can help you get clean](https://support.sucuri.net/support/?new&mremoval).
146
 
147
+ If you are not a client, and you want to share what you have found please send it to [labs@sucuri.net](mailto:labs@sucuri.net).
148
 
149
  The plugin is not performing application level malware / security scanning so this is not uncommon.
150
 
151
  = Is it free to enable the Website Firewall option? =
152
 
153
+ No, it is not. To enable you must subscribe to the [Website Firewall](https://sucuri.net/website-firewall-signup) service.
154
 
155
  = Will this plugin impact the performance of my website? =
156
 
164
 
165
  Not that we are aware of.
166
 
167
+ = Do I need this plugin to use the Website Firewall service? =
168
 
169
  No, it is not required. The Website Firewall runs in the cloud without the need of anything installed. This plugin only helps see and manage the service from the WordPress dashboard.
170
 
171
+ == Screenshots ==
172
+
173
+ 1. WordPress Integrity Tool - Detects added, modified, and removed files.
174
+ 2. Integrity Diff Utility - Shows differences in the core WordPress files.
175
+ 3. Audit Logs and Malware Scanner - Reports suspicious events and malicious code.
176
+ 4. Sucuri Firewall - Settings visibility, audit logs, IP blacklisting, and cache.
177
+ 5. Website Hardening - Offers multiple options to increase the security of the website.
178
+ 6. Failed Logins - Shows failed login attempts, successful logins and online users.
179
+ 7. Post Hack Tools - Offers multiple tools to react after the suspiciousness of a hack.
180
+ 8. Settings - Offers multiple settings to configure the functionality of the plugin.
181
+
182
  == Upgrade Notice ==
183
 
184
+ = 1.8.8 =
185
  This version adds support for the latest version of WordPress. Introduces new features and fixes some bugs reported by the WordPress community as well as bugs found by our automated testing system.
186
 
187
  == Changelog ==
188
 
189
+ = 1.8.8 =
190
+ * Add smart limit to send logs from the queue to the API
191
+ * Add option to ignore events for post transitions
192
+ * Fix infinite loop with email alerts and SMTP plugin
193
+ * Add option to configure the malware scanner target URL
194
+ * Add option to enable the auto clear cache firewall function
195
+ * Modify status of the directory hardening using the Firewall
196
+ * Modify error message in audit logs when the API key is missing
197
+ * Modify timing for the dashboard alerts after an update
198
+ * Modify firewall clear cache button to execute via Ajax
199
+ * Modify firewall settings page to load data via Ajax
200
+ * Add option to blacklist IP addresses with the Firewall API
201
+ * Fix order of the audit logs when the queue is merged
202
+ * Add more directories to ignore during the scans
203
+ * Add option to customize the URL for the malware scans
204
+ * Fix error interception for Firewall API errors
205
+ * Add support for other English and Spanish based languages
206
+ * Modify mechanism to ignore files from integrity checks
207
+ * Add option to stop sending the failed login passwords
208
+ * Modify default value for some of the alert settings
209
+ * Remove unnecessary statistics panel for the audit logs
210
+ * Modify output for the malware results to simplify links
211
+ * Add option to override the timezone for the datetime
212
+ * Add option to configure the WordPress checksums API
213
+ * Add maximum execution time avoidance in the integrity tool
214
+ * Add support to run diff on deleted WordPress files
215
+
216
  = 1.8.7 =
217
  * Fix multiple issues with the API calls
218
  * Add queue system to fix website performance
577
 
578
  = 1.1.1 =
579
  * First public release.
 
 
 
 
 
src/api.lib.php CHANGED
@@ -82,7 +82,7 @@ class SucuriScanAPI extends SucuriScanOption
82
  return self::throwException('Only GET and POST methods allowed');
83
  }
84
 
85
- $response = null;
86
  $timeout = SUCURISCAN_MAX_REQUEST_TIMEOUT;
87
  $args = is_array($args) ? $args : array();
88
 
@@ -98,6 +98,22 @@ class SucuriScanAPI extends SucuriScanOption
98
  $args['blocking'] = true;
99
  $args['sslverify'] = true;
100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  if (!array_key_exists('time', $params)) {
102
  $params['time'] = time();
103
  }
@@ -106,25 +122,30 @@ class SucuriScanAPI extends SucuriScanOption
106
  if ($method === 'GET') {
107
  $args['body'] = null;
108
  $url .= '?' . self::buildQuery($params);
109
- $response = wp_remote_get($url, $args);
110
  }
111
 
112
  /* support HTTP POST requests */
113
  if ($method === 'POST') {
 
 
 
 
 
114
  $args['body'] = $params;
115
- $response = wp_remote_post($url, $args);
116
  }
117
 
118
- if (is_wp_error($response)) {
119
- return self::throwException($response->get_error_message());
120
  }
121
 
122
  /* try to return a JSON-encode object */
123
- if ($data = @json_decode($response['body'], true)) {
124
  return $data; /* associative array */
125
  }
126
 
127
- return $response['body'];
128
  }
129
 
130
  /**
@@ -185,7 +206,6 @@ class SucuriScanAPI extends SucuriScanOption
185
  */
186
  public static function apiCallWordpress($method = 'GET', $params = array(), $send_api_key = true, $args = array())
187
  {
188
- $url = SUCURISCAN_API_URL;
189
  $params[SUCURISCAN_API_VERSION] = 1;
190
  $params['p'] = 'wordpress';
191
 
@@ -199,7 +219,7 @@ class SucuriScanAPI extends SucuriScanOption
199
  $params['k'] = $api_key;
200
  }
201
 
202
- return self::apiCall($url, $method, $params, $args);
203
  }
204
 
205
  /**
@@ -233,34 +253,34 @@ class SucuriScanAPI extends SucuriScanOption
233
  * verification, this option it disable automatically when the error is detected
234
  * for the first time.
235
  *
236
- * @param array $response HTTP response after API endpoint execution.
237
  * @return bool False if the API call failed, true otherwise.
238
  */
239
- public static function handleResponse($response = array())
240
  {
241
- if (!$response || getenv('SUCURISCAN_NO_API_HANDLE')) {
242
  return false;
243
  }
244
 
245
- if (is_array($response)
246
- && array_key_exists('status', $response)
247
- && intval($response['status']) === 1
248
  ) {
249
  return true;
250
  }
251
 
252
- if (is_string($response) && !empty($response)) {
253
- return SucuriScanInterface::error($response);
254
  }
255
 
256
- if (!is_array($response)
257
- || !isset($response['messages'])
258
- || empty($response['messages'])
259
  ) {
260
  return SucuriScanInterface::error(__('ErrorNoInfo', SUCURISCAN_TEXTDOMAIN));
261
  }
262
 
263
- $msg = implode(".\x20", $response['messages']);
264
  $raw = $msg; /* Keep a copy of the original message. */
265
 
266
  // Special response for invalid API keys.
@@ -313,14 +333,14 @@ class SucuriScanAPI extends SucuriScanOption
313
  $email = self::getSiteEmail();
314
  }
315
 
316
- $response = self::apiCallWordpress('POST', array(
317
  'e' => $email,
318
  's' => self::getDomain(),
319
  'a' => 'register_site',
320
  ), false);
321
 
322
- if (self::handleResponse($response)) {
323
- self::setPluginKey($response['output']['api_key']);
324
 
325
  SucuriScanEvent::installScheduledTask();
326
  SucuriScanEvent::notifyEvent('plugin_change', 'API key was generated and set');
@@ -339,15 +359,15 @@ class SucuriScanAPI extends SucuriScanOption
339
  {
340
  $domain = self::getDomain();
341
 
342
- $response = self::apiCallWordpress('GET', array(
343
  'e' => self::getSiteEmail(),
344
  's' => $domain,
345
  'a' => 'recover_key',
346
  ), false);
347
 
348
- if (self::handleResponse($response)) {
349
  SucuriScanEvent::notifyEvent('plugin_change', 'API key recovery for domain: ' . $domain);
350
- return SucuriScanInterface::info($response['output']['message']);
351
  }
352
 
353
  return false;
@@ -361,16 +381,16 @@ class SucuriScanAPI extends SucuriScanOption
361
  */
362
  public static function getAuditLogs($lines = 50)
363
  {
364
- $response = self::apiCallWordpress('GET', array(
365
  'a' => 'get_logs',
366
  'l' => $lines,
367
  ));
368
 
369
- if (!self::handleResponse($response)) {
370
  return false;
371
  }
372
 
373
- return self::parseAuditLogs($response);
374
  }
375
 
376
  /**
@@ -391,7 +411,7 @@ class SucuriScanAPI extends SucuriScanOption
391
  $time = substr($micro, 0, $offset);
392
  $auditlogs[] = sprintf(
393
  '%s %s : %s',
394
- date('Y-m-d H:i:s', intval($time)),
395
  SucuriScan::getSiteEmail(),
396
  $message
397
  );
@@ -411,15 +431,18 @@ class SucuriScanAPI extends SucuriScanOption
411
  /**
412
  * Reads, parses and extracts relevant data from the security logs.
413
  *
414
- * @param array $response JSON-decoded logs.
415
  * @return array Full data extracted from the logs.
416
  */
417
- private static function parseAuditLogs($response)
418
  {
419
- $response = is_array($response) ? $response : array();
420
- $response['output_data'] = array();
 
421
 
422
- foreach ((array) @$response['output'] as $log) {
 
 
423
  /* YYYY-MM-dd HH:ii:ss EMAIL : MESSAGE: (multiple entries): a,b,c */
424
  if (strpos($log, "\x20:\x20") === false) {
425
  continue; /* ignore; invalid format */
@@ -449,9 +472,9 @@ class SucuriScanAPI extends SucuriScanOption
449
  /* extract and fix the date and time using the Eastern time zone */
450
  $datetime = sprintf('%s %s EDT', $dateAndEmail[0], $dateAndEmail[1]);
451
  $log_data['timestamp'] = strtotime($datetime);
452
- $log_data['datetime'] = date('Y-m-d H:i:s', $log_data['timestamp']);
453
- $log_data['date'] = date('Y-m-d', $log_data['timestamp']);
454
- $log_data['time'] = date('H:i:s', $log_data['timestamp']);
455
 
456
  /* extract more information from the generic audit logs */
457
  $log_data['message'] = str_replace('<br>', ";\x20", $log_data['message']);
@@ -526,11 +549,11 @@ class SucuriScanAPI extends SucuriScanOption
526
  }
527
 
528
  if ($log_data = self::getLogsHotfix($log_data)) {
529
- $response['output_data'][] = $log_data;
530
  }
531
  }
532
 
533
- return $response;
534
  }
535
 
536
  /**
@@ -591,15 +614,14 @@ class SucuriScanAPI extends SucuriScanOption
591
  * Parse the event logs with multiple entries.
592
  *
593
  * @param string $event_log Event log that will be processed.
594
- * @return array List of parts of the event log.
595
  */
596
  public static function parseMultipleEntries($event_log = '')
597
  {
598
- if (@preg_match('/^(.*:\s)\(multiple entries\):\s(.+)/', $event_log, $match)) {
599
- $event_log = array();
600
- $event_log[] = trim($match[1]);
601
- $grouped_items = @explode(',', $match[2]);
602
- $event_log = array_merge($event_log, $grouped_items);
603
  }
604
 
605
  return $event_log;
@@ -704,12 +726,12 @@ class SucuriScanAPI extends SucuriScanOption
704
  return false;
705
  }
706
 
707
- $response = self::apiCallWordpress('POST', array(
708
  'a' => 'send_hashes',
709
  'h' => $hashes,
710
  ));
711
 
712
- return self::handleResponse($response);
713
  }
714
 
715
  /**
@@ -721,9 +743,9 @@ class SucuriScanAPI extends SucuriScanOption
721
  {
722
  $new_keys = array();
723
  $pattern = self::secretKeyPattern();
724
- $response = self::apiCall('https://api.wordpress.org/secret-key/1.1/salt/', 'GET');
725
 
726
- if ($response && @preg_match_all($pattern, $response, $match)) {
727
  foreach ($match[1] as $key => $value) {
728
  $new_keys[$value] = $match[3][$key];
729
  }
@@ -733,30 +755,123 @@ class SucuriScanAPI extends SucuriScanOption
733
  }
734
 
735
  /**
736
- * Retrieve a list with the checksums of the files in a specific version of WordPress.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
737
  *
738
  * @see Release Archive https://wordpress.org/download/release-archive/
 
739
  *
740
- * @param string|int $version Valid version number of the WordPress project.
741
- * @return array|bool Associative object with the relative filepath and the checksums of the project files.
742
  */
743
- public static function getOfficialChecksums($version = 0)
744
  {
745
  $result = false;
746
- $language = SucuriScanOption::getOption(':language');
747
- $response = self::apiCall(
748
- 'https://api.wordpress.org/core/checksums/1.0/',
749
- 'GET',
750
- array(
751
- 'version' => $version,
752
- 'locale' => $language,
753
- )
754
- );
 
 
 
 
 
 
 
755
 
756
- if (is_array($response) && isset($response['checksums'])) {
757
- $result = isset($response['checksums'][$version])
758
- ? $response['checksums'][$version]
759
- : $response['checksums'];
760
  }
761
 
762
  return $result;
@@ -859,11 +974,8 @@ class SucuriScanAPI extends SucuriScanOption
859
  */
860
  public static function getRemotePluginData($plugin = '')
861
  {
862
- $url = sprintf('https://api.wordpress.org/plugins/info/1.0/%s.json', $plugin);
863
- $response = self::apiCall($url, 'GET'); /* ignore plugin existence */
864
- $response = ($response === 'null') ? false : $response;
865
-
866
- return $response ? $response : false;
867
  }
868
 
869
  /**
@@ -875,27 +987,36 @@ class SucuriScanAPI extends SucuriScanOption
875
  * @see https://i18n.svn.wordpress.org/
876
  * @see https://core.svn.wordpress.org/tags/VERSION_NUMBER/
877
  *
878
- * @param string $filepath Relative path of a core file.
879
- * @param string|int $version Optional Wordpress version number.
880
  * @return string|bool Original code for the core file, false otherwise.
881
  */
882
- public static function getOriginalCoreFile($filepath = '', $version = 0)
883
  {
884
- if (empty($filepath)) {
885
- return false;
886
- }
887
 
888
- if ($version == 0) {
889
- $version = self::siteVersion();
 
 
 
890
  }
891
 
892
- $url = sprintf('https://core.svn.wordpress.org/tags/%s/%s', $version, $filepath);
893
- $response = self::apiCall($url, 'GET');
 
 
 
 
 
 
 
894
 
895
- if (strpos($response, '404 Not Found') !== false) {
 
896
  return self::throwException('WordPress version is not supported anymore');
897
  }
898
 
899
- return $response ? $response : false;
900
  }
901
  }
82
  return self::throwException('Only GET and POST methods allowed');
83
  }
84
 
85
+ $res = null;
86
  $timeout = SUCURISCAN_MAX_REQUEST_TIMEOUT;
87
  $args = is_array($args) ? $args : array();
88
 
98
  $args['blocking'] = true;
99
  $args['sslverify'] = true;
100
 
101
+ /* separate hardcoded query parameters */
102
+ if (empty($params) && strpos($url, '?')) {
103
+ $parts = @parse_url($url);
104
+
105
+ if (array_key_exists('query', $parts)) {
106
+ $portions = explode('&', $parts['query']);
107
+ $url = str_replace('?' . $parts['query'], '', $url);
108
+
109
+ foreach ($portions as $portion) {
110
+ $bits = explode('=', $portion, 2);
111
+ $params[$bits[0]] = $bits[1];
112
+ }
113
+ }
114
+ }
115
+
116
+ /* include current timestamp for trackability */
117
  if (!array_key_exists('time', $params)) {
118
  $params['time'] = time();
119
  }
122
  if ($method === 'GET') {
123
  $args['body'] = null;
124
  $url .= '?' . self::buildQuery($params);
125
+ $res = wp_remote_get($url, $args);
126
  }
127
 
128
  /* support HTTP POST requests */
129
  if ($method === 'POST') {
130
+ if (array_key_exists('a', $params)) {
131
+ /* include action to increase visibility */
132
+ $url .= '?a=' . $params['a'];
133
+ }
134
+
135
  $args['body'] = $params;
136
+ $res = wp_remote_post($url, $args);
137
  }
138
 
139
+ if (is_wp_error($res)) {
140
+ return self::throwException($res->get_error_message());
141
  }
142
 
143
  /* try to return a JSON-encode object */
144
+ if ($data = @json_decode($res['body'], true)) {
145
  return $data; /* associative array */
146
  }
147
 
148
+ return $res['body'];
149
  }
150
 
151
  /**
206
  */
207
  public static function apiCallWordpress($method = 'GET', $params = array(), $send_api_key = true, $args = array())
208
  {
 
209
  $params[SUCURISCAN_API_VERSION] = 1;
210
  $params['p'] = 'wordpress';
211
 
219
  $params['k'] = $api_key;
220
  }
221
 
222
+ return self::apiCall(SUCURISCAN_API_URL, $method, $params, $args);
223
  }
224
 
225
  /**
253
  * verification, this option it disable automatically when the error is detected
254
  * for the first time.
255
  *
256
+ * @param array $res HTTP response after API endpoint execution.
257
  * @return bool False if the API call failed, true otherwise.
258
  */
259
+ public static function handleResponse($res = array())
260
  {
261
+ if (!$res || getenv('SUCURISCAN_NO_API_HANDLE')) {
262
  return false;
263
  }
264
 
265
+ if (is_array($res)
266
+ && array_key_exists('status', $res)
267
+ && intval($res['status']) === 1
268
  ) {
269
  return true;
270
  }
271
 
272
+ if (is_string($res) && !empty($res)) {
273
+ return SucuriScanInterface::error($res);
274
  }
275
 
276
+ if (!is_array($res)
277
+ || !isset($res['messages'])
278
+ || empty($res['messages'])
279
  ) {
280
  return SucuriScanInterface::error(__('ErrorNoInfo', SUCURISCAN_TEXTDOMAIN));
281
  }
282
 
283
+ $msg = implode(".\x20", $res['messages']);
284
  $raw = $msg; /* Keep a copy of the original message. */
285
 
286
  // Special response for invalid API keys.
333
  $email = self::getSiteEmail();
334
  }
335
 
336
+ $res = self::apiCallWordpress('POST', array(
337
  'e' => $email,
338
  's' => self::getDomain(),
339
  'a' => 'register_site',
340
  ), false);
341
 
342
+ if (self::handleResponse($res)) {
343
+ self::setPluginKey($res['output']['api_key']);
344
 
345
  SucuriScanEvent::installScheduledTask();
346
  SucuriScanEvent::notifyEvent('plugin_change', 'API key was generated and set');
359
  {
360
  $domain = self::getDomain();
361
 
362
+ $res = self::apiCallWordpress('GET', array(
363
  'e' => self::getSiteEmail(),
364
  's' => $domain,
365
  'a' => 'recover_key',
366
  ), false);
367
 
368
+ if (self::handleResponse($res)) {
369
  SucuriScanEvent::notifyEvent('plugin_change', 'API key recovery for domain: ' . $domain);
370
+ return SucuriScanInterface::info($res['output']['message']);
371
  }
372
 
373
  return false;
381
  */
382
  public static function getAuditLogs($lines = 50)
383
  {
384
+ $res = self::apiCallWordpress('GET', array(
385
  'a' => 'get_logs',
386
  'l' => $lines,
387
  ));
388
 
389
+ if (!self::handleResponse($res)) {
390
  return false;
391
  }
392
 
393
+ return self::parseAuditLogs($res);
394
  }
395
 
396
  /**
411
  $time = substr($micro, 0, $offset);
412
  $auditlogs[] = sprintf(
413
  '%s %s : %s',
414
+ SucuriScan::datetime($time, 'Y-m-d H:i:s'),
415
  SucuriScan::getSiteEmail(),
416
  $message
417
  );
431
  /**
432
  * Reads, parses and extracts relevant data from the security logs.
433
  *
434
+ * @param array $res JSON-decoded logs.
435
  * @return array Full data extracted from the logs.
436
  */
437
+ private static function parseAuditLogs($res)
438
  {
439
+ if (!is_array($res)) {
440
+ $res = array();
441
+ }
442
 
443
+ $res['output_data'] = array();
444
+
445
+ foreach ((array) @$res['output'] as $log) {
446
  /* YYYY-MM-dd HH:ii:ss EMAIL : MESSAGE: (multiple entries): a,b,c */
447
  if (strpos($log, "\x20:\x20") === false) {
448
  continue; /* ignore; invalid format */
472
  /* extract and fix the date and time using the Eastern time zone */
473
  $datetime = sprintf('%s %s EDT', $dateAndEmail[0], $dateAndEmail[1]);
474
  $log_data['timestamp'] = strtotime($datetime);
475
+ $log_data['datetime'] = SucuriScan::datetime($log_data['timestamp'], 'Y-m-d H:i:s');
476
+ $log_data['date'] = SucuriScan::datetime($log_data['timestamp'], 'Y-m-d');
477
+ $log_data['time'] = SucuriScan::datetime($log_data['timestamp'], 'H:i:s');
478
 
479
  /* extract more information from the generic audit logs */
480
  $log_data['message'] = str_replace('<br>', ";\x20", $log_data['message']);
549
  }
550
 
551
  if ($log_data = self::getLogsHotfix($log_data)) {
552
+ $res['output_data'][] = $log_data;
553
  }
554
  }
555
 
556
+ return $res;
557
  }
558
 
559
  /**
614
  * Parse the event logs with multiple entries.
615
  *
616
  * @param string $event_log Event log that will be processed.
617
+ * @return string|array List of parts of the event log.
618
  */
619
  public static function parseMultipleEntries($event_log = '')
620
  {
621
+ $pattern = "\x20(multiple entries):\x20";
622
+
623
+ if (strpos($event_log, $pattern)) {
624
+ return explode(',', str_replace($pattern, ',', $event_log));
 
625
  }
626
 
627
  return $event_log;
726
  return false;
727
  }
728
 
729
+ $res = self::apiCallWordpress('POST', array(
730
  'a' => 'send_hashes',
731
  'h' => $hashes,
732
  ));
733
 
734
+ return self::handleResponse($res);
735
  }
736
 
737
  /**
743
  {
744
  $new_keys = array();
745
  $pattern = self::secretKeyPattern();
746
+ $res = self::apiCall('https://api.wordpress.org/secret-key/1.1/salt/', 'GET');
747
 
748
+ if ($res && @preg_match_all($pattern, $res, $match)) {
749
  foreach ($match[1] as $key => $value) {
750
  $new_keys[$value] = $match[3][$key];
751
  }
755
  }
756
 
757
  /**
758
+ * Returns the URL for the WordPress checksums API service.
759
+ *
760
+ * @return string URL for the WordPress checksums API.
761
+ */
762
+ public static function checksumAPI()
763
+ {
764
+ $url = 'https://api.wordpress.org/core/checksums/1.0/?version={version}&locale={locale}';
765
+
766
+ if ($custom = SucuriScanOption::getOption(':checksum_api')) {
767
+ $url = sprintf(
768
+ 'https://api.github.com/repos/%s/git/trees/master?recursive=1',
769
+ $custom /* expect: username/repository */
770
+ );
771
+ }
772
+
773
+ $url = str_replace('{version}', SucuriScan::siteVersion(), $url);
774
+ $url = str_replace('{locale}', SucuriScanOption::getOption(':language'), $url);
775
+
776
+ return $url;
777
+ }
778
+
779
+ /**
780
+ * Returns the name of the hash to use in the integrity tool
781
+ *
782
+ * By default, the plugin will use MD5 to hash the content of the specified
783
+ * file, however, if the core integrity tool is using a custom URL, and this
784
+ * URL is pointing to GitHub API, then we will assume that the checksum that
785
+ * comes from this service is using SHA1.
786
+ *
787
+ * @return string Hash to use in the integrity tool.
788
+ */
789
+ public static function checksumAlgorithm()
790
+ {
791
+ return strpos(self::checksumAPI(), '//api.github.com') ? 'sha1' : 'md5';
792
+ }
793
+
794
+ /**
795
+ * Calculates the md5/sha1 hash of a given file.
796
+ *
797
+ * When the user decides to configure the integrity tool to use the checksum
798
+ * from a GitHub repository the plugin will have to use the SHA1 algorithm
799
+ * instead of MD5 (which is what WordPress uses in their API). For this, we
800
+ * will have to calculate the GIT hash object of the file which is basically
801
+ * the merge of the text "blob" a single white space, the length of the text
802
+ * a null byte and then the text in itself (content of the file).
803
+ *
804
+ * Example:
805
+ *
806
+ * - Input: "hello world\n"
807
+ * - GIT (object): "blob 16\u0000hello world\n"
808
+ * - GIT (shaobj): "3b18e512dba79e4c8300dd08aeb37f8e728b8dad"
809
+ *
810
+ * @see https://git-scm.com/book/en/v2/Git-Internals-Git-Objects#_object_storage
811
+ *
812
+ * @param string $algorithm Either md5 or sha1.
813
+ * @param string $filename Absolute path to the given file.
814
+ * @return string Hash of the given file.
815
+ */
816
+ public static function checksum($algorithm, $filename)
817
+ {
818
+ if ($algorithm === 'sha1') {
819
+ $content = SucuriScanFileInfo::fileContent($filename);
820
+ return @sha1("blob\x20" . strlen($content) . "\x00" . $content);
821
+ }
822
+
823
+ return @md5_file($filename);
824
+ }
825
+
826
+ /**
827
+ * Returns the checksum of all the files of the current WordPress version.
828
+ *
829
+ * The webmaster can change this URL using an option form the settings page.
830
+ * This allows them to control which repository will be used to check the
831
+ * integrity of the installation.
832
+ *
833
+ * For example, projectnami.org offers an option to use Microsoft SQL Server
834
+ * instead of MySQL has a different set of files and even with the same
835
+ * filenames many of them have been modified to support the new database
836
+ * engine, since the checksums are different than the official ones the
837
+ * number of false positives will increase. This option allows the webmaster
838
+ * to point the plugin to a different URL where the new checksums for this
839
+ * project will be retrieved.
840
+ *
841
+ * If the custom API is part of GitHub infrastructure, the plugin will try
842
+ * to build the expected JSON object from the output, if it fails it will
843
+ * pass the unmodified response to the rest of the code and try to analyze
844
+ * the integrity of the installation with that information.
845
  *
846
  * @see Release Archive https://wordpress.org/download/release-archive/
847
+ * @see https://api.github.com/repos/user/repo/git/trees/master?recursive=1
848
  *
849
+ * @return array|bool Checksums of the WordPress installation.
 
850
  */
851
+ public static function getOfficialChecksums()
852
  {
853
  $result = false;
854
+ $url = self::checksumAPI();
855
+ $version = SucuriScan::siteVersion();
856
+ $res = self::apiCall($url, 'GET', array());
857
+
858
+ if (is_array($res)
859
+ && array_key_exists('sha', $res)
860
+ && array_key_exists('url', $res)
861
+ && array_key_exists('tree', $res)
862
+ && strpos($url, '//api.github.com')
863
+ ) {
864
+ $checksums = array();
865
+ foreach ($res['tree'] as $meta) {
866
+ $checksums[$meta['path']] = $meta['sha'];
867
+ }
868
+ $res = array('checksums' => array($version => $checksums));
869
+ }
870
 
871
+ if (is_array($res) && isset($res['checksums'])) {
872
+ $result = isset($res['checksums'][$version])
873
+ ? $res['checksums'][$version]
874
+ : $res['checksums'];
875
  }
876
 
877
  return $result;
974
  */
975
  public static function getRemotePluginData($plugin = '')
976
  {
977
+ $resp = self::apiCall('https://api.wordpress.org/plugins/info/1.0/' . $plugin . '.json', 'GET');
978
+ return ($resp === 'null') ? false : $resp;
 
 
 
979
  }
980
 
981
  /**
987
  * @see https://i18n.svn.wordpress.org/
988
  * @see https://core.svn.wordpress.org/tags/VERSION_NUMBER/
989
  *
990
+ * @param string $filename Relative path of a core file.
 
991
  * @return string|bool Original code for the core file, false otherwise.
992
  */
993
+ public static function getOriginalCoreFile($filename)
994
  {
995
+ $version = self::siteVersion();
996
+ $url = 'https://core.svn.wordpress.org/tags/{version}/{filename}';
 
997
 
998
+ if ($custom = SucuriScanOption::getOption(':checksum_api')) {
999
+ $url = sprintf(
1000
+ 'https://raw.githubusercontent.com/%s/master/{filename}',
1001
+ $custom /* expect: username/repository */
1002
+ );
1003
  }
1004
 
1005
+ $url = str_replace('{version}', $version, $url);
1006
+ $url = str_replace('{filename}', $filename, $url);
1007
+
1008
+ $resp = self::apiCall($url, 'GET');
1009
+
1010
+ if (strpos($resp, '404 Not Found') !== false) {
1011
+ /* not found comes from the official WordPress API */
1012
+ return self::throwException('WordPress version is not supported anymore');
1013
+ }
1014
 
1015
+ if (strpos($resp, '400: Invalid request') !== false) {
1016
+ /* invalid request comes from the unofficial GitHub API */
1017
  return self::throwException('WordPress version is not supported anymore');
1018
  }
1019
 
1020
+ return $resp ? $resp : false;
1021
  }
1022
  }
src/auditlogs.lib.php CHANGED
@@ -97,6 +97,11 @@ class SucuriScanAuditLogs
97
  : sprintf('API %s secs', round($duration, 4));
98
  }
99
 
 
 
 
 
 
100
  /* stop everything and report errors */
101
  if (!empty($errors)) {
102
  $response['content'] .= $errors;
@@ -112,28 +117,34 @@ class SucuriScanAuditLogs
112
  if (!$auditlogs) {
113
  $auditlogs = $queuelogs;
114
  } else {
115
- $auditlogs['total_entries'] += $queuelogs['total_entries'];
 
 
116
  $auditlogs['output'] = array_merge(
117
  $queuelogs['output'],
118
- $auditlogs['output']
119
  );
120
  $auditlogs['output_data'] = array_merge(
121
  $queuelogs['output_data'],
122
- $auditlogs['output_data']
123
  );
124
  }
125
  }
126
 
127
- if ($auditlogs) {
 
 
 
 
 
128
  $counter_i = 0;
129
  $total_items = 0;
130
  $previousDate = '';
131
- $todaysDate = date('M d, Y');
132
  $iterator_start = ($pageNumber - 1) * $maxPerPage;
 
133
 
134
- if (array_key_exists('output_data', $auditlogs)) {
135
- $total_items = count($auditlogs['output_data']);
136
- }
137
 
138
  for ($i = $iterator_start; $i < $total_items; $i++) {
139
  if ($counter_i > $maxPerPage) {
@@ -148,15 +159,15 @@ class SucuriScanAuditLogs
148
 
149
  $snippet_data = array(
150
  'AuditLog.Event' => $audit_log['event'],
151
- 'AuditLog.Time' => date('H:i', $audit_log['timestamp']),
152
- 'AuditLog.Date' => date('M d, Y', $audit_log['timestamp']),
153
  'AuditLog.Username' => $audit_log['username'],
154
  'AuditLog.Address' => $audit_log['remote_addr'],
155
  'AuditLog.Message' => $audit_log['message'],
156
  'AuditLog.Extra' => '',
157
  );
158
 
159
- // Determine if we need to print the date.
160
  if ($snippet_data['AuditLog.Date'] === $previousDate) {
161
  $snippet_data['AuditLog.Date'] = '';
162
  } elseif ($snippet_data['AuditLog.Date'] === $todaysDate) {
@@ -166,7 +177,7 @@ class SucuriScanAuditLogs
166
  $previousDate = $snippet_data['AuditLog.Date'];
167
  }
168
 
169
- // Decorate date if necessary.
170
  if (!empty($snippet_data['AuditLog.Date'])) {
171
  $snippet_data['AuditLog.Date'] =
172
  '<div class="sucuriscan-auditlog-date">'
@@ -174,10 +185,9 @@ class SucuriScanAuditLogs
174
  . '</div>';
175
  }
176
 
177
- // Print every file_list information item in a separate table.
178
  if ($audit_log['file_list']) {
179
- $css_scrollable = $audit_log['file_list_count'] > 10 ? 'sucuriscan-list-as-table-scrollable' : '';
180
- $snippet_data['AuditLog.Extra'] .= '<ul class="sucuriscan-list-as-table ' . $css_scrollable . '">';
181
 
182
  foreach ($audit_log['file_list'] as $log_extra) {
183
  $snippet_data['AuditLog.Extra'] .= '<li>' . SucuriScan::escape($log_extra) . '</li>';
@@ -225,32 +235,7 @@ class SucuriScanAuditLogs
225
  }
226
 
227
  /**
228
- * Draws the statistic charts with data from the security logs.
229
- *
230
- * The percentage of successful and failed logins. The percentage of events
231
- * distributed by severity. The amount of events triggered by each user. And
232
- * the amount of events triggered from each IP address. All these statistics
233
- * will be rendered in the page.
234
- *
235
- * @return string HTML with the stats about the security logs.
236
- */
237
- public static function pageAuditLogsReport()
238
- {
239
- $params = array();
240
- $logs4report = SucuriScanOption::getOption(':logs4report');
241
-
242
- $params['AuditReport.Logs4Report'] = $logs4report;
243
-
244
- return SucuriScanTemplate::getSection('auditlogs-report', $params);
245
- }
246
-
247
- /**
248
- * Analyzes the latest security logs and generates statistics.
249
- *
250
- * A JSON-encoded data structure will be returned after the plugin reads,
251
- * processes and extracts relevant information from the latest security logs.
252
- * By default the plugin will use the latest 500 logs but the website owner
253
- * can increase or decrease this value to reduce or extend the statistics.
254
  *
255
  * @codeCoverageIgnore - Notice that there is a test case that covers this
256
  * code, but since the WP-Send-JSON method uses die() to stop any further
@@ -258,79 +243,34 @@ class SucuriScanAuditLogs
258
  * with a missing line in the coverage. Since the test case takes care of
259
  * the functionality of this code we will assume that it is fully covered.
260
  */
261
- public static function ajaxAuditLogsReport()
262
  {
263
- if (SucuriScanRequest::post('form_action') !== 'get_audit_logs_report') {
264
  return;
265
  }
266
 
267
- $response = array();
268
- $logs4report = SucuriScanOption::getOption(':logs4report');
269
- $report = SucuriScanAPI::getAuditReport($logs4report);
270
-
271
- $response['status'] = false;
272
- $response['message'] = 'Not enough logs';
273
- $response['eventsPerUserSeries'] = array();
274
- $response['eventsPerUserCategories'] = array();
275
- $response['eventsPerIPAddressSeries'] = array();
276
- $response['eventsPerIPAddressCategories'] = array();
277
- $response['eventsPerTypePoints'] = array();
278
- $response['eventsPerTypeColors'] = array();
279
- $response['eventsPerLogin'] = array();
280
-
281
- if ($report) {
282
- $response['status'] = true;
283
- $response['message'] = '';
284
- $response['eventsPerTypeColors'] = $report['event_colors'];
285
-
286
- /* Generate report chart data for the events per type */
287
- foreach ($report['events_per_type'] as $event => $times) {
288
- $response['eventsPerTypePoints'][] = array(
289
- ucwords($event . "\x20events"),
290
- $times /* amount of events */
291
- );
292
- }
293
-
294
- /* Generate report chart data for the events per login */
295
- foreach ($report['events_per_login'] as $event => $times) {
296
- $response['eventsPerLogin'][] = array(
297
- ucwords($event . "\x20logins"),
298
- $times /* number of logins */
299
- );
300
- }
301
-
302
- /* Generate report chart data for the events per user */
303
- $users = array_values($report['events_per_user']);
304
- $response['eventsPerUserSeries'] = array_merge(array('data'), $users);
305
- $response['eventsPerUserCategories'] = array_keys($report['events_per_user']);
306
-
307
- /* Generate report chart data for the events per remote address */
308
- $ips = array_values($report['events_per_ipaddress']);
309
- $response['eventsPerIPAddressSeries'] = array_merge(array('data'), $ips);
310
- $response['eventsPerIPAddressCategories'] = array_keys($report['events_per_ipaddress']);
311
- }
312
-
313
- wp_send_json($response, 200);
314
  }
315
 
316
  /**
317
- * Send the logs from the queue to the API.
318
  *
319
- * @codeCoverageIgnore - Notice that there is a test case that covers this
320
- * code, but since the WP-Send-JSON method uses die() to stop any further
321
- * output it means that XDebug cannot cover the next line, leaving a report
322
- * with a missing line in the coverage. Since the test case takes care of
323
- * the functionality of this code we will assume that it is fully covered.
 
 
 
324
  */
325
- public static function ajaxAuditLogsSendLogs()
326
  {
327
- if (SucuriScanRequest::post('form_action') !== 'auditlogs_send_logs') {
328
- return;
329
  }
330
 
331
- /* blocking; might take a while */
332
- SucuriScanEvent::sendLogsFromQueue();
333
-
334
- wp_send_json(array('ok' => true), 200);
335
  }
336
  }
97
  : sprintf('API %s secs', round($duration, 4));
98
  }
99
 
100
+ /* explain missing API key */
101
+ if (!SucuriScanAPI::getPluginKey()) {
102
+ $response['status'] = __('APIKeyMissing', SUCURISCAN_TEXTDOMAIN);
103
+ }
104
+
105
  /* stop everything and report errors */
106
  if (!empty($errors)) {
107
  $response['content'] .= $errors;
117
  if (!$auditlogs) {
118
  $auditlogs = $queuelogs;
119
  } else {
120
+ $auditlogs['total_entries'] = isset($auditlogs['total_entries'])
121
+ ? ($auditlogs['total_entries'] + $queuelogs['total_entries'])
122
+ : $queuelogs['total_entries'];
123
  $auditlogs['output'] = array_merge(
124
  $queuelogs['output'],
125
+ @$auditlogs['output']
126
  );
127
  $auditlogs['output_data'] = array_merge(
128
  $queuelogs['output_data'],
129
+ @$auditlogs['output_data']
130
  );
131
  }
132
  }
133
 
134
+ if (is_array($auditlogs)
135
+ && isset($auditlogs['output_data'])
136
+ && isset($auditlogs['total_entries'])
137
+ && is_array($auditlogs['output_data'])
138
+ && is_numeric($auditlogs['total_entries'])
139
+ ) {
140
  $counter_i = 0;
141
  $total_items = 0;
142
  $previousDate = '';
143
+ $todaysDate = SucuriScan::datetime(null, 'M d, Y');
144
  $iterator_start = ($pageNumber - 1) * $maxPerPage;
145
+ $total_items = count($auditlogs['output_data']);
146
 
147
+ usort($auditlogs['output_data'], array('SucuriScanAuditLogs', 'sortByDate'));
 
 
148
 
149
  for ($i = $iterator_start; $i < $total_items; $i++) {
150
  if ($counter_i > $maxPerPage) {
159
 
160
  $snippet_data = array(
161
  'AuditLog.Event' => $audit_log['event'],
162
+ 'AuditLog.Time' => SucuriScan::datetime($audit_log['timestamp'], 'H:i'),
163
+ 'AuditLog.Date' => SucuriScan::datetime($audit_log['timestamp'], 'M d, Y'),
164
  'AuditLog.Username' => $audit_log['username'],
165
  'AuditLog.Address' => $audit_log['remote_addr'],
166
  'AuditLog.Message' => $audit_log['message'],
167
  'AuditLog.Extra' => '',
168
  );
169
 
170
+ /* determine if we need to print the date */
171
  if ($snippet_data['AuditLog.Date'] === $previousDate) {
172
  $snippet_data['AuditLog.Date'] = '';
173
  } elseif ($snippet_data['AuditLog.Date'] === $todaysDate) {
177
  $previousDate = $snippet_data['AuditLog.Date'];
178
  }
179
 
180
+ /* decorate date if necessary */
181
  if (!empty($snippet_data['AuditLog.Date'])) {
182
  $snippet_data['AuditLog.Date'] =
183
  '<div class="sucuriscan-auditlog-date">'
185
  . '</div>';
186
  }
187
 
188
+ /* print every file_list information item in a separate table */
189
  if ($audit_log['file_list']) {
190
+ $snippet_data['AuditLog.Extra'] .= '<ul class="sucuriscan-list-as-table">';
 
191
 
192
  foreach ($audit_log['file_list'] as $log_extra) {
193
  $snippet_data['AuditLog.Extra'] .= '<li>' . SucuriScan::escape($log_extra) . '</li>';
235
  }
236
 
237
  /**
238
+ * Send the logs from the queue to the API.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  *
240
  * @codeCoverageIgnore - Notice that there is a test case that covers this
241
  * code, but since the WP-Send-JSON method uses die() to stop any further
243
  * with a missing line in the coverage. Since the test case takes care of
244
  * the functionality of this code we will assume that it is fully covered.
245
  */
246
+ public static function ajaxAuditLogsSendLogs()
247
  {
248
+ if (SucuriScanRequest::post('form_action') !== 'auditlogs_send_logs') {
249
  return;
250
  }
251
 
252
+ /* blocking; might take a while */
253
+ wp_send_json(SucuriScanEvent::sendLogsFromQueue(), 200);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
  }
255
 
256
  /**
257
+ * Sort the audit logs by date.
258
  *
259
+ * Considering that the logs from the API service will be merged with the
260
+ * logs from the local queue system to complement the information until the
261
+ * queue is emptied, we will have to sort the entries in the list to keep
262
+ * the dates in sync.
263
+ *
264
+ * @param array $a Data associated to a single log.
265
+ * @param array $b Data associated to another log.
266
+ * @return int Comparison between the dates of both logs.
267
  */
268
+ public static function sortByDate($a, $b)
269
  {
270
+ if ($a['timestamp'] === $b['timestamp']) {
271
+ return 0;
272
  }
273
 
274
+ return ($a['timestamp'] > $b['timestamp']) ? -1 : 1;
 
 
 
275
  }
276
  }
src/cache.lib.php CHANGED
@@ -368,7 +368,9 @@ class SucuriScanCache extends SucuriScan
368
 
369
  $finfo = $this->getDatastoreContent($assoc === 'array');
370
 
371
- if ($this->dataHasExpired($lifetime, $finfo)) {
 
 
372
  return false;
373
  }
374
 
@@ -425,7 +427,7 @@ class SucuriScanCache extends SucuriScan
425
  $finfo = $this->getDatastoreContent(true);
426
 
427
  if (!array_key_exists($key, $finfo['entries'])) {
428
- return self::throwException('Cache key does not exists');
429
  }
430
 
431
  unset($finfo['entries'][$key]);
368
 
369
  $finfo = $this->getDatastoreContent($assoc === 'array');
370
 
371
+ if ($this->dataHasExpired($lifetime, $finfo)
372
+ || !array_key_exists($key, $finfo['entries'])
373
+ ) {
374
  return false;
375
  }
376
 
427
  $finfo = $this->getDatastoreContent(true);
428
 
429
  if (!array_key_exists($key, $finfo['entries'])) {
430
+ return true;
431
  }
432
 
433
  unset($finfo['entries'][$key]);
src/command.lib.php CHANGED
@@ -100,12 +100,11 @@ class SucuriScanCommand extends SucuriScan
100
  * the elements in the code to facilitate the styling of the diff report.
101
  *
102
  * @param string $filepath Relative path to the core WordPress file.
103
- * @param string $version Version number of the WordPress installation.
104
  * @return string|bool HTML code with the diff report, false on failure.
105
  */
106
- public static function diffHTML($filepath, $version)
107
  {
108
- $checksums = SucuriScanAPI::getOfficialChecksums($version);
109
 
110
  if (!$checksums) {
111
  return SucuriScanInterface::error(__('UnsupportedWordPress', SUCURISCAN_TEXTDOMAIN));
@@ -115,25 +114,22 @@ class SucuriScanCommand extends SucuriScan
115
  return SucuriScanInterface::error(__('NoWordPressFile', SUCURISCAN_TEXTDOMAIN));
116
  }
117
 
118
- if (!file_exists(ABSPATH . '/' . $filepath)) {
119
- return SucuriScanInterface::error(__('CannotCheckMissingFile', SUCURISCAN_TEXTDOMAIN));
120
- }
121
-
122
  $output = ''; /* initialize empty with no differences */
123
- $tempfile = tempnam(sys_get_temp_dir(), SUCURISCAN . '-integrity-');
 
124
 
125
- if ($handle = @fopen($tempfile, 'w')) {
126
- $a = $tempfile; /* original file to compare */
127
- $b = ABSPATH . '/' . $filepath; /* modified */
128
- $content = SucuriScanAPI::getOriginalCoreFile($filepath, $version);
129
- @fwrite($handle, $content); /* create a copy of the original file */
130
  $output = self::diff($a, $b);
131
- @fclose($tempfile);
132
- @unlink($tempfile);
133
  }
134
 
 
 
 
135
  if (!is_array($output) || empty($output)) {
136
- return ''; /* no differences found */
137
  }
138
 
139
  $response = "<ul class='" . SUCURISCAN . "-diff-content'>\n";
@@ -144,13 +140,11 @@ class SucuriScanCommand extends SucuriScan
144
  $cssclass .= "\x20" . SUCURISCAN . '-diff-line' . $number;
145
 
146
  if ($number === 1) {
147
- $line = str_replace($a, $b . ' (ORIGINAL)', $line);
148
  $cssclass .= "\x20" . SUCURISCAN . '-diff-header';
149
- $line = substr($line, 0, 4 + strlen($b) + 11);
150
  } elseif ($number === 2) {
151
- $line = str_replace($b, $b . ' (MODIFIED)', $line);
152
  $cssclass .= "\x20" . SUCURISCAN . '-diff-header';
153
- $line = substr($line, 0, 4 + strlen($b) + 11);
154
  } elseif ($number === 3) {
155
  $cssclass .= "\x20" . SUCURISCAN . '-diff-header';
156
  } elseif ($line === '') {
100
  * the elements in the code to facilitate the styling of the diff report.
101
  *
102
  * @param string $filepath Relative path to the core WordPress file.
 
103
  * @return string|bool HTML code with the diff report, false on failure.
104
  */
105
+ public static function diffHTML($filepath)
106
  {
107
+ $checksums = SucuriScanAPI::getOfficialChecksums();
108
 
109
  if (!$checksums) {
110
  return SucuriScanInterface::error(__('UnsupportedWordPress', SUCURISCAN_TEXTDOMAIN));
114
  return SucuriScanInterface::error(__('NoWordPressFile', SUCURISCAN_TEXTDOMAIN));
115
  }
116
 
 
 
 
 
117
  $output = ''; /* initialize empty with no differences */
118
+ $a = tempnam(sys_get_temp_dir(), SUCURISCAN . '-integrity-');
119
+ $b = tempnam(sys_get_temp_dir(), SUCURISCAN . '-integrity-');
120
 
121
+ if ($handle = @fopen($a, 'w')) {
122
+ @fwrite($handle, SucuriScanAPI::getOriginalCoreFile($filepath));
123
+ @copy(ABSPATH . '/' . $filepath, $b);
 
 
124
  $output = self::diff($a, $b);
125
+ @fclose($handle);
 
126
  }
127
 
128
+ @unlink($a); /* delete original file */
129
+ @unlink($b); /* delete modified file */
130
+
131
  if (!is_array($output) || empty($output)) {
132
+ return SucuriScanInterface::error(__('ThereAreNoDifferences', SUCURISCAN_TEXTDOMAIN));
133
  }
134
 
135
  $response = "<ul class='" . SUCURISCAN . "-diff-content'>\n";
140
  $cssclass .= "\x20" . SUCURISCAN . '-diff-line' . $number;
141
 
142
  if ($number === 1) {
143
+ $line = sprintf('--- %s (ORIGINAL)', $filepath);
144
  $cssclass .= "\x20" . SUCURISCAN . '-diff-header';
 
145
  } elseif ($number === 2) {
146
+ $line = sprintf('+++ %s (MODIFIED)', $filepath);
147
  $cssclass .= "\x20" . SUCURISCAN . '-diff-header';
 
148
  } elseif ($number === 3) {
149
  $cssclass .= "\x20" . SUCURISCAN . '-diff-header';
150
  } elseif ($line === '') {
src/event.lib.php CHANGED
@@ -170,10 +170,11 @@ class SucuriScanEvent extends SucuriScan
170
  * to write the log into the queue when the previous request failed.
171
  *
172
  * @param string $message Information about the event.
173
- * @param string $timestamp Time when the event was triggered.
 
174
  * @return bool True if the event was logged, false otherwise.
175
  */
176
- private static function sendLogToAPI($message = '', $timestamp = '')
177
  {
178
  if (empty($message)) {
179
  return self::throwException('Event identifier cannot be empty');
@@ -183,7 +184,7 @@ class SucuriScanEvent extends SucuriScan
183
  $params['a'] = 'send_log';
184
  $params['m'] = $message;
185
  $params['time'] = $timestamp;
186
- $args = array('timeout' => 5 /* seconds */);
187
 
188
  $resp = SucuriScanAPI::apiCallWordpress('POST', $params, true, $args);
189
 
@@ -197,6 +198,10 @@ class SucuriScanEvent extends SucuriScan
197
  /**
198
  * Sends the event message to a local queue system.
199
  *
 
 
 
 
200
  * @param string $message Information about the security event.
201
  * @return bool True if the operation succeeded, false otherwise.
202
  */
@@ -219,7 +224,7 @@ class SucuriScanEvent extends SucuriScan
219
  if ($monitor_fpath !== false) {
220
  $local_event = sprintf(
221
  "%s WordPressAudit %s %s : %s\n",
222
- date('Y-m-d H:i:s'),
223
  SucuriScan::getTopLevelDomain(),
224
  SucuriScanOption::getOption(':account'),
225
  $message
@@ -232,7 +237,17 @@ class SucuriScanEvent extends SucuriScan
232
  }
233
  }
234
 
235
- /* enqueue the event if the API is enabled */
 
 
 
 
 
 
 
 
 
 
236
  if (SucuriScanOption::isEnabled(':api_service')) {
237
  $cache = new SucuriScanCache('auditqueue');
238
  $key = str_replace('.', '_', microtime(true));
@@ -244,47 +259,77 @@ class SucuriScanEvent extends SucuriScan
244
 
245
  /**
246
  * Sends all the events from the queue to the API.
 
 
247
  */
248
  public static function sendLogsFromQueue()
249
  {
250
  if (SucuriScanOption::isDisabled(':api_service')) {
251
- return;
252
  }
253
 
254
  $cache = new SucuriScanCache('auditqueue');
255
  $finfo = $cache->getDatastoreInfo();
256
  $events = $cache->getAll();
257
- $counter = 0;
258
 
259
  if (!$events) {
260
- return;
261
  }
262
 
263
- /* Send around 15,000 logs for maximum 30 seconds */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
264
  $maxtime = (int) SucuriScan::iniGet('max_execution_time');
265
- $maxreqs = ($maxtime > 1) ? (500 * $maxtime) : 5000;
 
 
 
 
 
266
 
267
  foreach ($events as $keyname => $message) {
268
  $offset = strpos($keyname, '_');
269
  $timestamp = substr($keyname, 0, $offset);
270
  $status = self::sendLogToAPI($message, $timestamp);
271
 
 
272
  if ($status !== true) {
273
- /* API is down */
274
- break;
275
  }
276
 
277
  /* dequeue event message */
278
  unset($events[$keyname]);
279
- $counter++;
280
 
281
- /* avoid memory limit */
282
- if ($counter >= $maxreqs) {
 
283
  break;
284
  }
285
  }
286
 
 
287
  $cache->override($events);
 
 
288
  }
289
 
290
  /**
@@ -415,58 +460,19 @@ class SucuriScanEvent extends SucuriScan
415
  {
416
  $message = strip_tags($message);
417
 
418
- /* auto-detect the action performed, either enabled or disabled. */
419
- if (preg_match('/( was )?(enabled|disabled)$/', $message, $match)) {
420
- $action = $match[2];
421
- }
422
-
423
- if ($action === 'enabled') {
424
  return self::reportNoticeEvent($message);
425
  }
426
 
427
- if ($action === 'disabled') {
 
428
  return self::reportErrorEvent($message);
429
  }
430
 
431
  return self::reportInfoEvent($message);
432
  }
433
 
434
- /**
435
- * Reports an esception on the code.
436
- *
437
- * @param Exception $exception A valid exception object of any type.
438
- * @return bool Whether the report was filled correctly or not.
439
- */
440
- public static function reportException($exception)
441
- {
442
- $e_trace = $exception->getTrace();
443
- $multiple_entries = array();
444
-
445
- foreach ($e_trace as $e_child) {
446
- $e_file = array_key_exists('file', $e_child)
447
- ? basename($e_child['file'])
448
- : '[internal function]';
449
- $e_line = array_key_exists('line', $e_child)
450
- ? basename($e_child['line'])
451
- : '0';
452
- $e_method = array_key_exists('class', $e_child)
453
- ? $e_child['class'] . $e_child['type'] . $e_child['function']
454
- : $e_child['function'];
455
- $multiple_entries[] = sprintf(
456
- '%s(%s): %s',
457
- $e_file,
458
- $e_line,
459
- $e_method
460
- );
461
- }
462
-
463
- return self::reportDebugEvent(sprintf(
464
- '%s: (multiple entries): %s',
465
- $exception->getMessage(),
466
- @implode(',', $multiple_entries)
467
- ));
468
- }
469
-
470
  /**
471
  * Send a notification to the administrator of the specified events, only if
472
  * the administrator accepted to receive alerts for this type of events.
@@ -506,7 +512,11 @@ class SucuriScanEvent extends SucuriScan
506
 
507
  case 'failed_login':
508
  $settings_url = SucuriScanTemplate::getUrl('settings');
509
- $content .= sprintf(__('FailedLoginFooter'), $settings_url, $settings_url);
 
 
 
 
510
  break;
511
 
512
  case 'bruteforce_attack':
@@ -644,13 +654,15 @@ class SucuriScanEvent extends SucuriScan
644
  }
645
 
646
  /**
647
- * Modify the WordPress configuration file and change the keys that were defined
648
- * by a new random-generated list of keys retrieved from the official WordPress
649
- * API. The result of the operation will be either FALSE in case of error, or an
650
- * array containing multiple indexes explaining the modification, among them you
651
- * will find the old and new keys.
 
 
652
  *
653
- * @return array|bool Either FALSE in case of error, or an array with the old and new keys.
654
  */
655
  public static function setNewConfigKeys()
656
  {
170
  * to write the log into the queue when the previous request failed.
171
  *
172
  * @param string $message Information about the event.
173
+ * @param string|int $timestamp Time when the event was triggered.
174
+ * @param int $timeout Maximum time in seconds to connect to the API.
175
  * @return bool True if the event was logged, false otherwise.
176
  */
177
+ private static function sendLogToAPI($message = '', $timestamp = '', $timeout = 1)
178
  {
179
  if (empty($message)) {
180
  return self::throwException('Event identifier cannot be empty');
184
  $params['a'] = 'send_log';
185
  $params['m'] = $message;
186
  $params['time'] = $timestamp;
187
+ $args = array('timeout' => $timeout);
188
 
189
  $resp = SucuriScanAPI::apiCallWordpress('POST', $params, true, $args);
190
 
198
  /**
199
  * Sends the event message to a local queue system.
200
  *
201
+ * Note: The method is public to facilitate the execution of some unit-tests
202
+ * but it could be private and be mocked by the test bootstrap script. Take
203
+ * this in consideration during the static analysis of the code.
204
+ *
205
  * @param string $message Information about the security event.
206
  * @return bool True if the operation succeeded, false otherwise.
207
  */
224
  if ($monitor_fpath !== false) {
225
  $local_event = sprintf(
226
  "%s WordPressAudit %s %s : %s\n",
227
+ SucuriScan::datetime(null, 'Y-m-d H:i:s'),
228
  SucuriScan::getTopLevelDomain(),
229
  SucuriScanOption::getOption(':account'),
230
  $message
237
  }
238
  }
239
 
240
+ /**
241
+ * Send event to the API if possible.
242
+ *
243
+ * If the user have not disabled the communication with the API service,
244
+ * the plugin will send a message with information about every triggered
245
+ * event in the website in realtime with a maximum connection time of
246
+ * two seconds. If the API service does not responds on time the plugin
247
+ * will insert the event into the local queue system and it will try to
248
+ * send the message again with a scheduled task every 24 hours, once the
249
+ * operation succeeds the event will be deleted from the queue.
250
+ */
251
  if (SucuriScanOption::isEnabled(':api_service')) {
252
  $cache = new SucuriScanCache('auditqueue');
253
  $key = str_replace('.', '_', microtime(true));
259
 
260
  /**
261
  * Sends all the events from the queue to the API.
262
+ *
263
+ * @return array|bool Information about the dequeue process.
264
  */
265
  public static function sendLogsFromQueue()
266
  {
267
  if (SucuriScanOption::isDisabled(':api_service')) {
268
+ return false;
269
  }
270
 
271
  $cache = new SucuriScanCache('auditqueue');
272
  $finfo = $cache->getDatastoreInfo();
273
  $events = $cache->getAll();
 
274
 
275
  if (!$events) {
276
+ return false;
277
  }
278
 
279
+ $result = array(
280
+ 'maxtime' => -1,
281
+ 'ttllogs' => 0,
282
+ 'success' => 0,
283
+ 'failure' => 0,
284
+ 'elapsed' => 0,
285
+ );
286
+
287
+ /**
288
+ * Send logs to the API with a limit.
289
+ *
290
+ * We will use the maximum execution time setting to limit the number of
291
+ * logs that the plugin will try to send to the API service before the
292
+ * server times out. In a regular installation, the limit is set to 30
293
+ * seconds, since the timeout for the HTTP request is 5 seconds we will
294
+ * instruct the plugin to wait (30 secs - 5 secs) and an additional one
295
+ * second to spare processing, so in a regular installation the plugin
296
+ * will try to send as much logs as possible to the API service in less
297
+ * than 25 seconds.
298
+ */
299
  $maxtime = (int) SucuriScan::iniGet('max_execution_time');
300
+ $timeout = ($maxtime > 1) ? ($maxtime - 6) : 30;
301
+
302
+ /* record some statistics */
303
+ $startTime = microtime(true);
304
+ $result['maxtime'] = $maxtime;
305
+ $result['ttllogs'] = count($events);
306
 
307
  foreach ($events as $keyname => $message) {
308
  $offset = strpos($keyname, '_');
309
  $timestamp = substr($keyname, 0, $offset);
310
  $status = self::sendLogToAPI($message, $timestamp);
311
 
312
+ /* skip; API is busy */
313
  if ($status !== true) {
314
+ $result['failure']++;
315
+ continue;
316
  }
317
 
318
  /* dequeue event message */
319
  unset($events[$keyname]);
320
+ $result['success']++;
321
 
322
+ /* avoid gateway timeout; max execution time */
323
+ $elapsedTime = (microtime(true) - $startTime);
324
+ if ($elapsedTime >= $timeout) {
325
  break;
326
  }
327
  }
328
 
329
+ $result['elapsed'] = round(microtime(true) - $startTime, 4);
330
  $cache->override($events);
331
+
332
+ return $result;
333
  }
334
 
335
  /**
460
  {
461
  $message = strip_tags($message);
462
 
463
+ /* auto-detect the action performed: enabled */
464
+ if (strpos($message, 'enabled') !== false) {
 
 
 
 
465
  return self::reportNoticeEvent($message);
466
  }
467
 
468
+ /* auto-detect the action performed: disabled */
469
+ if (strpos($message, 'disabled') !== false) {
470
  return self::reportErrorEvent($message);
471
  }
472
 
473
  return self::reportInfoEvent($message);
474
  }
475
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
476
  /**
477
  * Send a notification to the administrator of the specified events, only if
478
  * the administrator accepted to receive alerts for this type of events.
512
 
513
  case 'failed_login':
514
  $settings_url = SucuriScanTemplate::getUrl('settings');
515
+ $content .= "\n" . sprintf(
516
+ __('FailedLoginFooter', SUCURISCAN_TEXTDOMAIN),
517
+ $settings_url,
518
+ $settings_url
519
+ );
520
  break;
521
 
522
  case 'bruteforce_attack':
654
  }
655
 
656
  /**
657
+ * Changes the WordPress secret keys.
658
+ *
659
+ * Modify the WordPress configuration file to define new secret keys from a
660
+ * new randomly generated list of strings from the official WordPress API.
661
+ * The result of the operation will be either False in case of error, or an
662
+ * array containing multiple indexes explaining the modification, among them
663
+ * you will find the old and new keys.
664
  *
665
+ * @return array|bool Array with the old and new keys, false otherwise.
666
  */
667
  public static function setNewConfigKeys()
668
  {
src/fileinfo.lib.php CHANGED
@@ -136,7 +136,10 @@ class SucuriScanFileInfo extends SucuriScan
136
  private function ignoreFolder($path)
137
  {
138
  return (bool) ($this->ignore_directories && (
139
- strpos($path, 'wp-content/backup') !== false
 
 
 
140
  || strpos($path, 'wp-content/cache') !== false
141
  || strpos($path, 'wp-content/uploads') !== false
142
  || strpos($path, 'wp-content/w3tc') !== false
@@ -206,7 +209,7 @@ class SucuriScanFileInfo extends SucuriScan
206
  $objects = new DirectoryIterator($directory);
207
  }
208
  } catch (RuntimeException $exception) {
209
- SucuriScanEvent::reportException($exception);
210
  }
211
  // @codeCoverageIgnoreEnd
212
 
@@ -314,6 +317,20 @@ class SucuriScanFileInfo extends SucuriScan
314
  */
315
  public function removeDirectoryTree($directory = '')
316
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
317
  /* force complete scan */
318
  $this->ignore_files = false;
319
  $this->skip_directories = false;
@@ -328,24 +345,10 @@ class SucuriScanFileInfo extends SucuriScan
328
  }
329
  }
330
 
331
- if (!function_exists('sucuriscanStrlenDiff')) {
332
- /**
333
- * Evaluates the difference between the length of two strings.
334
- *
335
- * @param string $a First string of characters that will be measured.
336
- * @param string $b Second string of characters that will be measured.
337
- * @return int The difference in length between the two strings.
338
- */
339
- function sucuriscanStrlenDiff($a = '', $b = '')
340
- {
341
- return strlen($b) - strlen($a);
342
- }
343
- }
344
-
345
  /* delete directories starting from the deepest level */
346
  if ($dir_tree = $this->getDirectoryTree($directory, 'directory')) {
347
  $dir_tree = array_unique($dir_tree);
348
- usort($dir_tree, 'sucuriscanStrlenDiff');
349
  foreach ($dir_tree as $dir_path) {
350
  @rmdir($dir_path);
351
  }
@@ -357,6 +360,18 @@ class SucuriScanFileInfo extends SucuriScan
357
  return (bool) !($this->getDirectoryTree($directory));
358
  }
359
 
 
 
 
 
 
 
 
 
 
 
 
 
360
  /**
361
  * Returns the content of a file.
362
  *
136
  private function ignoreFolder($path)
137
  {
138
  return (bool) ($this->ignore_directories && (
139
+ strpos($path, '/.hg') !== false
140
+ || strpos($path, '/.git') !== false
141
+ || strpos($path, '/.svn') !== false
142
+ || strpos($path, 'wp-content/backup') !== false
143
  || strpos($path, 'wp-content/cache') !== false
144
  || strpos($path, 'wp-content/uploads') !== false
145
  || strpos($path, 'wp-content/w3tc') !== false
209
  $objects = new DirectoryIterator($directory);
210
  }
211
  } catch (RuntimeException $exception) {
212
+ /* ignore failure */
213
  }
214
  // @codeCoverageIgnoreEnd
215
 
317
  */
318
  public function removeDirectoryTree($directory = '')
319
  {
320
+ $directory = realpath($directory);
321
+
322
+ if (!is_dir($directory)) {
323
+ return self::throwException('Directory does not exists');
324
+ }
325
+
326
+ if ($directory === ABSPATH . 'wp-content') {
327
+ return self::throwException('Cannot delete content directory');
328
+ }
329
+
330
+ if ($directory === ABSPATH . 'wp-content/uploads') {
331
+ return self::throwException('Cannot delete uploads directory');
332
+ }
333
+
334
  /* force complete scan */
335
  $this->ignore_files = false;
336
  $this->skip_directories = false;
345
  }
346
  }
347
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348
  /* delete directories starting from the deepest level */
349
  if ($dir_tree = $this->getDirectoryTree($directory, 'directory')) {
350
  $dir_tree = array_unique($dir_tree);
351
+ usort($dir_tree, array('SucuriScanFileInfo', 'sortByLength'));
352
  foreach ($dir_tree as $dir_path) {
353
  @rmdir($dir_path);
354
  }
360
  return (bool) !($this->getDirectoryTree($directory));
361
  }
362
 
363
+ /**
364
+ * Evaluates the difference between the length of two strings.
365
+ *
366
+ * @param string $a First string of characters that will be measured.
367
+ * @param string $b Second string of characters that will be measured.
368
+ * @return int The difference in length between the two strings.
369
+ */
370
+ public static function sortByLength($a, $b)
371
+ {
372
+ return strlen($b) - strlen($a);
373
+ }
374
+
375
  /**
376
  * Returns the content of a file.
377
  *
src/firewall.lib.php CHANGED
@@ -80,22 +80,16 @@ class SucuriScanFirewall extends SucuriScanAPI
80
 
81
  if (isset($params['k']) && isset($params['s'])) {
82
  $send_request = true;
83
- } else {
84
- $api_key = self::getKey();
85
-
86
- if ($api_key) {
87
- $send_request = true;
88
- $params['k'] = $api_key['k'];
89
- $params['s'] = $api_key['s'];
90
- }
91
  }
92
 
93
  if ($send_request) {
94
- $url = SUCURISCAN_CLOUDPROXY_API;
95
- $params[ SUCURISCAN_CLOUDPROXY_API_VERSION ] = 1;
96
  unset($params['string']);
97
-
98
- return self::apiCall($url, $method, $params);
99
  }
100
 
101
  return false;
@@ -136,8 +130,6 @@ class SucuriScanFirewall extends SucuriScanAPI
136
  'Firewall.APIKey' => '',
137
  'Firewall.APIKeyVisibility' => 'hidden',
138
  'Firewall.APIKeyFormVisibility' => 'visible',
139
- 'Firewall.SettingsVisibility' => 'hidden',
140
- 'Firewall.SettingOptions' => '',
141
  );
142
 
143
  if (SucuriScanInterface::checkNonce()) {
@@ -167,50 +159,12 @@ class SucuriScanFirewall extends SucuriScanAPI
167
  }
168
  }
169
 
170
- $api_key = self::getKey(); /* extract API key information */
171
 
172
  if ($api_key && array_key_exists('string', $api_key)) {
173
- $settings = self::settings($api_key);
174
-
175
  $params['Firewall.APIKeyVisibility'] = 'visible';
176
  $params['Firewall.APIKeyFormVisibility'] = 'hidden';
177
  $params['Firewall.APIKey'] = $api_key['string'];
178
-
179
- if ($settings) {
180
- $params['Firewall.SettingsVisibility'] = 'visible';
181
- $settings = self::settingsExplanation($settings);
182
-
183
- foreach ($settings as $option_name => $option_value) {
184
- $option_title = ucwords(str_replace('_', "\x20", $option_name));
185
-
186
- // Generate a HTML list when the option's value is an array.
187
- if (is_array($option_value)) {
188
- $css_scrollable = count($option_value) > 10 ? 'sucuriscan-list-as-table-scrollable' : '';
189
- $html_list = '<ul class="sucuriscan-list-as-table ' . $css_scrollable . '">';
190
-
191
- if (!empty($option_value)) {
192
- foreach ($option_value as $single_value) {
193
- $single_value = SucuriScan::escape($single_value);
194
- $html_list .= '<li>' . SucuriScan::escape($single_value) . '</li>';
195
- }
196
- } else {
197
- $html_list .= '<li>(' . __('NoData', SUCURISCAN_TEXTDOMAIN) . ')</li>';
198
- }
199
-
200
- $html_list .= '</ul>';
201
- $option_value = $html_list;
202
- } else {
203
- $option_value = SucuriScan::escape($option_value);
204
- }
205
-
206
- // Parse the snippet template and replace the pseudo-variables.
207
- $params['Firewall.SettingOptions']
208
- .= SucuriScanTemplate::getSnippet('firewall-settings', array(
209
- 'Firewall.OptionName' => $option_title,
210
- 'Firewall.OptionValue' => $option_value,
211
- ));
212
- }
213
- }
214
  }
215
 
216
  return SucuriScanTemplate::getSection('firewall-settings', $params);
@@ -226,6 +180,10 @@ class SucuriScanFirewall extends SucuriScanAPI
226
  */
227
  public static function settingsExplanation($settings = array())
228
  {
 
 
 
 
229
  $cache_modes = array(
230
  'docache' => __('FirewallDoCache', SUCURISCAN_TEXTDOMAIN),
231
  'sitecache' => __('FirewallSiteCache', SUCURISCAN_TEXTDOMAIN),
@@ -233,9 +191,6 @@ class SucuriScanFirewall extends SucuriScanAPI
233
  'nocacheatall' => __('FirewallNoCacheAtAll', SUCURISCAN_TEXTDOMAIN),
234
  );
235
 
236
- // TODO: Prefer Array over stdClass, modify the API library.
237
- $settings = @json_decode(json_encode($settings), true);
238
-
239
  foreach ($settings as $keyname => $value) {
240
  if ($keyname == 'proxy_active') {
241
  $settings[$keyname] = ($value === 1)
@@ -253,6 +208,45 @@ class SucuriScanFirewall extends SucuriScanAPI
253
  return $settings;
254
  }
255
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
256
  /**
257
  * Retrieve the audit logs of the account associated with the API keys
258
  * registered b the administrator of the site. This method will send a HTTP
@@ -300,7 +294,7 @@ class SucuriScanFirewall extends SucuriScanAPI
300
  $params = array();
301
 
302
  /* logs are available after 24 hours */
303
- $date = date('Y-m-d', strtotime('-1 day'));
304
 
305
  $params['AuditLogs.DateYears'] = self::dates('years', $date);
306
  $params['AuditLogs.DateMonths'] = self::dates('months', $date);
@@ -325,41 +319,49 @@ class SucuriScanFirewall extends SucuriScanAPI
325
  return;
326
  }
327
 
328
- $response = ''; /* HTML code response */
 
329
 
330
- if ($api_key = self::getKey()) {
331
- $query = SucuriScanRequest::post(':query');
332
- $month = SucuriScanRequest::post(':month');
333
- $year = SucuriScanRequest::post(':year');
334
- $day = SucuriScanRequest::post(':day');
335
- $limit = 50;
336
- $offset = 1;
337
-
338
- if ($year && $month && $day) {
339
- $date = sprintf('%s-%s-%s', $year, $month, $day);
340
- } else {
341
- $date = date('Y-m-d');
342
- }
343
 
344
- $auditlogs = self::auditlogs(
345
- $api_key,
346
- $date, /* Retrieve the data from this date. */
347
- $query, /* Filter the data to match this query. */
348
- $limit, /* Retrieve this maximum of data. */
349
- $offset /* Retrieve the data from this point. */
350
- );
351
 
352
- if ($auditlogs && array_key_exists('total_lines', $auditlogs)) {
353
- $response = self::auditlogsEntries($auditlogs['access_logs']);
 
 
 
354
 
355
- if (empty($response)) {
356
- $response = '<tr><td>' . __('NoData', SUCURISCAN_TEXTDOMAIN) . '.</td></tr>';
357
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
358
  }
359
- } else {
360
- ob_start();
361
- SucuriScanInterface::error(__('FirewallAPIKeyMissing', SUCURISCAN_TEXTDOMAIN));
362
- $response = ob_get_clean();
363
  }
364
 
365
  wp_send_json($response, 200);
@@ -453,10 +455,11 @@ class SucuriScanFirewall extends SucuriScanAPI
453
  switch ($type) {
454
  case 'years':
455
  $selected = $s_year;
456
- $current_year = (int) date('Y');
457
  $max_years = 5; /* Maximum number of years to keep the logs. */
458
  $options = range(($current_year - $max_years), $current_year);
459
  break;
 
460
  case 'months':
461
  $selected = $s_month;
462
  $options = array(
@@ -474,6 +477,7 @@ class SucuriScanFirewall extends SucuriScanAPI
474
  '12' => __('December', SUCURISCAN_TEXTDOMAIN),
475
  );
476
  break;
 
477
  case 'days':
478
  $options = range(1, 31);
479
  $selected = $s_day;
@@ -502,6 +506,133 @@ class SucuriScanFirewall extends SucuriScanAPI
502
  return $options;
503
  }
504
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
505
  /**
506
  * Flush the cache of the site(s) associated with the API key.
507
  *
@@ -532,23 +663,9 @@ class SucuriScanFirewall extends SucuriScanAPI
532
  {
533
  $params = array();
534
 
535
- /* flush the cache of the site(s) associated with the API key. */
536
- if (SucuriScanInterface::checkNonce() && SucuriScanRequest::post(':clear_cache')) {
537
- $response = self::clearCache();
538
-
539
- if (!$response) {
540
- SucuriScanInterface::error(__('FirewallNotEnabled', SUCURISCAN_TEXTDOMAIN));
541
- } elseif (!isset($response['messages'][0])) {
542
- SucuriScanInterface::error(__('FirewallClearCacheFailure', SUCURISCAN_TEXTDOMAIN));
543
- } else {
544
- // Clear W3 Total Cache if it is installed.
545
- if (function_exists('w3tc_flush_all')) {
546
- w3tc_flush_all();
547
- }
548
-
549
- SucuriScanInterface::info($response['messages'][0]);
550
- }
551
- }
552
 
553
  return SucuriScanTemplate::getSection('firewall-clearcache', $params);
554
  }
@@ -562,13 +679,68 @@ class SucuriScanFirewall extends SucuriScanAPI
562
  * of certain files is going to stay as it is due to the configuration on the
563
  * edge of the servers.
564
  *
565
- * @param int $post_id The post ID.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
566
  */
567
- public static function clearCacheHook($post_id = 0)
568
  {
569
- /* prevent double execution of the save_post action */
570
- if (!wp_is_post_revision($post_id) && !wp_is_post_autosave($post_id)) {
571
- self::clearCache(); /* ignore HTTP request errors */
 
 
 
 
 
 
 
 
 
572
  }
 
 
573
  }
574
  }
80
 
81
  if (isset($params['k']) && isset($params['s'])) {
82
  $send_request = true;
83
+ } elseif ($api_key = self::getKey()) {
84
+ $send_request = true;
85
+ $params['k'] = $api_key['k'];
86
+ $params['s'] = $api_key['s'];
 
 
 
 
87
  }
88
 
89
  if ($send_request) {
 
 
90
  unset($params['string']);
91
+ $params[SUCURISCAN_CLOUDPROXY_API_VERSION] = 1;
92
+ return self::apiCall(SUCURISCAN_CLOUDPROXY_API, $method, $params);
93
  }
94
 
95
  return false;
130
  'Firewall.APIKey' => '',
131
  'Firewall.APIKeyVisibility' => 'hidden',
132
  'Firewall.APIKeyFormVisibility' => 'visible',
 
 
133
  );
134
 
135
  if (SucuriScanInterface::checkNonce()) {
159
  }
160
  }
161
 
162
+ $api_key = self::getKey();
163
 
164
  if ($api_key && array_key_exists('string', $api_key)) {
 
 
165
  $params['Firewall.APIKeyVisibility'] = 'visible';
166
  $params['Firewall.APIKeyFormVisibility'] = 'hidden';
167
  $params['Firewall.APIKey'] = $api_key['string'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  }
169
 
170
  return SucuriScanTemplate::getSection('firewall-settings', $params);
180
  */
181
  public static function settingsExplanation($settings = array())
182
  {
183
+ if (!is_array($settings)) {
184
+ return array(/* empty */);
185
+ }
186
+
187
  $cache_modes = array(
188
  'docache' => __('FirewallDoCache', SUCURISCAN_TEXTDOMAIN),
189
  'sitecache' => __('FirewallSiteCache', SUCURISCAN_TEXTDOMAIN),
191
  'nocacheatall' => __('FirewallNoCacheAtAll', SUCURISCAN_TEXTDOMAIN),
192
  );
193
 
 
 
 
194
  foreach ($settings as $keyname => $value) {
195
  if ($keyname == 'proxy_active') {
196
  $settings[$keyname] = ($value === 1)
208
  return $settings;
209
  }
210
 
211
+ /**
212
+ * Returns the public firewall settings.
213
+ *
214
+ * @codeCoverageIgnore
215
+ */
216
+ public static function getSettingsAjax()
217
+ {
218
+ if (SucuriScanRequest::post('form_action') !== 'firewall_settings') {
219
+ return;
220
+ }
221
+
222
+ $response = array();
223
+ $response['ok'] = false;
224
+ $api_key = self::getKey();
225
+
226
+ ob_start();
227
+ $settings = self::settings($api_key);
228
+ $error = ob_get_clean();
229
+
230
+ if (!$settings) {
231
+ if (empty($error)) {
232
+ ob_start();
233
+ SucuriScanInterface::error(__('FirewallAPIKeyMissing', SUCURISCAN_TEXTDOMAIN));
234
+ $response['error'] = ob_get_clean();
235
+ } else {
236
+ $response['error'] = $error;
237
+ }
238
+
239
+ wp_send_json($response, 200);
240
+ }
241
+
242
+ $response['ok'] = true;
243
+ $response['settings'] = self::settingsExplanation($settings);
244
+ unset($response['settings']['whitelist_list']);
245
+ unset($response['settings']['blacklist_list']);
246
+
247
+ wp_send_json($response, 200);
248
+ }
249
+
250
  /**
251
  * Retrieve the audit logs of the account associated with the API keys
252
  * registered b the administrator of the site. This method will send a HTTP
294
  $params = array();
295
 
296
  /* logs are available after 24 hours */
297
+ $date = SucuriScan::datetime(strtotime('-1 day'), 'Y-m-d');
298
 
299
  $params['AuditLogs.DateYears'] = self::dates('years', $date);
300
  $params['AuditLogs.DateMonths'] = self::dates('months', $date);
319
  return;
320
  }
321
 
322
+ $response = '';
323
+ $api_key = self::getKey();
324
 
325
+ if (!$api_key) {
326
+ ob_start();
327
+ SucuriScanInterface::error(__('FirewallAPIKeyMissing', SUCURISCAN_TEXTDOMAIN));
328
+ $response = ob_get_clean();
329
+ wp_send_json($response, 200);
330
+ }
 
 
 
 
 
 
 
331
 
332
+ $query = SucuriScanRequest::post(':query');
333
+ $month = SucuriScanRequest::post(':month');
334
+ $year = SucuriScanRequest::post(':year');
335
+ $day = SucuriScanRequest::post(':day');
336
+ $limit = 50;
337
+ $offset = 1;
 
338
 
339
+ if ($year && $month && $day) {
340
+ $date = sprintf('%s-%s-%s', $year, $month, $day);
341
+ } else {
342
+ $date = SucuriScan::datetime(null, 'Y-m-d');
343
+ }
344
 
345
+ ob_start();
346
+ $auditlogs = self::auditlogs(
347
+ $api_key,
348
+ $date, /* Retrieve the data from this date. */
349
+ $query, /* Filter the data to match this query. */
350
+ $limit, /* Retrieve this maximum of data. */
351
+ $offset /* Retrieve the data from this point. */
352
+ );
353
+ $error = ob_get_clean();
354
+
355
+ if (!$auditlogs && !empty($error)) {
356
+ wp_send_json($error, 200);
357
+ }
358
+
359
+ if ($auditlogs && array_key_exists('total_lines', $auditlogs)) {
360
+ $response = self::auditlogsEntries($auditlogs['access_logs']);
361
+
362
+ if (empty($response)) {
363
+ $response = '<tr><td>' . __('NoData', SUCURISCAN_TEXTDOMAIN) . '.</td></tr>';
364
  }
 
 
 
 
365
  }
366
 
367
  wp_send_json($response, 200);
455
  switch ($type) {
456
  case 'years':
457
  $selected = $s_year;
458
+ $current_year = (int) SucuriScan::datetime(null, 'Y');
459
  $max_years = 5; /* Maximum number of years to keep the logs. */
460
  $options = range(($current_year - $max_years), $current_year);
461
  break;
462
+
463
  case 'months':
464
  $selected = $s_month;
465
  $options = array(
477
  '12' => __('December', SUCURISCAN_TEXTDOMAIN),
478
  );
479
  break;
480
+
481
  case 'days':
482
  $options = range(1, 31);
483
  $selected = $s_day;
506
  return $options;
507
  }
508
 
509
+ /**
510
+ * Generate the HTML code for the firewall IP access panel.
511
+ *
512
+ * @return string The parsed-content of the firewall IP access panel.
513
+ */
514
+ public static function ipAccessPage()
515
+ {
516
+ $params = array();
517
+
518
+ return SucuriScanTemplate::getSection('firewall-ipaccess', $params);
519
+ }
520
+
521
+ /**
522
+ * Returns the whitelisted and blacklisted IP addresses.
523
+ *
524
+ * @codeCoverageIgnore
525
+ */
526
+ public static function ipAccessAjax()
527
+ {
528
+ if (SucuriScanRequest::post('form_action') !== 'firewall_ipaccess') {
529
+ return;
530
+ }
531
+
532
+ $response = array();
533
+ $response['ok'] = false;
534
+ $api_key = self::getKey();
535
+
536
+ ob_start();
537
+ $settings = self::settings($api_key);
538
+ $error = ob_get_clean();
539
+
540
+ if (!$settings) {
541
+ if (empty($error)) {
542
+ ob_start();
543
+ SucuriScanInterface::error(__('FirewallAPIKeyMissing', SUCURISCAN_TEXTDOMAIN));
544
+ $response['error'] = ob_get_clean();
545
+ } else {
546
+ $response['error'] = $error;
547
+ }
548
+
549
+ wp_send_json($response, 200);
550
+ }
551
+
552
+ $response['ok'] = true;
553
+ $response['whitelist'] = $settings['whitelist_list'];
554
+ $response['blacklist'] = $settings['blacklist_list'];
555
+
556
+ wp_send_json($response, 200);
557
+ }
558
+
559
+ /**
560
+ * Blacklists an IP address.
561
+ *
562
+ * @codeCoverageIgnore
563
+ */
564
+ public static function blacklistAjax()
565
+ {
566
+ if (SucuriScanRequest::post('form_action') !== 'firewall_blacklist') {
567
+ return;
568
+ }
569
+
570
+ $response = array();
571
+ $response['ok'] = false;
572
+ $params = self::getKey();
573
+
574
+ if (!$params) {
575
+ ob_start();
576
+ SucuriScanInterface::error(__('FirewallAPIKeyMissing', SUCURISCAN_TEXTDOMAIN));
577
+ $response['msg'] = ob_get_clean();
578
+ wp_send_json($response, 200);
579
+ }
580
+
581
+ $params['a'] = 'blacklist_ip';
582
+ $params['ip'] = SucuriScanRequest::post('ip');
583
+ $out = self::apiCallFirewall('POST', $params);
584
+ $response['msg'] = 'Failure connecting to the API service; try again.';
585
+
586
+ if ($out && !empty($out['messages'])) {
587
+ $response['ok'] = (bool) ($out['status'] == 1);
588
+ $response['msg'] = implode(";\x20", $out['messages']);
589
+
590
+ if ($out['status'] == 1) {
591
+ SucuriScanEvent::reportInfoEvent(
592
+ 'IP has been blacklisted: ' . $params['ip']);
593
+ }
594
+ }
595
+
596
+ wp_send_json($response, 200);
597
+ }
598
+
599
+ /**
600
+ * Deletes an IP address from the blacklist.
601
+ *
602
+ * @codeCoverageIgnore
603
+ */
604
+ public static function deblacklistAjax()
605
+ {
606
+ if (SucuriScanRequest::post('form_action') !== 'firewall_deblacklist') {
607
+ return;
608
+ }
609
+
610
+ $response = array();
611
+ $params = self::getKey();
612
+
613
+ if (!$params) {
614
+ ob_start();
615
+ $response['ok'] = false;
616
+ SucuriScanInterface::error(__('FirewallAPIKeyMissing', SUCURISCAN_TEXTDOMAIN));
617
+ $response['error'] = ob_get_clean();
618
+ wp_send_json($response, 200);
619
+ }
620
+
621
+ $params['a'] = 'delete_blacklist_ip';
622
+ $params['ip'] = SucuriScanRequest::post('ip');
623
+ $out = self::apiCallFirewall('POST', $params);
624
+
625
+ $response['ok'] = (bool) ($out['status'] == 1);
626
+ $response['msg'] = implode(";\x20", $out['messages']);
627
+
628
+ if ($out['status'] == 1) {
629
+ SucuriScanEvent::reportInfoEvent(
630
+ 'IP has been unblacklisted: ' . $params['ip']);
631
+ }
632
+
633
+ wp_send_json($response, 200);
634
+ }
635
+
636
  /**
637
  * Flush the cache of the site(s) associated with the API key.
638
  *
663
  {
664
  $params = array();
665
 
666
+ $params['FirewallAutoClearCache'] =
667
+ SucuriScanOption::isEnabled(':auto_clear_cache')
668
+ ? 'checked="checked"' : 'data-status="disabled"';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
669
 
670
  return SucuriScanTemplate::getSection('firewall-clearcache', $params);
671
  }
679
  * of certain files is going to stay as it is due to the configuration on the
680
  * edge of the servers.
681
  *
682
+ * @param array $data The post metadata.
683
+ */
684
+ public static function clearCacheHook($data)
685
+ {
686
+ if (SucuriScanOption::isEnabled(':auto_clear_cache')) {
687
+ ob_start();
688
+ self::clearCache();
689
+ $error = ob_get_clean();
690
+ }
691
+ }
692
+
693
+ /**
694
+ * Requests a cache flush to the firewall service.
695
+ *
696
+ * @codeCoverageIgnore
697
+ */
698
+ public static function clearCacheAjax()
699
+ {
700
+ if (SucuriScanRequest::post('form_action') !== 'firewall_clear_cache') {
701
+ return;
702
+ }
703
+
704
+ ob_start();
705
+ SucuriScanInterface::error(__('FirewallAPIKeyMissing', SUCURISCAN_TEXTDOMAIN));
706
+ $response = ob_get_clean();
707
+
708
+ if ($api_key = self::getKey()) {
709
+ $res = self::clearCache($api_key);
710
+
711
+ if (is_array($res) && isset($res['messages'])) {
712
+ $response = sprintf(
713
+ '<div class="sucuriscan-inline-alert-%s"><p>%s</p></div>',
714
+ ($res['status'] == 1) ? 'success' : 'error',
715
+ implode('<br>', $res['messages'])
716
+ );
717
+ }
718
+ }
719
+
720
+ wp_send_json($response, 200);
721
+ }
722
+
723
+ /**
724
+ * Configures the status of the automatic cache flush.
725
+ *
726
+ * @codeCoverageIgnore
727
  */
728
+ public static function clearAutoCacheAjax()
729
  {
730
+ if (SucuriScanRequest::post('form_action') !== 'firewall_auto_clear_cache') {
731
+ return;
732
+ }
733
+
734
+ $response = array();
735
+
736
+ if (SucuriScanRequest::post('auto_clear_cache') === 'enable') {
737
+ $response['ok'] = SucuriScanOption::updateOption(':auto_clear_cache', 'enabled');
738
+ $response['status'] = 'enabled';
739
+ } else {
740
+ $response['ok'] = SucuriScanOption::deleteOption(':auto_clear_cache');
741
+ $response['status'] = 'disabled';
742
  }
743
+
744
+ wp_send_json($response, 200);
745
  }
746
  }
src/fsscanner.lib.php CHANGED
@@ -60,7 +60,7 @@ class SucuriScanFSScanner extends SucuriScan
60
  $resource_type = SucuriScanFileInfo::getResourceType($path);
61
  $cache_value = array(
62
  'directory_path' => $path,
63
- 'ignored_at' => self::localTime(),
64
  'resource_type' => $resource_type,
65
  );
66
 
60
  $resource_type = SucuriScanFileInfo::getResourceType($path);
61
  $cache_value = array(
62
  'directory_path' => $path,
63
+ 'ignored_at' => time(),
64
  'resource_type' => $resource_type,
65
  );
66
 
src/globals.php CHANGED
@@ -36,20 +36,6 @@ if (defined('SUCURISCAN')) {
36
  */
37
  $sucuriscan_action_prefix = SucuriScan::isMultiSite() ? 'network_' : '';
38
 
39
- /**
40
- * Settings options.
41
- *
42
- * The following global variables are mostly associative arrays where the
43
- * key is linked to an option that will be stored in the database, and their
44
- * correspondent values are the description of the option. These variables
45
- * will be used in the settings page to offer the user a way to configure
46
- * the behaviour of the plugin.
47
- *
48
- * @var string
49
- */
50
- $sucuriscan_date_format = get_option('date_format');
51
- $sucuriscan_time_format = get_option('time_format');
52
-
53
  /**
54
  * Remove the WordPress generator meta-tag from the source code.
55
  */
@@ -76,7 +62,6 @@ if (defined('SUCURISCAN')) {
76
  if (SucuriScan::runAdminInit()) {
77
  add_action('admin_init', 'SucuriScanInterface::handleOldPlugins');
78
  add_action('admin_init', 'SucuriScanInterface::createStorageFolder');
79
- add_action('admin_init', 'SucuriScanInterface::noticeAfterUpdate');
80
  }
81
 
82
  /**
@@ -111,6 +96,7 @@ if (defined('SUCURISCAN')) {
111
  {
112
  global $locale;
113
 
 
114
  $pofile = sprintf(
115
  '%s/languages/%s-%s.po',
116
  SUCURISCAN_PLUGIN_PATH,
@@ -126,15 +112,37 @@ if (defined('SUCURISCAN')) {
126
 
127
  /* attempt to import the English POT file into LOCALE */
128
  if (!file_exists($pofile) || !file_exists($mofile)) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  $en_pofile = sprintf(
130
- '%s/languages/%s-en_US.po',
131
  SUCURISCAN_PLUGIN_PATH,
132
- SUCURISCAN_TEXTDOMAIN
 
133
  );
134
  $en_mofile = sprintf(
135
- '%s/languages/%s-en_US.mo',
136
  SUCURISCAN_PLUGIN_PATH,
137
- SUCURISCAN_TEXTDOMAIN
 
138
  );
139
 
140
  @copy($en_pofile, $pofile);
@@ -143,8 +151,8 @@ if (defined('SUCURISCAN')) {
143
 
144
  /* fallback to English on language import failure */
145
  if (!file_exists($pofile) || !file_exists($mofile)) {
146
- $locale = 'en_US';
147
- setlocale(LC_ALL, 'en_US');
148
  }
149
 
150
  load_plugin_textdomain(
@@ -247,15 +255,4 @@ if (defined('SUCURISCAN')) {
247
  add_action('admin_init', 'SucuriScanHook::hookWidgetDelete');
248
  }
249
  }
250
-
251
- /**
252
- * Clear the firewall cache if necessary.
253
- *
254
- * Every time a page or post is modified and saved into the database the
255
- * plugin will send a HTTP request to the firewall API service and except
256
- * that, if the API key is valid, the cache is reset. Notice that the cache
257
- * of certain files is going to stay as it is due to the configuration on the
258
- * edge of the servers.
259
- */
260
- add_action('save_post', 'SucuriScanFirewall::clearCacheHook');
261
  }
36
  */
37
  $sucuriscan_action_prefix = SucuriScan::isMultiSite() ? 'network_' : '';
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  /**
40
  * Remove the WordPress generator meta-tag from the source code.
41
  */
62
  if (SucuriScan::runAdminInit()) {
63
  add_action('admin_init', 'SucuriScanInterface::handleOldPlugins');
64
  add_action('admin_init', 'SucuriScanInterface::createStorageFolder');
 
65
  }
66
 
67
  /**
96
  {
97
  global $locale;
98
 
99
+ $default_locale = 'en_US';
100
  $pofile = sprintf(
101
  '%s/languages/%s-%s.po',
102
  SUCURISCAN_PLUGIN_PATH,
112
 
113
  /* attempt to import the English POT file into LOCALE */
114
  if (!file_exists($pofile) || !file_exists($mofile)) {
115
+ $fallback = array(
116
+ 'en_NZ' => 'en_US', /* English (New Zealand) */
117
+ 'en_CA' => 'en_US', /* English (Canada) */
118
+ 'en_ZA' => 'en_US', /* English (South Africa) */
119
+ 'en_GB' => 'en_US', /* English (UK) */
120
+ 'en_AU' => 'en_US', /* English (Australia) */
121
+ 'es_AR' => 'es_ES', /* Español de Argentina */
122
+ 'es_MX' => 'es_ES', /* Español de México */
123
+ 'es_CO' => 'es_ES', /* Español de Colombia */
124
+ 'es_GT' => 'es_ES', /* Español de Guatemala */
125
+ 'es_VE' => 'es_ES', /* Español de Venezuela */
126
+ 'es_CL' => 'es_ES', /* Español de Chile */
127
+ 'es_PE' => 'es_ES', /* Español de Perú */
128
+ );
129
+
130
+ /* try to find a similar translation */
131
+ if (array_key_exists($locale, $fallback)) {
132
+ $default_locale = $fallback[$locale];
133
+ }
134
+
135
  $en_pofile = sprintf(
136
+ '%s/languages/%s-%s.po',
137
  SUCURISCAN_PLUGIN_PATH,
138
+ SUCURISCAN_TEXTDOMAIN,
139
+ $default_locale
140
  );
141
  $en_mofile = sprintf(
142
+ '%s/languages/%s-%s.mo',
143
  SUCURISCAN_PLUGIN_PATH,
144
+ SUCURISCAN_TEXTDOMAIN,
145
+ $default_locale
146
  );
147
 
148
  @copy($en_pofile, $pofile);
151
 
152
  /* fallback to English on language import failure */
153
  if (!file_exists($pofile) || !file_exists($mofile)) {
154
+ $locale = $default_locale;
155
+ setlocale(LC_ALL, $default_locale);
156
  }
157
 
158
  load_plugin_textdomain(
255
  add_action('admin_init', 'SucuriScanHook::hookWidgetDelete');
256
  }
257
  }
 
 
 
 
 
 
 
 
 
 
 
258
  }
src/hook.lib.php CHANGED
@@ -151,15 +151,20 @@ class SucuriScanHook extends SucuriScanEvent
151
  {
152
  $password = SucuriScanRequest::post('pwd');
153
  $title = empty($title) ? 'Unknown' : sanitize_user($title, true);
154
- $message = 'User authentication failed: ' . $title . '; password: ' . $password;
 
 
 
 
 
 
 
 
155
 
156
  self::reportErrorEvent($message);
157
 
158
  self::notifyEvent('failed_login', $message);
159
 
160
- /* log the failed login in the internal storage */
161
- sucuriscan_log_failed_login($title, $password);
162
-
163
  /* report brute-force attack if necessary */
164
  if ($logins = sucuriscan_get_failed_logins()) {
165
  $max_time = 3600; /* report logins in the last hour */
@@ -281,7 +286,7 @@ class SucuriScanHook extends SucuriScanEvent
281
 
282
  if ($options_changed_count) {
283
  $message = $page_referer . ' settings changed';
284
- SucuriScanEvent::reportErrorEvent(sprintf(
285
  '%s: (multiple entries): %s',
286
  $message,
287
  rtrim($options_changed_simple, ',')
@@ -443,7 +448,7 @@ class SucuriScanHook extends SucuriScanEvent
443
 
444
  $plugin = $plugin ? $plugin : 'Unknown';
445
  $message = 'Plugin installed: ' . self::escape($plugin);
446
- SucuriScanEvent::reportWarningEvent($message);
447
  self::notifyEvent('plugin_installed', $message);
448
  }
449
  }
@@ -577,7 +582,7 @@ class SucuriScanHook extends SucuriScanEvent
577
 
578
  /* ignore; the same */
579
  if ($old === $new) {
580
- return;
581
  }
582
 
583
  $post_type = 'post'; /* either post or page */
@@ -586,11 +591,35 @@ class SucuriScanHook extends SucuriScanEvent
586
  $post_type = $post->post_type;
587
  }
588
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
589
  /* check if email alerts are disabled for this type */
590
  if (SucuriScanOption::isIgnoredEvent($post_type)) {
591
  return self::throwException('Skip events for ignored post-types');
592
  }
593
 
 
 
 
 
 
 
594
  $pieces = array();
595
  $post_type = ucwords($post_type);
596
 
@@ -654,6 +683,8 @@ class SucuriScanHook extends SucuriScanEvent
654
  if ($data->post_date === $data->post_modified) {
655
  $action = 'created';
656
  }
 
 
657
  }
658
 
659
  $message = sprintf(
@@ -734,7 +765,7 @@ class SucuriScanHook extends SucuriScanEvent
734
  $theme = $theme ? $theme : 'Unknown';
735
 
736
  $message = 'Theme deleted: ' . self::escape($theme);
737
- SucuriScanEvent::reportWarningEvent($message);
738
  self::notifyEvent('theme_deleted', $message);
739
  }
740
  }
@@ -772,7 +803,7 @@ class SucuriScanHook extends SucuriScanEvent
772
  $theme = $theme ? $theme : 'Unknown';
773
 
774
  $message = 'Theme installed: ' . self::escape($theme);
775
- SucuriScanEvent::reportWarningEvent($message);
776
  self::notifyEvent('theme_installed', $message);
777
  }
778
  }
151
  {
152
  $password = SucuriScanRequest::post('pwd');
153
  $title = empty($title) ? 'Unknown' : sanitize_user($title, true);
154
+ $message = 'User authentication failed: ' . $title;
155
+
156
+ /* send the submitted password along with the alert */
157
+ if (SucuriScanOption::isEnabled(':notify_failed_password')) {
158
+ $message .= '; password: ' . $password;
159
+ sucuriscan_log_failed_login($title, $password);
160
+ } else {
161
+ sucuriscan_log_failed_login($title, '[hidden]');
162
+ }
163
 
164
  self::reportErrorEvent($message);
165
 
166
  self::notifyEvent('failed_login', $message);
167
 
 
 
 
168
  /* report brute-force attack if necessary */
169
  if ($logins = sucuriscan_get_failed_logins()) {
170
  $max_time = 3600; /* report logins in the last hour */
286
 
287
  if ($options_changed_count) {
288
  $message = $page_referer . ' settings changed';
289
+ self::reportErrorEvent(sprintf(
290
  '%s: (multiple entries): %s',
291
  $message,
292
  rtrim($options_changed_simple, ',')
448
 
449
  $plugin = $plugin ? $plugin : 'Unknown';
450
  $message = 'Plugin installed: ' . self::escape($plugin);
451
+ self::reportWarningEvent($message);
452
  self::notifyEvent('plugin_installed', $message);
453
  }
454
  }
582
 
583
  /* ignore; the same */
584
  if ($old === $new) {
585
+ return self::throwException('Skip events for equal transitions');
586
  }
587
 
588
  $post_type = 'post'; /* either post or page */
591
  $post_type = $post->post_type;
592
  }
593
 
594
+ if ($post_type === 'postman_sent_mail') {
595
+ /**
596
+ * Stop infinite loop sending the email alerts.
597
+ *
598
+ * The plugin detects changes in the posts, there are some other
599
+ * plugins that intercept PHPMailer and create a post object that is
600
+ * later used to send the real message to the users. This object is
601
+ * also detected by our plugin and is considered an additional event
602
+ * that must be reported, so after the first execution the operation
603
+ * falls into an infinite loop.
604
+ *
605
+ * @date 30 June, 2017
606
+ * @see https://wordpress.org/plugins/postman-smtp/
607
+ * @see https://wordpress.org/support/topic/unable-to-access-wordpress-dashboard-after-update-to-1-8-7/
608
+ */
609
+ return self::throwException('Skip events for postman-smtp alerts');
610
+ }
611
+
612
  /* check if email alerts are disabled for this type */
613
  if (SucuriScanOption::isIgnoredEvent($post_type)) {
614
  return self::throwException('Skip events for ignored post-types');
615
  }
616
 
617
+ /* check if email alerts are disabled for this transition */
618
+ $custom_type = sprintf('from_%s_to_%s', $old, $new);
619
+ if (SucuriScanOption::isIgnoredEvent($custom_type)) {
620
+ return self::throwException('Skip events for ignored post transitions');
621
+ }
622
+
623
  $pieces = array();
624
  $post_type = ucwords($post_type);
625
 
683
  if ($data->post_date === $data->post_modified) {
684
  $action = 'created';
685
  }
686
+
687
+ SucuriScanFirewall::clearCacheHook($data);
688
  }
689
 
690
  $message = sprintf(
765
  $theme = $theme ? $theme : 'Unknown';
766
 
767
  $message = 'Theme deleted: ' . self::escape($theme);
768
+ self::reportWarningEvent($message);
769
  self::notifyEvent('theme_deleted', $message);
770
  }
771
  }
803
  $theme = $theme ? $theme : 'Unknown';
804
 
805
  $message = 'Theme installed: ' . self::escape($theme);
806
+ self::reportWarningEvent($message);
807
  self::notifyEvent('theme_installed', $message);
808
  }
809
  }
src/integrity.lib.php CHANGED
@@ -117,57 +117,76 @@ class SucuriScanIntegrity
117
  return SucuriScanInterface::error(__('NothingSelected', SUCURISCAN_TEXTDOMAIN));
118
  }
119
 
 
 
 
 
 
 
120
  foreach ((array) $core_files as $file_meta) {
121
- if (strpos($file_meta, '@')) {
122
- @list($status_type, $file_path) = explode('@', $file_meta, 2);
 
123
 
124
- if (!$file_path || !$status_type) {
125
- continue;
126
- }
 
 
 
127
 
128
- $full_path = ABSPATH . '/' . $file_path;
129
-
130
- if ($action === 'fixed' && (
131
- $status_type === 'added'
132
- || $status_type === 'removed'
133
- || $status_type === 'modified'
134
- )) {
135
- $cache_key = md5($file_path);
136
- $cache_value = array(
137
- 'file_path' => $file_path,
138
- 'file_status' => $status_type,
139
- 'ignored_at' => time(),
140
- );
141
- $cached = $cache->add($cache_key, $cache_value);
142
- $files_processed += ($cached ? 1 : 0);
 
 
 
 
 
 
143
  $files_affected[] = $full_path;
144
- continue;
145
  }
 
 
146
 
147
- if ($action === 'restore' && (
148
- $status_type === 'removed'
149
- || $status_type === 'modified'
150
- )) {
151
- if ($content = SucuriScanAPI::getOriginalCoreFile($file_path)) {
152
- $basedir = dirname($full_path);
153
- @mkdir($basedir, 0755, true);
154
 
155
- if (file_exists($basedir)) {
156
- $restored = @file_put_contents($full_path, $content);
157
- $files_processed += ($restored ? 1 : 0);
158
- $files_affected[] = $full_path;
159
- }
160
  }
161
- continue;
162
- }
163
 
164
- if ($action === 'delete' && $status_type === 'added') {
165
- if (@unlink($full_path)) {
166
- $files_processed += 1;
167
  $files_affected[] = $full_path;
 
168
  }
169
- continue;
170
  }
 
 
 
 
 
 
 
 
 
171
  }
172
  }
173
 
@@ -197,6 +216,10 @@ class SucuriScanIntegrity
197
  }
198
  }
199
 
 
 
 
 
200
  if ($files_processed != $files_selected) {
201
  return SucuriScanInterface::error(sprintf(
202
  __('SomeItemsProcessed', SUCURISCAN_TEXTDOMAIN),
@@ -231,7 +254,6 @@ class SucuriScanIntegrity
231
  {
232
  $params = array();
233
  $affected_files = 0;
234
- $siteVersion = SucuriScan::siteVersion();
235
 
236
  $params['Version'] = SucuriScan::siteVersion();
237
  $params['Integrity.List'] = '';
@@ -241,91 +263,84 @@ class SucuriScanIntegrity
241
  $params['Integrity.GoodVisibility'] = 'hidden';
242
  $params['Integrity.FailureVisibility'] = 'visible';
243
  $params['Integrity.FalsePositivesVisibility'] = 'hidden';
 
 
 
 
 
244
 
245
- /* Check if we have already ignored irrelevant files */
246
- self::ignoreIrrelevantFiles();
 
 
247
 
248
- if ($siteVersion) {
249
- // Check if there are added, removed, or modified files.
250
- $latest_hashes = self::checkIntegrityIntegrity($siteVersion);
251
- $language = SucuriScanOption::getOption(':language');
252
- $params['Integrity.RemoteChecksumsURL'] =
253
- 'https://api.wordpress.org/core/checksums/1.0/'
254
- . '?version=' . $siteVersion . '&locale=' . $language;
255
 
256
- if ($latest_hashes) {
257
- $cache = new SucuriScanCache('integrity');
258
- $ignored_files = $cache->getAll();
259
- $counter = 0;
260
 
261
- $params['Integrity.BadVisibility'] = 'hidden';
262
- $params['Integrity.GoodVisibility'] = 'visible';
263
- $params['Integrity.FailureVisibility'] = 'hidden';
264
 
265
- foreach ($latest_hashes as $list_type => $file_list) {
266
- if ($list_type == 'stable' || empty($file_list)) {
 
 
267
  continue;
268
  }
269
 
270
- foreach ($file_list as $file_info) {
271
- $file_path = $file_info['filepath'];
272
- $full_filepath = sprintf('%s/%s', rtrim(ABSPATH, '/'), $file_path);
273
-
274
- if ($ignored_files /* skip files marked as fixed */
275
- && array_key_exists(md5($file_path), $ignored_files)
276
- ) {
277
- $params['Integrity.FalsePositivesVisibility'] = 'visible';
278
- continue;
279
- }
280
-
281
- // Add extra information to the file list.
282
- $file_size = @filesize($full_filepath);
283
- $file_size_human = ''; /* empty */
284
 
285
- /* error message if the file cannot be fixed */
286
- $error = '';
287
- $visibility = 'hidden';
288
 
289
- if ($file_info['is_fixable'] !== true) {
290
- $visibility = 'visible';
291
 
292
- if ($list_type === 'added') {
293
- $error = __('ErrorIntegrityAdded', SUCURISCAN_TEXTDOMAIN);
294
- } elseif ($list_type === 'modified') {
295
- $error = __('ErrorIntegrityModified', SUCURISCAN_TEXTDOMAIN);
296
- } elseif ($list_type === 'removed') {
297
- $error = __('ErrorIntegrityRemoved', SUCURISCAN_TEXTDOMAIN);
298
- }
299
- }
300
-
301
- // Pretty-print the file size in human-readable form.
302
- if ($file_size !== false) {
303
- $file_size_human = SucuriScan::humanFileSize($file_size);
304
  }
 
305
 
306
- // Generate the HTML code from the snippet template for this file.
307
- $params['Integrity.List'] .=
308
- SucuriScanTemplate::getSnippet('integrity-incorrect', array(
309
- 'Integrity.StatusType' => $list_type,
310
- 'Integrity.FilePath' => $file_path,
311
- 'Integrity.FileSize' => $file_size,
312
- 'Integrity.FileSizeHuman' => $file_size_human,
313
- 'Integrity.FileSizeNumber' => number_format($file_size),
314
- 'Integrity.ModifiedAt' => SucuriScan::datetime($file_info['modified_at']),
315
- 'Integrity.ErrorVisibility' => $visibility,
316
- 'Integrity.ErrorMessage' => $error,
317
- ));
318
- $affected_files++;
319
- $counter++;
320
  }
321
- }
322
 
323
- if ($counter > 0) {
324
- $params['Integrity.ListCount'] = $counter;
325
- $params['Integrity.BadVisibility'] = 'visible';
326
- $params['Integrity.GoodVisibility'] = 'hidden';
 
 
 
 
 
 
 
 
 
 
327
  }
328
  }
 
 
 
 
 
 
329
  }
330
 
331
  if ($send_email === true) {
@@ -398,11 +413,9 @@ class SucuriScanIntegrity
398
  return;
399
  }
400
 
401
- $version = SucuriScan::siteVersion();
402
- $filepath = SucuriScanRequest::post('filepath');
403
-
404
  ob_start();
405
- print(SucuriScanCommand::diffHTML($filepath, $version));
 
406
  $response = ob_get_clean();
407
 
408
  wp_send_json($response, 200);
@@ -440,12 +453,11 @@ class SucuriScanIntegrity
440
  * <li>added: Files present in the local project but not in the official WordPress packages.</li>
441
  * </ul>
442
  *
443
- * @param string|int $version Valid version number of the WordPress project.
444
  * @return array|bool Associative array with these keys: modified, stable, removed, added.
445
  */
446
- private static function checkIntegrityIntegrity($version = 0)
447
  {
448
- $latest_hashes = SucuriScanAPI::getOfficialChecksums($version);
449
  $base_content_dir = defined('WP_CONTENT_DIR')
450
  ? basename(rtrim(WP_CONTENT_DIR, '/'))
451
  : '';
@@ -468,6 +480,7 @@ class SucuriScanIntegrity
468
  $wp_admin_hashes = self::integrityTree(ABSPATH . 'wp-admin', true);
469
  $wp_includes_hashes = self::integrityTree(ABSPATH . 'wp-includes', true);
470
  $wp_core_hashes = array_merge($wp_top_hashes, $wp_admin_hashes, $wp_includes_hashes);
 
471
 
472
  // Compare remote and local checksums and search removed files.
473
  foreach ($latest_hashes as $file_path => $remote) {
@@ -491,7 +504,17 @@ class SucuriScanIntegrity
491
 
492
  // Check whether the official file exists or not.
493
  if (file_exists($full_filepath)) {
494
- $local = @md5_file($full_filepath);
 
 
 
 
 
 
 
 
 
 
495
 
496
  if ($local !== false && $local === $remote) {
497
  $output['stable'][] = array(
@@ -550,10 +573,69 @@ class SucuriScanIntegrity
550
  */
551
  private static function ignoreIntegrityFilepath($path = '')
552
  {
553
- // List of files that will be ignored from the integrity checking.
554
- $ignore_files = array(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
555
  '^sucuri-[0-9a-z\-]+\.php$',
556
  '^\S+-sucuri-db-dump-gzip-[0-9]{10}-[0-9a-z]{32}\.gz$',
 
557
  '^([^\/]*)\.(pdf|css|txt|jpg|gif|png|jpeg)$',
558
  '^wp-content\/(themes|plugins)\/.+',
559
  '^google[0-9a-z]{16}\.html$',
@@ -561,107 +643,13 @@ class SucuriScanIntegrity
561
  '\.ico$',
562
  );
563
 
564
- // Determine whether a file must be ignored from the integrity checks or not.
565
- foreach ($ignore_files as $ignore_pattern) {
566
- if (@preg_match('/'.$ignore_pattern.'/', $path)) {
567
- return true;
568
  }
569
  }
570
 
571
- return false;
572
- }
573
-
574
- /**
575
- * Includes some irrelevant files into the integrity cache.
576
- */
577
- private static function ignoreIrrelevantFiles()
578
- {
579
- global $wp_local_package;
580
-
581
- if (SucuriScanOption::getOption(':integrity_startup') !== 'done') {
582
- /* ignore files no matter if they do not exist */
583
- self::ignoreIrrelevantFile('php.ini', false);
584
- self::ignoreIrrelevantFile('.htaccess', false);
585
- self::ignoreIrrelevantFile('.htpasswd', false);
586
- self::ignoreIrrelevantFile('.ftpquota', false);
587
- self::ignoreIrrelevantFile('wp-includes/.htaccess', false);
588
- self::ignoreIrrelevantFile('wp-admin/setup-config.php', false);
589
- self::ignoreIrrelevantFile('wp-config.php', false);
590
- self::ignoreIrrelevantFile('sitemap.xml', false);
591
- self::ignoreIrrelevantFile('sitemap.xml.gz', false);
592
- self::ignoreIrrelevantFile('readme.html', false);
593
- self::ignoreIrrelevantFile('error_log', false);
594
-
595
- /* ignore irrelevant files only if they exist */
596
- self::ignoreIrrelevantFile('wp-pass.php');
597
- self::ignoreIrrelevantFile('wp-rss.php');
598
- self::ignoreIrrelevantFile('wp-feed.php');
599
- self::ignoreIrrelevantFile('wp-register.php');
600
- self::ignoreIrrelevantFile('wp-atom.php');
601
- self::ignoreIrrelevantFile('wp-commentsrss2.php');
602
- self::ignoreIrrelevantFile('wp-rss2.php');
603
- self::ignoreIrrelevantFile('wp-rdf.php');
604
- self::ignoreIrrelevantFile('404.php');
605
- self::ignoreIrrelevantFile('503.php');
606
- self::ignoreIrrelevantFile('500.php');
607
- self::ignoreIrrelevantFile('500.shtml');
608
- self::ignoreIrrelevantFile('400.shtml');
609
- self::ignoreIrrelevantFile('401.shtml');
610
- self::ignoreIrrelevantFile('402.shtml');
611
- self::ignoreIrrelevantFile('403.shtml');
612
- self::ignoreIrrelevantFile('404.shtml');
613
- self::ignoreIrrelevantFile('405.shtml');
614
- self::ignoreIrrelevantFile('406.shtml');
615
- self::ignoreIrrelevantFile('407.shtml');
616
- self::ignoreIrrelevantFile('408.shtml');
617
- self::ignoreIrrelevantFile('409.shtml');
618
- self::ignoreIrrelevantFile('healthcheck.html');
619
-
620
- /**
621
- * Ignore i18n files.
622
- *
623
- * Sites with i18n have differences compared with the official English version
624
- * of the project, basically they have files with new variables specifying the
625
- * language that will be used in the admin panel, site options, and emails.
626
- */
627
- if (isset($wp_local_package) && $wp_local_package != 'en_US') {
628
- self::ignoreIrrelevantFile('wp-includes/version.php');
629
- self::ignoreIrrelevantFile('wp-config-sample.php');
630
- }
631
-
632
- SucuriScanOption::updateOption(':integrity_startup', 'done');
633
- }
634
- }
635
-
636
- /**
637
- * Forces the integrity checker to ignore a file.
638
- *
639
- * The first time the WordPress integrity checker it will include some files
640
- * into a storage file that will be used to skip these files during the next
641
- * scans. This is to reduce the amount of false/positives. The website owner
642
- * is free to add more files that are considered harmless, or stop ignoring
643
- * these files from a tool available in the scanner section in the settings
644
- * page.
645
- *
646
- * @param string $path Relative path to the file.
647
- * @param bool $checkExistence Stop if the file does not exists.
648
- * @return bool True if the file was ignored, false otherwise.
649
- */
650
- private static function ignoreIrrelevantFile($path = '', $checkExistence = true)
651
- {
652
- if ($checkExistence && !file_exists(ABSPATH . '/' . $path)) {
653
- return; /* skip if the file does not exists */
654
- }
655
-
656
- $cache = new SucuriScanCache('integrity');
657
-
658
- $cache_key = md5($path);
659
- $cache_value = array(
660
- 'file_path' => $path,
661
- 'file_status' => 'added',
662
- 'ignored_at' => time(),
663
- );
664
-
665
- return $cache->add($cache_key, $cache_value);
666
  }
667
  }
117
  return SucuriScanInterface::error(__('NothingSelected', SUCURISCAN_TEXTDOMAIN));
118
  }
119
 
120
+ /* process files until the maximum execution time is reached */
121
+ $startTime = microtime(true);
122
+ $displayTimeoutAlert = false;
123
+ $maxtime = (int) SucuriScan::iniGet('max_execution_time');
124
+ $timeout = ($maxtime > 1) ? ($maxtime - 6) : 30;
125
+
126
  foreach ((array) $core_files as $file_meta) {
127
+ if (strpos($file_meta, '@') === false) {
128
+ continue;
129
+ }
130
 
131
+ /* avoid gateway timeout; max execution time */
132
+ $elapsedTime = (microtime(true) - $startTime);
133
+ if ($elapsedTime >= $timeout) {
134
+ $displayTimeoutAlert = true;
135
+ break;
136
+ }
137
 
138
+ @list($status_type, $file_path) = explode('@', $file_meta, 2);
139
+
140
+ if (!$file_path || !$status_type) {
141
+ continue;
142
+ }
143
+
144
+ $full_path = ABSPATH . '/' . $file_path;
145
+
146
+ if ($action === 'fixed' && (
147
+ $status_type === 'added'
148
+ || $status_type === 'removed'
149
+ || $status_type === 'modified'
150
+ )) {
151
+ $cache_key = md5($file_path);
152
+ $cache_value = array(
153
+ 'file_path' => $file_path,
154
+ 'file_status' => $status_type,
155
+ 'ignored_at' => time(),
156
+ );
157
+
158
+ if ($cache->add($cache_key, $cache_value)) {
159
  $files_affected[] = $full_path;
160
+ $files_processed++;
161
  }
162
+ continue;
163
+ }
164
 
165
+ if ($action === 'restore' && (
166
+ $status_type === 'removed'
167
+ || $status_type === 'modified'
168
+ )) {
169
+ if ($content = SucuriScanAPI::getOriginalCoreFile($file_path)) {
170
+ $basedir = dirname($full_path);
 
171
 
172
+ if (!file_exists($basedir)) {
173
+ @mkdir($basedir, 0755, true);
 
 
 
174
  }
 
 
175
 
176
+ if (@file_put_contents($full_path, $content)) {
 
 
177
  $files_affected[] = $full_path;
178
+ $files_processed++;
179
  }
 
180
  }
181
+ continue;
182
+ }
183
+
184
+ if ($action === 'delete' && $status_type === 'added') {
185
+ if (@unlink($full_path)) {
186
+ $files_affected[] = $full_path;
187
+ $files_processed++;
188
+ }
189
+ continue;
190
  }
191
  }
192
 
216
  }
217
  }
218
 
219
+ if ($displayTimeoutAlert) {
220
+ SucuriScanInterface::error(__('MaxExecutionTimeAlert', SUCURISCAN_TEXTDOMAIN));
221
+ }
222
+
223
  if ($files_processed != $files_selected) {
224
  return SucuriScanInterface::error(sprintf(
225
  __('SomeItemsProcessed', SUCURISCAN_TEXTDOMAIN),
254
  {
255
  $params = array();
256
  $affected_files = 0;
 
257
 
258
  $params['Version'] = SucuriScan::siteVersion();
259
  $params['Integrity.List'] = '';
263
  $params['Integrity.GoodVisibility'] = 'hidden';
264
  $params['Integrity.FailureVisibility'] = 'visible';
265
  $params['Integrity.FalsePositivesVisibility'] = 'hidden';
266
+ $params['Integrity.DiffUtility'] = '';
267
+
268
+ // Check if there are added, removed, or modified files.
269
+ $latest_hashes = self::checkIntegrityIntegrity();
270
+ $params['Integrity.RemoteChecksumsURL'] = SucuriScanAPI::checksumAPI();
271
 
272
+ if ($latest_hashes) {
273
+ $cache = new SucuriScanCache('integrity');
274
+ $ignored_files = $cache->getAll();
275
+ $counter = 0;
276
 
277
+ $params['Integrity.BadVisibility'] = 'hidden';
278
+ $params['Integrity.GoodVisibility'] = 'visible';
279
+ $params['Integrity.FailureVisibility'] = 'hidden';
 
 
 
 
280
 
281
+ foreach ($latest_hashes as $list_type => $file_list) {
282
+ if ($list_type == 'stable' || empty($file_list)) {
283
+ continue;
284
+ }
285
 
286
+ foreach ($file_list as $file_info) {
287
+ $file_path = $file_info['filepath'];
288
+ $full_filepath = sprintf('%s/%s', rtrim(ABSPATH, '/'), $file_path);
289
 
290
+ if ($ignored_files /* skip files marked as fixed */
291
+ && array_key_exists(md5($file_path), $ignored_files)
292
+ ) {
293
+ $params['Integrity.FalsePositivesVisibility'] = 'visible';
294
  continue;
295
  }
296
 
297
+ // Add extra information to the file list.
298
+ $file_size = @filesize($full_filepath);
299
+ $file_size_human = ''; /* empty */
 
 
 
 
 
 
 
 
 
 
 
300
 
301
+ /* error message if the file cannot be fixed */
302
+ $error = '';
303
+ $visibility = 'hidden';
304
 
305
+ if ($file_info['is_fixable'] !== true) {
306
+ $visibility = 'visible';
307
 
308
+ if ($list_type === 'added') {
309
+ $error = __('ErrorIntegrityAdded', SUCURISCAN_TEXTDOMAIN);
310
+ } elseif ($list_type === 'modified') {
311
+ $error = __('ErrorIntegrityModified', SUCURISCAN_TEXTDOMAIN);
312
+ } elseif ($list_type === 'removed') {
313
+ $error = __('ErrorIntegrityRemoved', SUCURISCAN_TEXTDOMAIN);
 
 
 
 
 
 
314
  }
315
+ }
316
 
317
+ // Pretty-print the file size in human-readable form.
318
+ if ($file_size !== false) {
319
+ $file_size_human = SucuriScan::humanFileSize($file_size);
 
 
 
 
 
 
 
 
 
 
 
320
  }
 
321
 
322
+ // Generate the HTML code from the snippet template for this file.
323
+ $params['Integrity.List'] .=
324
+ SucuriScanTemplate::getSnippet('integrity-incorrect', array(
325
+ 'Integrity.StatusType' => $list_type,
326
+ 'Integrity.FilePath' => $file_path,
327
+ 'Integrity.FileSize' => $file_size,
328
+ 'Integrity.FileSizeHuman' => $file_size_human,
329
+ 'Integrity.FileSizeNumber' => number_format($file_size),
330
+ 'Integrity.ModifiedAt' => SucuriScan::datetime($file_info['modified_at']),
331
+ 'Integrity.ErrorVisibility' => $visibility,
332
+ 'Integrity.ErrorMessage' => $error,
333
+ ));
334
+ $affected_files++;
335
+ $counter++;
336
  }
337
  }
338
+
339
+ if ($counter > 0) {
340
+ $params['Integrity.ListCount'] = $counter;
341
+ $params['Integrity.BadVisibility'] = 'visible';
342
+ $params['Integrity.GoodVisibility'] = 'hidden';
343
+ }
344
  }
345
 
346
  if ($send_email === true) {
413
  return;
414
  }
415
 
 
 
 
416
  ob_start();
417
+ $filename = SucuriScanRequest::post('filepath');
418
+ print(SucuriScanCommand::diffHTML($filename));
419
  $response = ob_get_clean();
420
 
421
  wp_send_json($response, 200);
453
  * <li>added: Files present in the local project but not in the official WordPress packages.</li>
454
  * </ul>
455
  *
 
456
  * @return array|bool Associative array with these keys: modified, stable, removed, added.
457
  */
458
+ private static function checkIntegrityIntegrity()
459
  {
460
+ $latest_hashes = SucuriScanAPI::getOfficialChecksums();
461
  $base_content_dir = defined('WP_CONTENT_DIR')
462
  ? basename(rtrim(WP_CONTENT_DIR, '/'))
463
  : '';
480
  $wp_admin_hashes = self::integrityTree(ABSPATH . 'wp-admin', true);
481
  $wp_includes_hashes = self::integrityTree(ABSPATH . 'wp-includes', true);
482
  $wp_core_hashes = array_merge($wp_top_hashes, $wp_admin_hashes, $wp_includes_hashes);
483
+ $checksumAlgorithm = SucuriScanAPI::checksumAlgorithm();
484
 
485
  // Compare remote and local checksums and search removed files.
486
  foreach ($latest_hashes as $file_path => $remote) {
504
 
505
  // Check whether the official file exists or not.
506
  if (file_exists($full_filepath)) {
507
+ /* skip folders; cannot calculate a hash easily */
508
+ if (is_dir($full_filepath)) {
509
+ $output['stable'][] = array(
510
+ 'filepath' => $file_path,
511
+ 'is_fixable' => false,
512
+ 'modified_at' => 0,
513
+ );
514
+ continue;
515
+ }
516
+
517
+ $local = SucuriScanAPI::checksum($checksumAlgorithm, $full_filepath);
518
 
519
  if ($local !== false && $local === $remote) {
520
  $output['stable'][] = array(
573
  */
574
  private static function ignoreIntegrityFilepath($path = '')
575
  {
576
+ global $wp_local_package;
577
+
578
+ $irrelevant = array(
579
+ 'php.ini',
580
+ '.htaccess',
581
+ '.htpasswd',
582
+ '.ftpquota',
583
+ 'wp-includes/.htaccess',
584
+ 'wp-admin/setup-config.php',
585
+ 'wp-tests-config.php',
586
+ 'wp-config.php',
587
+ 'sitemap.xml',
588
+ 'sitemap.xml.gz',
589
+ 'readme.html',
590
+ 'error_log',
591
+ 'wp-pass.php',
592
+ 'wp-rss.php',
593
+ 'wp-feed.php',
594
+ 'wp-register.php',
595
+ 'wp-atom.php',
596
+ 'wp-commentsrss2.php',
597
+ 'wp-rss2.php',
598
+ 'wp-rdf.php',
599
+ '404.php',
600
+ '503.php',
601
+ '500.php',
602
+ '500.shtml',
603
+ '400.shtml',
604
+ '401.shtml',
605
+ '402.shtml',
606
+ '403.shtml',
607
+ '404.shtml',
608
+ '405.shtml',
609
+ '406.shtml',
610
+ '407.shtml',
611
+ '408.shtml',
612
+ '409.shtml',
613
+ 'healthcheck.html',
614
+ );
615
+
616
+ /**
617
+ * Ignore i18n files.
618
+ *
619
+ * Sites with i18n have differences compared with the official English
620
+ * version of the project, basically they have files with new variables
621
+ * specifying the language that will be used in the admin panel, site
622
+ * options, and emails.
623
+ */
624
+ if (isset($wp_local_package) && $wp_local_package != 'en_US') {
625
+ $irrelevant[] = 'wp-includes/version.php';
626
+ $irrelevant[] = 'wp-config-sample.php';
627
+ }
628
+
629
+ if (in_array($path, $irrelevant)) {
630
+ return true;
631
+ }
632
+
633
+ /* use regular expressions */
634
+ $ignore = false;
635
+ $irrelevant = array(
636
  '^sucuri-[0-9a-z\-]+\.php$',
637
  '^\S+-sucuri-db-dump-gzip-[0-9]{10}-[0-9a-z]{32}\.gz$',
638
+ '^\.sucuri-sss-resume-[0-9a-z]{32}\.php$',
639
  '^([^\/]*)\.(pdf|css|txt|jpg|gif|png|jpeg)$',
640
  '^wp-content\/(themes|plugins)\/.+',
641
  '^google[0-9a-z]{16}\.html$',
643
  '\.ico$',
644
  );
645
 
646
+ foreach ($irrelevant as $pattern) {
647
+ if (@preg_match('/'.$pattern.'/', $path)) {
648
+ $ignore = true;
649
+ break;
650
  }
651
  }
652
 
653
+ return $ignore;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
654
  }
655
  }
src/interface.lib.php CHANGED
@@ -69,32 +69,6 @@ class SucuriScanInterface
69
  );
70
  wp_enqueue_script('sucuriscan1');
71
 
72
- if (SucuriScanRequest::get('page', 'sucuriscan') !== false) {
73
- wp_register_style(
74
- 'sucuriscan2',
75
- SUCURISCAN_URL . '/inc/css/c3.min.css',
76
- array(/* empty */),
77
- $asset
78
- );
79
- wp_enqueue_style('sucuriscan2');
80
-
81
- wp_register_script(
82
- 'sucuriscan2',
83
- SUCURISCAN_URL . '/inc/js/d3.min.js',
84
- array(/* empty */),
85
- $asset
86
- );
87
- wp_enqueue_script('sucuriscan2');
88
-
89
- wp_register_script(
90
- 'sucuriscan3',
91
- SUCURISCAN_URL . '/inc/js/c3.min.js',
92
- array(/* empty */),
93
- $asset
94
- );
95
- wp_enqueue_script('sucuriscan3');
96
- }
97
-
98
  if (SucuriScanRequest::get('page', 'sucuriscan_firewall') !== false) {
99
  wp_register_style(
100
  'sucuriscan3',
@@ -175,6 +149,35 @@ class SucuriScanInterface
175
  }
176
  }
177
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  /**
179
  * Do something if the plugin was updated.
180
  *
@@ -191,20 +194,7 @@ class SucuriScanInterface
191
  $version = SucuriScanOption::getOption(':plugin_version');
192
 
193
  /* use simple comparison to force type cast. */
194
- if (headers_sent() || $version == SUCURISCAN_VERSION) {
195
- return;
196
- }
197
-
198
- if (!is_writable(SucuriScanOption::optionsFilePath())) {
199
- /**
200
- * Stop if the settings file is not writable.
201
- *
202
- * In some cases where the settings file is not writable, or for
203
- * some reason the option cannot be updated, the alerts below will
204
- * be rendered all the time, to avoid unnecessary complains from
205
- * the website owners we will not display the alerts if the option
206
- * cannot be updated.
207
- */
208
  return;
209
  }
210
 
69
  );
70
  wp_enqueue_script('sucuriscan1');
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  if (SucuriScanRequest::get('page', 'sucuriscan_firewall') !== false) {
73
  wp_register_style(
74
  'sucuriscan3',
149
  }
150
  }
151
 
152
+ /**
153
+ * Display alerts and execute pre-checks before every page.
154
+ *
155
+ * This method verifies if the visibility of the requested page is allowed
156
+ * for the current user in session which usually needs to be granted admin
157
+ * privileges to access the plugin's tools. It also checks if the required
158
+ * SPL library is available and if the settings file is writable.
159
+ */
160
+ public static function startupChecks()
161
+ {
162
+ self::checkPageVisibility();
163
+
164
+ self::noticeAfterUpdate();
165
+
166
+ if (!SucuriScanFileInfo::isSplAvailable()) {
167
+ /* display a warning when system dependencies are not met */
168
+ self::error(__('RequiresModernPHP', SUCURISCAN_TEXTDOMAIN));
169
+ }
170
+
171
+ if ($filename = SucuriScanOption::optionsFilePath()) {
172
+ if (!is_writable($filename)) {
173
+ self::error(sprintf(
174
+ __('StorageNotWritable', SUCURISCAN_TEXTDOMAIN),
175
+ $filename /* absolute path of the settings file */
176
+ ));
177
+ }
178
+ }
179
+ }
180
+
181
  /**
182
  * Do something if the plugin was updated.
183
  *
194
  $version = SucuriScanOption::getOption(':plugin_version');
195
 
196
  /* use simple comparison to force type cast. */
197
+ if ($version == SUCURISCAN_VERSION) {
 
 
 
 
 
 
 
 
 
 
 
 
 
198
  return;
199
  }
200
 
src/lastlogins-failed.php CHANGED
@@ -254,7 +254,6 @@ function sucuriscan_get_failed_logins($get_old_logs = false, $offset = 0, $limit
254
  $processed++; /* count decoded data */
255
 
256
  if (is_array($login_data)) {
257
- $login_data['attempt_date'] = date('r', $login_data['attempt_time']);
258
  $login_data['attempt_count'] = ( $key + 1 );
259
 
260
  if (!$login_data['user_agent']) {
@@ -360,6 +359,8 @@ function sucuriscan_report_failed_logins($failed_logins = array())
360
  }
361
 
362
  foreach ($failed_logins['entries'] as $login_data) {
 
 
363
  if ($prettify_mails) {
364
  $table_html .= '<tr>';
365
  $table_html .= '<td>' . esc_attr($login_data['user_login']) . '</td>';
254
  $processed++; /* count decoded data */
255
 
256
  if (is_array($login_data)) {
 
257
  $login_data['attempt_count'] = ( $key + 1 );
258
 
259
  if (!$login_data['user_agent']) {
359
  }
360
 
361
  foreach ($failed_logins['entries'] as $login_data) {
362
+ $login_data['attempt_date'] = SucuriScan::datetime($login_data['attempt_time']);
363
+
364
  if ($prettify_mails) {
365
  $table_html .= '<tr>';
366
  $table_html .= '<td>' . esc_attr($login_data['user_login']) . '</td>';
src/lastlogins.php CHANGED
@@ -103,7 +103,7 @@ function sucuriscan_lastlogins_all()
103
 
104
  if (!sucuriscan_lastlogins_datastore_is_writable()) {
105
  $fpath = SucuriScan::escape(sucuriscan_lastlogins_datastore_filepath());
106
- SucuriScanInterface::error(sprintf(__('LastLoginsNotWritable'), $fpath));
107
  }
108
 
109
  if ($last_logins = sucuriscan_get_logins($max_per_page, $offset)) {
@@ -128,7 +128,7 @@ function sucuriscan_lastlogins_all()
128
  'UserList.RemoteAddr' => $user->user_remoteaddr,
129
  'UserList.Hostname' => $user->user_hostname,
130
  'UserList.Datetime' => $user->user_lastlogin,
131
- 'UserList.TimeAgo' => SucuriScan::timeAgo($user->user_lastlogin),
132
  'UserList.UserURL' => SucuriScan::adminURL('user-edit.php?user_id=' . $user->user_id),
133
  );
134
 
103
 
104
  if (!sucuriscan_lastlogins_datastore_is_writable()) {
105
  $fpath = SucuriScan::escape(sucuriscan_lastlogins_datastore_filepath());
106
+ SucuriScanInterface::error(sprintf(__('LastLoginsNotWritable', SUCURISCAN_TEXTDOMAIN), $fpath));
107
  }
108
 
109
  if ($last_logins = sucuriscan_get_logins($max_per_page, $offset)) {
128
  'UserList.RemoteAddr' => $user->user_remoteaddr,
129
  'UserList.Hostname' => $user->user_hostname,
130
  'UserList.Datetime' => $user->user_lastlogin,
131
+ 'UserList.TimeAgo' => SucuriScan::humanTime($user->user_lastlogin_timestamp),
132
  'UserList.UserURL' => SucuriScan::adminURL('user-edit.php?user_id=' . $user->user_id),
133
  );
134
 
src/mail.lib.php CHANGED
@@ -192,7 +192,7 @@ class SucuriScanMail extends SucuriScanOption
192
  $params['RemoteAddress'] = self::getRemoteAddr();
193
  $params['Message'] = $message;
194
  $params['User'] = $display_name;
195
- $params['Time'] = SucuriScan::currentDateTime();
196
 
197
  foreach ($data_set as $var_key => $var_value) {
198
  $params[ $var_key ] = $var_value;
192
  $params['RemoteAddress'] = self::getRemoteAddr();
193
  $params['Message'] = $message;
194
  $params['User'] = $display_name;
195
+ $params['Time'] = SucuriScan::datetime();
196
 
197
  foreach ($data_set as $var_key => $var_value) {
198
  $params[ $var_key ] = $var_value;
src/option.lib.php CHANGED
@@ -54,6 +54,8 @@ class SucuriScanOption extends SucuriScanRequest
54
  'sucuriscan_api_key' => false,
55
  'sucuriscan_api_protocol' => 'https',
56
  'sucuriscan_api_service' => 'enabled',
 
 
57
  'sucuriscan_cloudproxy_apikey' => '',
58
  'sucuriscan_diff_utility' => 'disabled',
59
  'sucuriscan_dns_lookups' => 'enabled',
@@ -65,22 +67,22 @@ class SucuriScanOption extends SucuriScanRequest
65
  'sucuriscan_language' => 'en_US',
66
  'sucuriscan_last_email_at' => time(),
67
  'sucuriscan_lastlogin_redirection' => 'enabled',
68
- 'sucuriscan_logs4report' => 500,
69
  'sucuriscan_maximum_failed_logins' => 30,
70
  'sucuriscan_notify_available_updates' => 'disabled',
71
  'sucuriscan_notify_bruteforce_attack' => 'disabled',
72
  'sucuriscan_notify_failed_login' => 'enabled',
73
- 'sucuriscan_notify_plugin_activated' => 'disabled',
74
- 'sucuriscan_notify_plugin_change' => 'disabled',
 
75
  'sucuriscan_notify_plugin_deactivated' => 'disabled',
76
  'sucuriscan_notify_plugin_deleted' => 'disabled',
77
  'sucuriscan_notify_plugin_installed' => 'disabled',
78
  'sucuriscan_notify_plugin_updated' => 'disabled',
79
  'sucuriscan_notify_post_publication' => 'enabled',
80
  'sucuriscan_notify_scan_checksums' => 'disabled',
81
- 'sucuriscan_notify_settings_updated' => 'disabled',
82
  'sucuriscan_notify_success_login' => 'enabled',
83
- 'sucuriscan_notify_theme_activated' => 'disabled',
84
  'sucuriscan_notify_theme_deleted' => 'disabled',
85
  'sucuriscan_notify_theme_editor' => 'enabled',
86
  'sucuriscan_notify_theme_installed' => 'disabled',
@@ -97,6 +99,8 @@ class SucuriScanOption extends SucuriScanRequest
97
  'sucuriscan_selfhosting_fpath' => '',
98
  'sucuriscan_selfhosting_monitor' => 'disabled',
99
  'sucuriscan_site_version' => '0.0',
 
 
100
  'sucuriscan_use_wpmail' => 'enabled',
101
  );
102
 
@@ -134,7 +138,7 @@ class SucuriScanOption extends SucuriScanRequest
134
 
135
  $default['sucuriscan_email_subject'] =
136
  __('SucuriAlert', SUCURISCAN_TEXTDOMAIN)
137
- . ', :domain, :event';
138
  }
139
 
140
  return @$default[$option];
@@ -452,6 +456,57 @@ class SucuriScanOption extends SucuriScanRequest
452
  );
453
  }
454
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
455
  /**
456
  * Check whether an event is being ignored to send alerts or not.
457
  *
54
  'sucuriscan_api_key' => false,
55
  'sucuriscan_api_protocol' => 'https',
56
  'sucuriscan_api_service' => 'enabled',
57
+ 'sucuriscan_auto_clear_cache' => 'disabled',
58
+ 'sucuriscan_checksum_api' => '',
59
  'sucuriscan_cloudproxy_apikey' => '',
60
  'sucuriscan_diff_utility' => 'disabled',
61
  'sucuriscan_dns_lookups' => 'enabled',
67
  'sucuriscan_language' => 'en_US',
68
  'sucuriscan_last_email_at' => time(),
69
  'sucuriscan_lastlogin_redirection' => 'enabled',
 
70
  'sucuriscan_maximum_failed_logins' => 30,
71
  'sucuriscan_notify_available_updates' => 'disabled',
72
  'sucuriscan_notify_bruteforce_attack' => 'disabled',
73
  'sucuriscan_notify_failed_login' => 'enabled',
74
+ 'sucuriscan_notify_failed_password' => 'disabled',
75
+ 'sucuriscan_notify_plugin_activated' => 'enabled',
76
+ 'sucuriscan_notify_plugin_change' => 'enabled',
77
  'sucuriscan_notify_plugin_deactivated' => 'disabled',
78
  'sucuriscan_notify_plugin_deleted' => 'disabled',
79
  'sucuriscan_notify_plugin_installed' => 'disabled',
80
  'sucuriscan_notify_plugin_updated' => 'disabled',
81
  'sucuriscan_notify_post_publication' => 'enabled',
82
  'sucuriscan_notify_scan_checksums' => 'disabled',
83
+ 'sucuriscan_notify_settings_updated' => 'enabled',
84
  'sucuriscan_notify_success_login' => 'enabled',
85
+ 'sucuriscan_notify_theme_activated' => 'enabled',
86
  'sucuriscan_notify_theme_deleted' => 'disabled',
87
  'sucuriscan_notify_theme_editor' => 'enabled',
88
  'sucuriscan_notify_theme_installed' => 'disabled',
99
  'sucuriscan_selfhosting_fpath' => '',
100
  'sucuriscan_selfhosting_monitor' => 'disabled',
101
  'sucuriscan_site_version' => '0.0',
102
+ 'sucuriscan_sitecheck_target' => '',
103
+ 'sucuriscan_timezone' => 'UTC+00.00',
104
  'sucuriscan_use_wpmail' => 'enabled',
105
  );
106
 
138
 
139
  $default['sucuriscan_email_subject'] =
140
  __('SucuriAlert', SUCURISCAN_TEXTDOMAIN)
141
+ . ', :domain, :event, :remoteaddr';
142
  }
143
 
144
  return @$default[$option];
456
  );
457
  }
458
 
459
+ /**
460
+ * Returns a list of post-types.
461
+ *
462
+ * The list of post-types includes objects such as Post and Page but also
463
+ * the transitions between each post type, for example, if there are posts
464
+ * of type Draft and they change to Trash, this function will include a new
465
+ * post type called "from_draft_to_trash" and so on.
466
+ *
467
+ * @return array List of post-types with transitions.
468
+ */
469
+ public static function getPostTypes()
470
+ {
471
+ $postTypes = get_post_types();
472
+ $transitions = array(
473
+ 'new',
474
+ 'publish',
475
+ 'pending',
476
+ 'draft',
477
+ 'auto-draft',
478
+ 'future',
479
+ 'private',
480
+ 'inherit',
481
+ 'trash',
482
+ );
483
+
484
+ /* include post-type transitions */
485
+ foreach ($transitions as $from) {
486
+ foreach ($transitions as $to) {
487
+ if ($from === $to) {
488
+ continue;
489
+ }
490
+
491
+ $event = sprintf('from_%s_to_%s', $from, $to);
492
+
493
+ if (!array_key_exists($event, $postTypes)) {
494
+ $postTypes[$event] = $event;
495
+ }
496
+ }
497
+ }
498
+
499
+ /* include custom non-registered post-types */
500
+ $ignoredEvents = SucuriScanOption::getIgnoredEvents();
501
+ foreach ($ignoredEvents as $event => $time) {
502
+ if (!array_key_exists($event, $postTypes)) {
503
+ $postTypes[$event] = $event;
504
+ }
505
+ }
506
+
507
+ return $postTypes;
508
+ }
509
+
510
  /**
511
  * Check whether an event is being ignored to send alerts or not.
512
  *
src/pagehandler.php CHANGED
@@ -23,19 +23,13 @@ function sucuriscan_page()
23
  {
24
  $params = array();
25
 
26
- SucuriScanInterface::checkPageVisibility();
27
-
28
- if (!SucuriScanFileInfo::isSplAvailable()) {
29
- /* display a warning when system dependencies are not met */
30
- SucuriScanInterface::error(__('RequiresModernPHP', SUCURISCAN_TEXTDOMAIN));
31
- }
32
 
33
  /* load data for the Integrity section */
34
  $params['Integrity'] = SucuriScanIntegrity::pageIntegrity();
35
 
36
  /* load data for the AuditLogs section */
37
  $params['AuditLogs'] = SucuriScanAuditLogs::pageAuditLogs();
38
- $params['AuditLogsReport'] = SucuriScanAuditLogs::pageAuditLogsReport();
39
 
40
  /* load data for the SiteCheck section */
41
  $params['SiteCheck.iFramesTitle'] = __('iFrames', SUCURISCAN_TEXTDOMAIN);
@@ -56,11 +50,12 @@ function sucuriscan_page()
56
  */
57
  function sucuriscan_firewall_page()
58
  {
59
- SucuriScanInterface::checkPageVisibility();
60
 
61
  $params = array(
62
  'Firewall.Settings' => SucuriScanFirewall::settingsPage(),
63
  'Firewall.AuditLogs' => SucuriScanFirewall::auditlogsPage(),
 
64
  'Firewall.ClearCache' => SucuriScanFirewall::clearCachePage(),
65
  );
66
 
@@ -72,7 +67,7 @@ function sucuriscan_firewall_page()
72
  */
73
  function sucuriscan_lastlogins_page()
74
  {
75
- SucuriScanInterface::checkPageVisibility();
76
 
77
  // Reset the file with the last-logins logs.
78
  if (SucuriScanInterface::checkNonce()
@@ -105,7 +100,7 @@ function sucuriscan_lastlogins_page()
105
  */
106
  function sucuriscan_settings_page()
107
  {
108
- SucuriScanInterface::checkPageVisibility();
109
 
110
  $params = array();
111
  $nonce = SucuriScanInterface::checkNonce();
@@ -115,15 +110,15 @@ function sucuriscan_settings_page()
115
 
116
  /* settings - general */
117
  $params['Settings.General.ApiKey'] = sucuriscan_settings_general_apikey($nonce);
118
- $params['Settings.General.DataStorage'] = sucuriscan_settings_general_datastorage();
119
  $params['Settings.General.SelfHosting'] = sucuriscan_settings_general_selfhosting($nonce);
120
  $params['Settings.General.ReverseProxy'] = sucuriscan_settings_general_reverseproxy($nonce);
121
  $params['Settings.General.IPDiscoverer'] = sucuriscan_settings_general_ipdiscoverer($nonce);
122
- $params['Settings.General.AuditLogStats'] = sucuriscan_settings_general_auditlogstats($nonce);
123
  $params['Settings.General.ImportExport'] = sucuriscan_settings_general_importexport($nonce);
 
124
 
125
  /* settings - scanner */
126
- $params['Settings.Scanner.Cronjobs'] = SucuriScanSettingsScanner::cronjobs();
127
  $params['Settings.Scanner.IntegrityDiffUtility'] = SucuriScanSettingsIntegrity::diffUtility($nonce);
128
  $params['Settings.Scanner.IntegrityLanguage'] = SucuriScanSettingsIntegrity::language($nonce);
129
  $params['Settings.Scanner.IntegrityCache'] = SucuriScanSettingsIntegrity::cache($nonce);
@@ -161,10 +156,11 @@ function sucuriscan_settings_page()
161
  /* settings - api service */
162
  $params['Settings.APIService.Status'] = sucuriscan_settings_apiservice_status($nonce);
163
  $params['Settings.APIService.Proxy'] = sucuriscan_settings_apiservice_proxy();
 
 
164
 
165
  /* settings - website info */
166
  $params['Settings.Webinfo.Details'] = sucuriscan_settings_webinfo_details();
167
- $params['Settings.Webinfo.WPConfig'] = sucuriscan_settings_webinfo_wpconfig();
168
  $params['Settings.Webinfo.HTAccess'] = sucuriscan_settings_webinfo_htaccess();
169
 
170
  echo SucuriScanTemplate::getTemplate('settings', $params);
@@ -179,10 +175,15 @@ function sucuriscan_ajax()
179
 
180
  if (SucuriScanInterface::checkNonce()) {
181
  SucuriScanAuditLogs::ajaxAuditLogs();
182
- SucuriScanAuditLogs::ajaxAuditLogsReport();
183
  SucuriScanAuditLogs::ajaxAuditLogsSendLogs();
184
  SucuriScanSiteCheck::ajaxMalwareScan();
185
  SucuriScanFirewall::auditlogsAjax();
 
 
 
 
 
 
186
  SucuriScanIntegrity::ajaxIntegrity();
187
  SucuriScanIntegrity::ajaxIntegrityDiffUtility();
188
  SucuriScanSettingsPosthack::availableUpdatesAjax();
23
  {
24
  $params = array();
25
 
26
+ SucuriScanInterface::startupChecks();
 
 
 
 
 
27
 
28
  /* load data for the Integrity section */
29
  $params['Integrity'] = SucuriScanIntegrity::pageIntegrity();
30
 
31
  /* load data for the AuditLogs section */
32
  $params['AuditLogs'] = SucuriScanAuditLogs::pageAuditLogs();
 
33
 
34
  /* load data for the SiteCheck section */
35
  $params['SiteCheck.iFramesTitle'] = __('iFrames', SUCURISCAN_TEXTDOMAIN);
50
  */
51
  function sucuriscan_firewall_page()
52
  {
53
+ SucuriScanInterface::startupChecks();
54
 
55
  $params = array(
56
  'Firewall.Settings' => SucuriScanFirewall::settingsPage(),
57
  'Firewall.AuditLogs' => SucuriScanFirewall::auditlogsPage(),
58
+ 'Firewall.IPAccess' => SucuriScanFirewall::ipAccessPage(),
59
  'Firewall.ClearCache' => SucuriScanFirewall::clearCachePage(),
60
  );
61
 
67
  */
68
  function sucuriscan_lastlogins_page()
69
  {
70
+ SucuriScanInterface::startupChecks();
71
 
72
  // Reset the file with the last-logins logs.
73
  if (SucuriScanInterface::checkNonce()
100
  */
101
  function sucuriscan_settings_page()
102
  {
103
+ SucuriScanInterface::startupChecks();
104
 
105
  $params = array();
106
  $nonce = SucuriScanInterface::checkNonce();
110
 
111
  /* settings - general */
112
  $params['Settings.General.ApiKey'] = sucuriscan_settings_general_apikey($nonce);
113
+ $params['Settings.General.DataStorage'] = sucuriscan_settings_general_datastorage($nonce);
114
  $params['Settings.General.SelfHosting'] = sucuriscan_settings_general_selfhosting($nonce);
115
  $params['Settings.General.ReverseProxy'] = sucuriscan_settings_general_reverseproxy($nonce);
116
  $params['Settings.General.IPDiscoverer'] = sucuriscan_settings_general_ipdiscoverer($nonce);
 
117
  $params['Settings.General.ImportExport'] = sucuriscan_settings_general_importexport($nonce);
118
+ $params['Settings.General.Timezone'] = sucuriscan_settings_general_timezone($nonce);
119
 
120
  /* settings - scanner */
121
+ $params['Settings.Scanner.Cronjobs'] = SucuriScanSettingsScanner::cronjobs($nonce);
122
  $params['Settings.Scanner.IntegrityDiffUtility'] = SucuriScanSettingsIntegrity::diffUtility($nonce);
123
  $params['Settings.Scanner.IntegrityLanguage'] = SucuriScanSettingsIntegrity::language($nonce);
124
  $params['Settings.Scanner.IntegrityCache'] = SucuriScanSettingsIntegrity::cache($nonce);
156
  /* settings - api service */
157
  $params['Settings.APIService.Status'] = sucuriscan_settings_apiservice_status($nonce);
158
  $params['Settings.APIService.Proxy'] = sucuriscan_settings_apiservice_proxy();
159
+ $params['Settings.SiteCheck.Target'] = SucuriScanSiteCheck::targetURLOption();
160
+ $params['Settings.APIService.Checksums'] = sucuriscan_settings_apiservice_checksums($nonce);
161
 
162
  /* settings - website info */
163
  $params['Settings.Webinfo.Details'] = sucuriscan_settings_webinfo_details();
 
164
  $params['Settings.Webinfo.HTAccess'] = sucuriscan_settings_webinfo_htaccess();
165
 
166
  echo SucuriScanTemplate::getTemplate('settings', $params);
175
 
176
  if (SucuriScanInterface::checkNonce()) {
177
  SucuriScanAuditLogs::ajaxAuditLogs();
 
178
  SucuriScanAuditLogs::ajaxAuditLogsSendLogs();
179
  SucuriScanSiteCheck::ajaxMalwareScan();
180
  SucuriScanFirewall::auditlogsAjax();
181
+ SucuriScanFirewall::ipAccessAjax();
182
+ SucuriScanFirewall::blacklistAjax();
183
+ SucuriScanFirewall::deblacklistAjax();
184
+ SucuriScanFirewall::getSettingsAjax();
185
+ SucuriScanFirewall::clearCacheAjax();
186
+ SucuriScanFirewall::clearAutoCacheAjax();
187
  SucuriScanIntegrity::ajaxIntegrity();
188
  SucuriScanIntegrity::ajaxIntegrityDiffUtility();
189
  SucuriScanSettingsPosthack::availableUpdatesAjax();
src/settings-alerts.php CHANGED
@@ -50,7 +50,7 @@ function sucuriscan_settings_alerts_recipients($nonce)
50
  $message = sprintf(__('WillReceiveAlerts', SUCURISCAN_TEXTDOMAIN), $new_email);
51
 
52
  SucuriScanOption::updateOption(':notify_to', implode(',', $emails));
53
- SucuriScanEvent::reportInfoEvent($message);
54
  SucuriScanEvent::notifyEvent('plugin_change', $message);
55
  SucuriScanInterface::info($message);
56
  } else {
@@ -76,7 +76,7 @@ function sucuriscan_settings_alerts_recipients($nonce)
76
  $message = sprintf(__('WillNotReceiveAlerts', SUCURISCAN_TEXTDOMAIN), $deleted_emails_str);
77
 
78
  SucuriScanOption::updateOption(':notify_to', implode(',', $emails));
79
- SucuriScanEvent::reportInfoEvent($message);
80
  SucuriScanEvent::notifyEvent('plugin_change', $message);
81
  SucuriScanInterface::info($message);
82
  }
@@ -88,7 +88,7 @@ function sucuriscan_settings_alerts_recipients($nonce)
88
  SucuriScanMail::sendMail(
89
  $recipients,
90
  'Test Email Alert',
91
- sprintf('Test email alert sent at %s', date('r')),
92
  array('Force' => true)
93
  );
94
  SucuriScanInterface::info(__('TestAlertSent', SUCURISCAN_TEXTDOMAIN));
@@ -130,7 +130,7 @@ function sucuriscan_settings_alerts_trustedips()
130
  if ($trust_ip = SucuriScanRequest::post(':trust_ip')) {
131
  if (SucuriScan::isValidIP($trust_ip) || SucuriScan::isValidCIDR($trust_ip)) {
132
  $ip_info = SucuriScan::getIPInfo($trust_ip);
133
- $ip_info['added_at'] = SucuriScan::localTime();
134
  $cache_key = md5($ip_info['remote_addr']);
135
 
136
  if ($cache->exists($cache_key)) {
@@ -373,22 +373,24 @@ function sucuriscan_settings_alerts_events($nonce)
373
  {
374
  $params = array();
375
  $params['Alerts.Events'] = '';
 
376
 
377
  $notify_options = array(
378
- 'sucuriscan_notify_plugin_change' => __('OptionNotifyPluginChange', SUCURISCAN_TEXTDOMAIN),
379
- 'sucuriscan_prettify_mails' => __('OptionPrettifyMails', SUCURISCAN_TEXTDOMAIN),
380
- 'sucuriscan_use_wpmail' => __('OptionUseWordPressMail', SUCURISCAN_TEXTDOMAIN),
381
- 'sucuriscan_lastlogin_redirection' => __('OptionLastLoginRedirection', SUCURISCAN_TEXTDOMAIN),
382
- 'sucuriscan_notify_scan_checksums' => __('OptionNotifyScanChecksums', SUCURISCAN_TEXTDOMAIN),
383
- 'sucuriscan_notify_available_updates' => __('OptionNotifyAvailableUpdates', SUCURISCAN_TEXTDOMAIN),
384
  'sucuriscan_notify_user_registration' => 'user:' . __('OptionNotifyUserRegistration', SUCURISCAN_TEXTDOMAIN),
385
  'sucuriscan_notify_success_login' => 'user:' . __('OptionNotifySuccessLogin', SUCURISCAN_TEXTDOMAIN),
386
  'sucuriscan_notify_failed_login' => 'user:' . __('OptionNotifyFailedLogin', SUCURISCAN_TEXTDOMAIN),
 
387
  'sucuriscan_notify_bruteforce_attack' => 'user:' . __('OptionNotifyBruteforceAttack', SUCURISCAN_TEXTDOMAIN),
388
- 'sucuriscan_notify_post_publication' => __('OptionNotifyPostPublication', SUCURISCAN_TEXTDOMAIN),
389
- 'sucuriscan_notify_website_updated' => __('OptionNotifyWebsiteUpdated', SUCURISCAN_TEXTDOMAIN),
390
- 'sucuriscan_notify_settings_updated' => __('OptionNotifySettingsUpdated', SUCURISCAN_TEXTDOMAIN),
391
- 'sucuriscan_notify_theme_editor' => __('OptionNotifyThemeEditor', SUCURISCAN_TEXTDOMAIN),
392
  'sucuriscan_notify_plugin_installed' => 'plugin:' . __('OptionNotifyPluginInstalled', SUCURISCAN_TEXTDOMAIN),
393
  'sucuriscan_notify_plugin_activated' => 'plugin:' . __('OptionNotifyPluginActivated', SUCURISCAN_TEXTDOMAIN),
394
  'sucuriscan_notify_plugin_deactivated' => 'plugin:' . __('OptionNotifyPluginDeactivated', SUCURISCAN_TEXTDOMAIN),
@@ -402,6 +404,25 @@ function sucuriscan_settings_alerts_events($nonce)
402
  'sucuriscan_notify_theme_deleted' => 'theme:' . __('OptionNotifyThemeDeleted', SUCURISCAN_TEXTDOMAIN),
403
  );
404
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
405
  // Process form submission to change the alert settings.
406
  if ($nonce) {
407
  // Update the notification settings.
@@ -433,42 +454,46 @@ function sucuriscan_settings_alerts_events($nonce)
433
  }
434
  }
435
 
436
- // Build the HTML code for the interface.
437
- if (is_array($notify_options)) {
438
- $pattern = '/^([a-z]+:)?(.+)/';
439
-
440
- foreach ($notify_options as $alert_type => $alert_label) {
441
- $alert_value = SucuriScanOption::getOption($alert_type);
442
- $checked = ($alert_value == 'enabled') ? 'checked="checked"' : '';
443
- $alert_icon = '';
444
-
445
- if (@preg_match($pattern, $alert_label, $match)) {
446
- $alert_group = str_replace(':', '', $match[1]);
447
- $alert_label = $match[2];
448
-
449
- switch ($alert_group) {
450
- case 'user':
451
- $alert_icon = 'dashicons-before dashicons-admin-users';
452
- break;
453
-
454
- case 'plugin':
455
- $alert_icon = 'dashicons-before dashicons-admin-plugins';
456
- break;
457
-
458
- case 'theme':
459
- $alert_icon = 'dashicons-before dashicons-admin-appearance';
460
- break;
461
- }
462
- }
463
-
464
- $params['Alerts.Events'] .=
465
- SucuriScanTemplate::getSnippet('settings-alerts-events', array(
466
- 'Event.Name' => $alert_type,
467
- 'Event.Checked' => $checked,
468
- 'Event.Label' => $alert_label,
469
- 'Event.LabelIcon' => $alert_icon,
470
- ));
471
  }
 
 
 
 
 
 
 
 
472
  }
473
 
474
  return SucuriScanTemplate::getSection('settings-alerts-events', $params);
@@ -481,11 +506,9 @@ function sucuriscan_settings_alerts_events($nonce)
481
  */
482
  function sucuriscan_settings_alerts_ignore_posts()
483
  {
484
- $notify_new_site_content = SucuriScanOption::getOption(':notify_post_publication');
485
-
486
  $params = array(
487
- 'IgnoreRules.MessageVisibility' => 'visible',
488
  'IgnoreRules.PostTypes' => '',
 
489
  );
490
 
491
  if (SucuriScanInterface::checkNonce()) {
@@ -510,48 +533,55 @@ function sucuriscan_settings_alerts_ignore_posts()
510
  }
511
  }
512
 
513
- if ($notify_new_site_content == 'enabled') {
514
- $post_types = get_post_types();
515
- $ignored_events = SucuriScanOption::getIgnoredEvents();
 
 
 
 
516
 
517
- $params['IgnoreRules.MessageVisibility'] = 'hidden';
518
-
519
- /* Include custom non-registered post-types */
520
- foreach ($ignored_events as $event => $time) {
521
- if (!array_key_exists($event, $post_types)) {
522
- $post_types[$event] = $event;
523
- }
524
- }
525
 
526
- /* Check which post-types are being ignored */
527
- foreach ($post_types as $post_type) {
528
- $post_type_title = ucwords(str_replace('_', chr(32), $post_type));
529
 
530
- if (array_key_exists($post_type, $ignored_events)) {
531
- $is_ignored_text = __('Yes', SUCURISCAN_TEXTDOMAIN);
532
- $was_ignored_at = SucuriScan::datetime($ignored_events[ $post_type ]);
533
- $is_ignored_class = 'danger';
534
- $button_action = 'remove';
535
- $button_text = __('PostTypeIgnore', SUCURISCAN_TEXTDOMAIN);
536
- } else {
537
- $is_ignored_text = __('No', SUCURISCAN_TEXTDOMAIN);
538
- $was_ignored_at = '--';
539
- $is_ignored_class = 'success';
540
- $button_action = 'add';
541
- $button_text = __('PostTypeUnignore', SUCURISCAN_TEXTDOMAIN);
542
- }
543
 
544
- $params['IgnoreRules.PostTypes'] .=
545
- SucuriScanTemplate::getSnippet('settings-alerts-ignore-posts', array(
546
- 'IgnoreRules.PostTypeTitle' => $post_type_title,
547
- 'IgnoreRules.IsIgnored' => $is_ignored_text,
548
- 'IgnoreRules.WasIgnoredAt' => $was_ignored_at,
549
- 'IgnoreRules.IsIgnoredClass' => $is_ignored_class,
550
- 'IgnoreRules.PostType' => $post_type,
551
- 'IgnoreRules.Action' => $button_action,
552
- 'IgnoreRules.ButtonText' => $button_text,
553
- ));
 
 
 
 
 
 
554
  }
 
 
 
 
 
 
 
 
 
 
 
555
  }
556
 
557
  return SucuriScanTemplate::getSection('settings-alerts-ignore-posts', $params);
50
  $message = sprintf(__('WillReceiveAlerts', SUCURISCAN_TEXTDOMAIN), $new_email);
51
 
52
  SucuriScanOption::updateOption(':notify_to', implode(',', $emails));
53
+ SucuriScanEvent::reportInfoEvent('The email alerts will be sent to: ' . $new_email);
54
  SucuriScanEvent::notifyEvent('plugin_change', $message);
55
  SucuriScanInterface::info($message);
56
  } else {
76
  $message = sprintf(__('WillNotReceiveAlerts', SUCURISCAN_TEXTDOMAIN), $deleted_emails_str);
77
 
78
  SucuriScanOption::updateOption(':notify_to', implode(',', $emails));
79
+ SucuriScanEvent::reportInfoEvent('These emails will stop receiving alerts: ' . $deleted_emails_str);
80
  SucuriScanEvent::notifyEvent('plugin_change', $message);
81
  SucuriScanInterface::info($message);
82
  }
88
  SucuriScanMail::sendMail(
89
  $recipients,
90
  'Test Email Alert',
91
+ sprintf('Test email alert sent at %s', SucuriScan::datetime()),
92
  array('Force' => true)
93
  );
94
  SucuriScanInterface::info(__('TestAlertSent', SUCURISCAN_TEXTDOMAIN));
130
  if ($trust_ip = SucuriScanRequest::post(':trust_ip')) {
131
  if (SucuriScan::isValidIP($trust_ip) || SucuriScan::isValidCIDR($trust_ip)) {
132
  $ip_info = SucuriScan::getIPInfo($trust_ip);
133
+ $ip_info['added_at'] = time();
134
  $cache_key = md5($ip_info['remote_addr']);
135
 
136
  if ($cache->exists($cache_key)) {
373
  {
374
  $params = array();
375
  $params['Alerts.Events'] = '';
376
+ $params['Alerts.NoAlertsVisibility'] = 'hidden';
377
 
378
  $notify_options = array(
379
+ 'sucuriscan_notify_plugin_change' => 'setting:' . __('OptionNotifyPluginChange', SUCURISCAN_TEXTDOMAIN),
380
+ 'sucuriscan_prettify_mails' => 'setting:' . __('OptionPrettifyMails', SUCURISCAN_TEXTDOMAIN),
381
+ 'sucuriscan_use_wpmail' => 'setting:' . __('OptionUseWordPressMail', SUCURISCAN_TEXTDOMAIN),
382
+ 'sucuriscan_lastlogin_redirection' => 'setting:' . __('OptionLastLoginRedirection', SUCURISCAN_TEXTDOMAIN),
383
+ 'sucuriscan_notify_scan_checksums' => 'setting:' . __('OptionNotifyScanChecksums', SUCURISCAN_TEXTDOMAIN),
384
+ 'sucuriscan_notify_available_updates' => 'setting:' . __('OptionNotifyAvailableUpdates', SUCURISCAN_TEXTDOMAIN),
385
  'sucuriscan_notify_user_registration' => 'user:' . __('OptionNotifyUserRegistration', SUCURISCAN_TEXTDOMAIN),
386
  'sucuriscan_notify_success_login' => 'user:' . __('OptionNotifySuccessLogin', SUCURISCAN_TEXTDOMAIN),
387
  'sucuriscan_notify_failed_login' => 'user:' . __('OptionNotifyFailedLogin', SUCURISCAN_TEXTDOMAIN),
388
+ 'sucuriscan_notify_failed_password' => 'user:' . __('OptionNotifyFailedPassword', SUCURISCAN_TEXTDOMAIN),
389
  'sucuriscan_notify_bruteforce_attack' => 'user:' . __('OptionNotifyBruteforceAttack', SUCURISCAN_TEXTDOMAIN),
390
+ 'sucuriscan_notify_post_publication' => 'setting:' . __('OptionNotifyPostPublication', SUCURISCAN_TEXTDOMAIN),
391
+ 'sucuriscan_notify_website_updated' => 'setting:' . __('OptionNotifyWebsiteUpdated', SUCURISCAN_TEXTDOMAIN),
392
+ 'sucuriscan_notify_settings_updated' => 'setting:' . __('OptionNotifySettingsUpdated', SUCURISCAN_TEXTDOMAIN),
393
+ 'sucuriscan_notify_theme_editor' => 'setting:' . __('OptionNotifyThemeEditor', SUCURISCAN_TEXTDOMAIN),
394
  'sucuriscan_notify_plugin_installed' => 'plugin:' . __('OptionNotifyPluginInstalled', SUCURISCAN_TEXTDOMAIN),
395
  'sucuriscan_notify_plugin_activated' => 'plugin:' . __('OptionNotifyPluginActivated', SUCURISCAN_TEXTDOMAIN),
396
  'sucuriscan_notify_plugin_deactivated' => 'plugin:' . __('OptionNotifyPluginDeactivated', SUCURISCAN_TEXTDOMAIN),
404
  'sucuriscan_notify_theme_deleted' => 'theme:' . __('OptionNotifyThemeDeleted', SUCURISCAN_TEXTDOMAIN),
405
  );
406
 
407
+ /**
408
+ * Hide successful and failed logins option.
409
+ *
410
+ * Due to an incompatibility with the Postman-SMTP plugin we cannot sent
411
+ * email alerts when a successful or failed user authentication happens, the
412
+ * result is an infinite loop while our plugin tries to notify about changes
413
+ * in the posts and the other plugin creates temporary post objects to track
414
+ * the emails.
415
+ *
416
+ * @date 30 June, 2017
417
+ * @see https://wordpress.org/plugins/postman-smtp/
418
+ * @see https://wordpress.org/support/topic/unable-to-access-wordpress-dashboard-after-update-to-1-8-7/
419
+ */
420
+ if (is_plugin_active('postman-smtp/postman-smtp.php')) {
421
+ $params['Alerts.NoAlertsVisibility'] = 'visible';
422
+ unset($notify_options['sucuriscan_notify_success_login']);
423
+ unset($notify_options['sucuriscan_notify_failed_login']);
424
+ }
425
+
426
  // Process form submission to change the alert settings.
427
  if ($nonce) {
428
  // Update the notification settings.
454
  }
455
  }
456
 
457
+ /* build the HTML code for the checkbox input fields */
458
+ foreach ($notify_options as $alert_type => $alert_label) {
459
+ $alert_value = SucuriScanOption::getOption($alert_type);
460
+ $checked = ($alert_value == 'enabled') ? 'checked="checked"' : '';
461
+ $alert_icon = '';
462
+
463
+ /* identify the optional icon */
464
+ $offset = strpos($alert_label, ':');
465
+ $alert_group = substr($alert_label, 0, $offset);
466
+ $alert_label = substr($alert_label, $offset+1);
467
+
468
+ switch ($alert_group) {
469
+ case 'user':
470
+ $alert_icon = 'dashicons-before dashicons-admin-users';
471
+ break;
472
+
473
+ case 'plugin':
474
+ $alert_icon = 'dashicons-before dashicons-admin-plugins';
475
+ break;
476
+
477
+ case 'theme':
478
+ $alert_icon = 'dashicons-before dashicons-admin-appearance';
479
+ break;
480
+
481
+ case 'setting':
482
+ $alert_icon = 'dashicons-before dashicons-admin-tools';
483
+ break;
484
+
485
+ case 'widget':
486
+ $alert_icon = 'dashicons-before dashicons-admin-post';
487
+ break;
 
 
 
 
488
  }
489
+
490
+ $params['Alerts.Events'] .=
491
+ SucuriScanTemplate::getSnippet('settings-alerts-events', array(
492
+ 'Event.Name' => $alert_type,
493
+ 'Event.Checked' => $checked,
494
+ 'Event.Label' => $alert_label,
495
+ 'Event.LabelIcon' => $alert_icon,
496
+ ));
497
  }
498
 
499
  return SucuriScanTemplate::getSection('settings-alerts-events', $params);
506
  */
507
  function sucuriscan_settings_alerts_ignore_posts()
508
  {
 
 
509
  $params = array(
 
510
  'IgnoreRules.PostTypes' => '',
511
+ 'IgnoreRules.ErrorVisibility' => 'hidden',
512
  );
513
 
514
  if (SucuriScanInterface::checkNonce()) {
533
  }
534
  }
535
 
536
+ /* notifications are post updates are disabled; print error */
537
+ if (SucuriScanOption::isDisabled(':notify_post_publication')) {
538
+ $params['IgnoreRules.ErrorVisibility'] = 'visible';
539
+ $params['IgnoreRules.PostTypes'] = sprintf(
540
+ '<tr><td colspan="4">%s</td></tr>',
541
+ __('NoData', SUCURISCAN_TEXTDOMAIN)
542
+ );
543
 
544
+ return SucuriScanTemplate::getSection('settings-alerts-ignore-posts', $params);
545
+ }
 
 
 
 
 
 
546
 
547
+ $post_types = SucuriScanOption::getPostTypes();
548
+ $ignored_events = SucuriScanOption::getIgnoredEvents();
 
549
 
550
+ /* include custom non-registered post-types */
551
+ foreach ($ignored_events as $event => $time) {
552
+ if (!array_key_exists($event, $post_types)) {
553
+ $post_types[$event] = $event;
554
+ }
555
+ }
 
 
 
 
 
 
 
556
 
557
+ /* Check which post-types are being ignored */
558
+ foreach ($post_types as $post_type) {
559
+ $post_type_title = ucwords(str_replace('_', chr(32), $post_type));
560
+
561
+ if (array_key_exists($post_type, $ignored_events)) {
562
+ $is_ignored_text = __('Yes', SUCURISCAN_TEXTDOMAIN);
563
+ $was_ignored_at = SucuriScan::datetime($ignored_events[ $post_type ]);
564
+ $is_ignored_class = 'danger';
565
+ $button_action = 'remove';
566
+ $button_text = __('PostTypeIgnore', SUCURISCAN_TEXTDOMAIN);
567
+ } else {
568
+ $is_ignored_text = __('No', SUCURISCAN_TEXTDOMAIN);
569
+ $was_ignored_at = '--';
570
+ $is_ignored_class = 'success';
571
+ $button_action = 'add';
572
+ $button_text = __('PostTypeUnignore', SUCURISCAN_TEXTDOMAIN);
573
  }
574
+
575
+ $params['IgnoreRules.PostTypes'] .=
576
+ SucuriScanTemplate::getSnippet('settings-alerts-ignore-posts', array(
577
+ 'IgnoreRules.PostTypeTitle' => $post_type_title,
578
+ 'IgnoreRules.IsIgnored' => $is_ignored_text,
579
+ 'IgnoreRules.WasIgnoredAt' => $was_ignored_at,
580
+ 'IgnoreRules.IsIgnoredClass' => $is_ignored_class,
581
+ 'IgnoreRules.PostType' => $post_type,
582
+ 'IgnoreRules.Action' => $button_action,
583
+ 'IgnoreRules.ButtonText' => $button_text,
584
+ ));
585
  }
586
 
587
  return SucuriScanTemplate::getSection('settings-alerts-ignore-posts', $params);
src/settings-apiservice.php CHANGED
@@ -97,3 +97,40 @@ function sucuriscan_settings_apiservice_proxy()
97
 
98
  return SucuriScanTemplate::getSection('settings-apiservice-proxy', $params);
99
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
 
98
  return SucuriScanTemplate::getSection('settings-apiservice-proxy', $params);
99
  }
100
+
101
+ /**
102
+ * Returns the HTML to configure the URL for the checkums API.
103
+ *
104
+ * @param bool $nonce True if the CSRF protection worked, false otherwise.
105
+ * @return string HTML for the URL for the checksums API service.
106
+ */
107
+ function sucuriscan_settings_apiservice_checksums($nonce)
108
+ {
109
+ $params = array();
110
+ $url = SucuriScanRequest::post(':checksum_api');
111
+
112
+ if ($nonce && $url !== false) {
113
+ /* https://github.com/WordPress/WordPress - OR - WordPress/WordPress */
114
+ $pattern = '/^(https:\/\/github\.com\/)?([0-9a-zA-Z_]+\/[0-9a-zA-Z_]+)/';
115
+
116
+ if (@preg_match($pattern, $url, $match)) {
117
+ SucuriScanOption::updateOption(':checksum_api', $match[2]);
118
+
119
+ $message = 'Core integrity API changed: ' . SucuriScanAPI::checksumAPI();
120
+ SucuriScanEvent::reportInfoEvent($message);
121
+ SucuriScanEvent::notifyEvent('plugin_change', $message);
122
+ SucuriScanInterface::info(__('ChecksumsAPIChanged', SUCURISCAN_TEXTDOMAIN));
123
+ } else {
124
+ SucuriScanOption::deleteOption(':checksum_api');
125
+
126
+ $message = 'Core integrity API changed: ' . SucuriScanAPI::checksumAPI();
127
+ SucuriScanEvent::reportInfoEvent($message);
128
+ SucuriScanEvent::notifyEvent('plugin_change', $message);
129
+ SucuriScanInterface::info(__('ChecksumsAPIChanged', SUCURISCAN_TEXTDOMAIN));
130
+ }
131
+ }
132
+
133
+ $params['ChecksumsAPI'] = SucuriScanAPI::checksumAPI();
134
+
135
+ return SucuriScanTemplate::getSection('settings-apiservice-checksums', $params);
136
+ }
src/settings-general.php CHANGED
@@ -61,23 +61,16 @@ function sucuriscan_settings_general_apikey($nonce)
61
  $display_manual_key_form = (bool) (SucuriScanRequest::post(':recover_key') !== false);
62
 
63
  if ($nonce) {
64
- if (!empty($_POST)) {
65
- $fpath = SucuriScanOption::optionsFilePath();
66
-
67
- if (!is_writable($fpath)) {
68
- SucuriScanInterface::error(sprintf(
69
- __('StorageNotWritable', SUCURISCAN_TEXTDOMAIN),
70
- $fpath /* absolute path of the data storage folder */
71
- ));
72
- }
73
- }
74
-
75
  // Remove API key from the local storage.
76
- if (SucuriScanRequest::post(':remove_api_key') !== false) {
77
- SucuriScanAPI::setPluginKey('');
 
78
  wp_clear_scheduled_hook('sucuriscan_scheduled_scan');
79
- SucuriScanEvent::reportCriticalEvent('Sucuri API key was deleted.');
 
80
  SucuriScanEvent::notifyEvent('plugin_change', 'Sucuri API key removed');
 
 
81
  }
82
 
83
  // Save API key after it was recovered by the administrator.
@@ -147,7 +140,7 @@ function sucuriscan_settings_general_apikey($nonce)
147
  * @param bool $nonce True if the CSRF protection worked.
148
  * @return string Page with information about the data storage.
149
  */
150
- function sucuriscan_settings_general_datastorage()
151
  {
152
  $params = array();
153
  $files = array(
@@ -170,7 +163,7 @@ function sucuriscan_settings_general_datastorage()
170
  $params['Storage.Files'] = '';
171
  $params['Storage.Path'] = SucuriScan::dataStorePath();
172
 
173
- if (SucuriScanInterface::checkNonce()) {
174
  if ($filenames = SucuriScanRequest::post(':filename', '_array')) {
175
  $deleted = 0;
176
 
@@ -458,34 +451,6 @@ function sucuriscan_settings_general_ipdiscoverer($nonce)
458
  return SucuriScanTemplate::getSection('settings-general-ipdiscoverer', $params);
459
  }
460
 
461
- /**
462
- * Renders a page with information about the auditlog stats feature.
463
- *
464
- * @param bool $nonce True if the CSRF protection worked.
465
- * @return string Page with information about the auditlog stats.
466
- */
467
- function sucuriscan_settings_general_auditlogstats($nonce)
468
- {
469
- $params = array();
470
-
471
- if ($nonce) {
472
- // Update the limit for audit logs report.
473
- if ($logs4report = SucuriScanRequest::post(':logs4report', '[0-9]{1,4}')) {
474
- $message = 'Audit log statistics limit set to <code>' . $logs4report . '</code>';
475
-
476
- SucuriScanOption::updateOption(':logs4report', $logs4report);
477
- SucuriScanEvent::reportInfoEvent($message);
478
- SucuriScanEvent::notifyEvent('plugin_change', $message);
479
- SucuriScanInterface::info(__('LogsReportLimit', SUCURISCAN_TEXTDOMAIN));
480
- }
481
- }
482
-
483
- $logs4report = SucuriScanOption::getOption(':logs4report');
484
- $params['AuditLogStats.Limit'] = SucuriScan::escape($logs4report);
485
-
486
- return SucuriScanTemplate::getSection('settings-general-auditlogstats', $params);
487
- }
488
-
489
  /**
490
  * Renders a page with information about the import export feature.
491
  *
@@ -509,7 +474,6 @@ function sucuriscan_settings_general_importexport($nonce)
509
  ':ignored_events',
510
  ':language',
511
  ':lastlogin_redirection',
512
- ':logs4report',
513
  ':maximum_failed_logins',
514
  ':notify_available_updates',
515
  ':notify_bruteforce_attack',
@@ -595,3 +559,52 @@ function sucuriscan_settings_general_importexport($nonce)
595
 
596
  return SucuriScanTemplate::getSection('settings-general-importexport', $params);
597
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  $display_manual_key_form = (bool) (SucuriScanRequest::post(':recover_key') !== false);
62
 
63
  if ($nonce) {
 
 
 
 
 
 
 
 
 
 
 
64
  // Remove API key from the local storage.
65
+ if (SucuriScanRequest::post(':remove_api_key') !== false
66
+ && SucuriScanAPI::setPluginKey('') !== false
67
+ ) {
68
  wp_clear_scheduled_hook('sucuriscan_scheduled_scan');
69
+
70
+ SucuriScanEvent::reportCriticalEvent('Sucuri API key has been deleted.');
71
  SucuriScanEvent::notifyEvent('plugin_change', 'Sucuri API key removed');
72
+ SucuriScanInterface::info('Sucuri API key has been deleted <code>'
73
+ . SucuriScan::escape(SucuriScanAPI::getPluginKey()) . '</code>');
74
  }
75
 
76
  // Save API key after it was recovered by the administrator.
140
  * @param bool $nonce True if the CSRF protection worked.
141
  * @return string Page with information about the data storage.
142
  */
143
+ function sucuriscan_settings_general_datastorage($nonce)
144
  {
145
  $params = array();
146
  $files = array(
163
  $params['Storage.Files'] = '';
164
  $params['Storage.Path'] = SucuriScan::dataStorePath();
165
 
166
+ if ($nonce) {
167
  if ($filenames = SucuriScanRequest::post(':filename', '_array')) {
168
  $deleted = 0;
169
 
451
  return SucuriScanTemplate::getSection('settings-general-ipdiscoverer', $params);
452
  }
453
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
454
  /**
455
  * Renders a page with information about the import export feature.
456
  *
474
  ':ignored_events',
475
  ':language',
476
  ':lastlogin_redirection',
 
477
  ':maximum_failed_logins',
478
  ':notify_available_updates',
479
  ':notify_bruteforce_attack',
559
 
560
  return SucuriScanTemplate::getSection('settings-general-importexport', $params);
561
  }
562
+
563
+ /**
564
+ * Renders a page with the option to configure the timezone.
565
+ *
566
+ * @param bool $nonce True if the CSRF protection worked.
567
+ * @return string Page to configure the timezone.
568
+ */
569
+ function sucuriscan_settings_general_timezone($nonce)
570
+ {
571
+ $params = array();
572
+ $current = time();
573
+ $options = array();
574
+ $offsets = array(
575
+ -12.0, -11.5, -11.0, -10.5, -10.0, -9.50, -9.00, -8.50, -8.00, -7.50,
576
+ -7.00, -6.50, -6.00, -5.50, -5.00, -4.50, -4.00, -3.50, -3.00, -2.50,
577
+ -2.00, -1.50, -1.00, -0.50, +0.00, +0.50, +1.00, +1.50, +2.00, +2.50,
578
+ +3.00, +3.50, +4.00, +4.50, +5.00, +5.50, +5.75, +6.00, +6.50, +7.00,
579
+ +7.50, +8.00, +8.50, +8.75, +9.00, +9.50, 10.00, 10.50, 11.00, 11.50,
580
+ 12.00, 12.75, 13.00, 13.75, 14.00
581
+ );
582
+
583
+ foreach ($offsets as $hour) {
584
+ $sign = ($hour < 0) ? '-' : '+';
585
+ $fill = (abs($hour) < 10) ? '0' : '';
586
+ $keyname = sprintf('UTC%s%s%.2f', $sign, $fill, abs($hour));
587
+ $label = date('d M, Y H:i:s', $current + ($hour * 3600));
588
+ $options[$keyname] = $label;
589
+ }
590
+
591
+ if ($nonce) {
592
+ $pattern = 'UTC[\-\+][0-9]{2}\.[0-9]{2}';
593
+ $timezone = SucuriScanRequest::post(':timezone', $pattern);
594
+
595
+ if ($timezone) {
596
+ $message = 'Timezone override will use ' . $timezone;
597
+
598
+ SucuriScanOption::updateOption(':timezone', $timezone);
599
+ SucuriScanEvent::reportInfoEvent($message);
600
+ SucuriScanEvent::notifyEvent('plugin_change', $message);
601
+ SucuriScanInterface::info(__('TimezoneStatus', SUCURISCAN_TEXTDOMAIN));
602
+ }
603
+ }
604
+
605
+ $val = SucuriScanOption::getOption(':timezone');
606
+ $params['Timezone.Dropdown'] = SucuriScanTemplate::selectOptions($options, $val);
607
+ $params['Timezone.Example'] = SucuriScan::datetime();
608
+
609
+ return SucuriScanTemplate::getSection('settings-general-timezone', $params);
610
+ }
src/settings-hardening.php CHANGED
@@ -255,7 +255,11 @@ class SucuriScanHardeningPage extends SucuriScan
255
  $params['Hardening.Title'] = __('HardeningUploadsTitle', SUCURISCAN_TEXTDOMAIN);
256
  $params['Hardening.Description'] = __('HardeningUploadsDescription', SUCURISCAN_TEXTDOMAIN);
257
 
258
- if (SucuriScanHardening::isHardened($folder)) {
 
 
 
 
259
  $params['Hardening.Status'] = 1;
260
  $params['Hardening.FieldName'] = __FUNCTION__ . '_revert';
261
  $params['Hardening.FieldText'] = __('RevertHardening', SUCURISCAN_TEXTDOMAIN);
@@ -308,7 +312,11 @@ class SucuriScanHardeningPage extends SucuriScan
308
  $params['Hardening.Title'] = __('HardeningContentTitle', SUCURISCAN_TEXTDOMAIN);
309
  $params['Hardening.Description'] = __('HardeningContentDescription', SUCURISCAN_TEXTDOMAIN);
310
 
311
- if (SucuriScanHardening::isHardened(WP_CONTENT_DIR)) {
 
 
 
 
312
  $params['Hardening.Status'] = 1;
313
  $params['Hardening.FieldName'] = __FUNCTION__ . '_revert';
314
  $params['Hardening.FieldText'] = __('RevertHardening', SUCURISCAN_TEXTDOMAIN);
@@ -371,7 +379,11 @@ class SucuriScanHardeningPage extends SucuriScan
371
  $params['Hardening.Title'] = __('HardeningIncludesTitle', SUCURISCAN_TEXTDOMAIN);
372
  $params['Hardening.Description'] = __('HardeningIncludesDescription', SUCURISCAN_TEXTDOMAIN);
373
 
374
- if (SucuriScanHardening::isHardened($folder)) {
 
 
 
 
375
  $params['Hardening.Status'] = 1;
376
  $params['Hardening.FieldName'] = __FUNCTION__ . '_revert';
377
  $params['Hardening.FieldText'] = __('RevertHardening', SUCURISCAN_TEXTDOMAIN);
255
  $params['Hardening.Title'] = __('HardeningUploadsTitle', SUCURISCAN_TEXTDOMAIN);
256
  $params['Hardening.Description'] = __('HardeningUploadsDescription', SUCURISCAN_TEXTDOMAIN);
257
 
258
+ if (SucuriScan::isBehindFirewall()) {
259
+ $params['Hardening.Status'] = 1;
260
+ $params['Hardening.FieldAttrs'] = 'disabled';
261
+ $params['Hardening.FieldText'] = __('RevertHardening', SUCURISCAN_TEXTDOMAIN);
262
+ } elseif (SucuriScanHardening::isHardened($folder)) {
263
  $params['Hardening.Status'] = 1;
264
  $params['Hardening.FieldName'] = __FUNCTION__ . '_revert';
265
  $params['Hardening.FieldText'] = __('RevertHardening', SUCURISCAN_TEXTDOMAIN);
312
  $params['Hardening.Title'] = __('HardeningContentTitle', SUCURISCAN_TEXTDOMAIN);
313
  $params['Hardening.Description'] = __('HardeningContentDescription', SUCURISCAN_TEXTDOMAIN);
314
 
315
+ if (SucuriScan::isBehindFirewall()) {
316
+ $params['Hardening.Status'] = 1;
317
+ $params['Hardening.FieldAttrs'] = 'disabled';
318
+ $params['Hardening.FieldText'] = __('RevertHardening', SUCURISCAN_TEXTDOMAIN);
319
+ } elseif (SucuriScanHardening::isHardened(WP_CONTENT_DIR)) {
320
  $params['Hardening.Status'] = 1;
321
  $params['Hardening.FieldName'] = __FUNCTION__ . '_revert';
322
  $params['Hardening.FieldText'] = __('RevertHardening', SUCURISCAN_TEXTDOMAIN);
379
  $params['Hardening.Title'] = __('HardeningIncludesTitle', SUCURISCAN_TEXTDOMAIN);
380
  $params['Hardening.Description'] = __('HardeningIncludesDescription', SUCURISCAN_TEXTDOMAIN);
381
 
382
+ if (SucuriScan::isBehindFirewall()) {
383
+ $params['Hardening.Status'] = 1;
384
+ $params['Hardening.FieldAttrs'] = 'disabled';
385
+ $params['Hardening.FieldText'] = __('RevertHardening', SUCURISCAN_TEXTDOMAIN);
386
+ } elseif (SucuriScanHardening::isHardened($folder)) {
387
  $params['Hardening.Status'] = 1;
388
  $params['Hardening.FieldName'] = __FUNCTION__ . '_revert';
389
  $params['Hardening.FieldText'] = __('RevertHardening', SUCURISCAN_TEXTDOMAIN);
src/settings-integrity.php CHANGED
@@ -87,7 +87,7 @@ class SucuriScanSettingsIntegrity extends SucuriScanSettings
87
  $message = 'Core integrity language set to <code>' . $language . '</code>';
88
 
89
  SucuriScanOption::updateOption(':language', $language);
90
- SucuriScanEvent::reportAutoEvent($message);
91
  SucuriScanEvent::notifyEvent('plugin_change', $message);
92
  SucuriScanInterface::info(__('IntegrityLanguage', SUCURISCAN_TEXTDOMAIN));
93
  } else {
87
  $message = 'Core integrity language set to <code>' . $language . '</code>';
88
 
89
  SucuriScanOption::updateOption(':language', $language);
90
+ SucuriScanEvent::reportInfoEvent($message);
91
  SucuriScanEvent::notifyEvent('plugin_change', $message);
92
  SucuriScanInterface::info(__('IntegrityLanguage', SUCURISCAN_TEXTDOMAIN));
93
  } else {
src/settings-scanner.php CHANGED
@@ -27,7 +27,7 @@ class SucuriScanSettingsScanner extends SucuriScanSettings
27
  * @param bool $nonce True if the CSRF protection worked.
28
  * @return string Page with information about the cronjobs.
29
  */
30
- public static function cronjobs()
31
  {
32
  $params = array(
33
  'Cronjobs.List' => '',
@@ -35,14 +35,9 @@ class SucuriScanSettingsScanner extends SucuriScanSettings
35
  'Cronjob.Schedules' => '',
36
  );
37
 
38
- $schedule_allowed = SucuriScanEvent::availableSchedules();
39
-
40
- if (SucuriScanInterface::checkNonce()) {
41
  // Modify the scheduled tasks (run now, remove, re-schedule).
42
- $available = ($schedule_allowed === null)
43
- ? SucuriScanEvent::availableSchedules()
44
- : $schedule_allowed;
45
- $allowed_actions = array_keys($available);
46
  $allowed_actions[] = 'runnow'; /* execute in the next 10 seconds */
47
  $allowed_actions[] = 'remove'; /* can be reinstalled automatically */
48
  $allowed_actions = sprintf('(%s)', implode('|', $allowed_actions));
@@ -105,9 +100,7 @@ class SucuriScanSettingsScanner extends SucuriScanSettings
105
  }
106
 
107
  $cronjobs = _get_cron_array();
108
- $available = ($schedule_allowed === null)
109
- ? SucuriScanEvent::availableSchedules()
110
- : $schedule_allowed;
111
 
112
  /* Hardcode the first one to allow the immediate execution of the cronjob(s) */
113
  $params['Cronjob.Schedules'] .= '<option value="runnow">'
27
  * @param bool $nonce True if the CSRF protection worked.
28
  * @return string Page with information about the cronjobs.
29
  */
30
+ public static function cronjobs($nonce)
31
  {
32
  $params = array(
33
  'Cronjobs.List' => '',
35
  'Cronjob.Schedules' => '',
36
  );
37
 
38
+ if ($nonce) {
 
 
39
  // Modify the scheduled tasks (run now, remove, re-schedule).
40
+ $allowed_actions = array_keys(SucuriScanEvent::availableSchedules());
 
 
 
41
  $allowed_actions[] = 'runnow'; /* execute in the next 10 seconds */
42
  $allowed_actions[] = 'remove'; /* can be reinstalled automatically */
43
  $allowed_actions = sprintf('(%s)', implode('|', $allowed_actions));
100
  }
101
 
102
  $cronjobs = _get_cron_array();
103
+ $available = SucuriScanEvent::availableSchedules();
 
 
104
 
105
  /* Hardcode the first one to allow the immediate execution of the cronjob(s) */
106
  $params['Cronjob.Schedules'] .= '<option value="runnow">'
src/settings-webinfo.php CHANGED
@@ -35,7 +35,7 @@ function sucuriscan_settings_webinfo_details()
35
  'Datetime_and_Timezone' => '',
36
  'Operating_system' => sprintf('%s (%d Bit)', PHP_OS, PHP_INT_SIZE * 8),
37
  'Server' => __('Unknown', SUCURISCAN_TEXTDOMAIN),
38
- 'Developer_mode' => __('NotActive', SUCURISCAN_TEXTDOMAIN),
39
  'Memory_usage' => __('Unknown', SUCURISCAN_TEXTDOMAIN),
40
  'MySQL_version' => '0.0',
41
  'SQL_mode' => __('NotSet', SUCURISCAN_TEXTDOMAIN),
@@ -43,13 +43,13 @@ function sucuriscan_settings_webinfo_details()
43
  );
44
 
45
  $info_vars['Datetime_and_Timezone'] = sprintf(
46
- '%s (GMT %s)',
47
- SucuriScan::currentDateTime(),
48
- SucuriScanOption::getOption('gmt_offset')
49
  );
50
 
51
  if (defined('WP_DEBUG') && WP_DEBUG) {
52
- $info_vars['Developer_mode'] = __('Active', SUCURISCAN_TEXTDOMAIN);
53
  }
54
 
55
  if (function_exists('memory_get_usage')) {
@@ -69,6 +69,7 @@ function sucuriscan_settings_webinfo_details()
69
  }
70
  }
71
 
 
72
  $field_names = array(
73
  'safe_mode',
74
  'expose_php',
@@ -86,6 +87,22 @@ function sucuriscan_settings_webinfo_details()
86
  $info_vars[$php_flag_name] = $php_flag_value ? $php_flag_value : 'N/A';
87
  }
88
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  foreach ($info_vars as $var_name => $var_value) {
90
  $var_name = str_replace('_', "\x20", $var_name);
91
 
@@ -99,106 +116,6 @@ function sucuriscan_settings_webinfo_details()
99
  return SucuriScanTemplate::getSection('settings-webinfo-details', $params);
100
  }
101
 
102
- /**
103
- * Retrieve all the constants and variables with their respective values defined
104
- * in the WordPress configuration file, only the database password constant is
105
- * omitted for security reasons.
106
- *
107
- * @return string The HTML code displaying the constants and variables found in the wp-config file.
108
- */
109
- function sucuriscan_settings_webinfo_wpconfig()
110
- {
111
- $params = array(
112
- 'WordpressConfig.Rules' => '',
113
- 'WordpressConfig.Total' => 0,
114
- );
115
-
116
- $ignore_wp_rules = array('DB_PASSWORD');
117
- $wp_config_path = SucuriScan::getWPConfigPath();
118
-
119
- if ($wp_config_path) {
120
- $wp_config_rules = array();
121
- $wp_config_content = SucuriScanFileInfo::fileLines($wp_config_path);
122
-
123
- // Parse the main configuration file and look for constants and global variables.
124
- foreach ((array) $wp_config_content as $line) {
125
- if (@preg_match('/^\s?(#|\/\/)/', $line)) {
126
- continue; /* Ignore commented lines. */
127
- } elseif (@preg_match('/define\(/', $line)) {
128
- // Detect PHP constants even if the line if indented.
129
- $line = preg_replace('/.*define\((.+)\);.*/', '$1', $line);
130
- $line_parts = explode(',', $line, 2);
131
- } elseif (@preg_match('/^\$[a-zA-Z_]+/', $line)) {
132
- // Detect global variables like the database table prefix.
133
- $line = @preg_replace('/;\s\/\/.*/', ';', $line);
134
- $line_parts = explode('=', $line, 2);
135
- } else {
136
- continue; /* Ignore other lines. */
137
- }
138
-
139
- // Clean and append the rule to the wp_config_rules variable.
140
- if (isset($line_parts) && count($line_parts) === 2) {
141
- $key_name = '';
142
- $key_value = '';
143
-
144
- // TODO: A foreach loop is not really necessary, find a better way.
145
- foreach ($line_parts as $i => $line_part) {
146
- $line_part = trim($line_part);
147
- $line_part = ltrim($line_part, '$');
148
- $line_part = rtrim($line_part, ';');
149
-
150
- // Remove single/double quotes at the beginning and end of the string.
151
- $line_part = ltrim($line_part, "'");
152
- $line_part = rtrim($line_part, "'");
153
- $line_part = ltrim($line_part, '"');
154
- $line_part = rtrim($line_part, '"');
155
-
156
- // Assign the clean strings to specific variables.
157
- if ($i == 0) {
158
- $key_name = $line_part;
159
- }
160
-
161
- if ($i == 1) {
162
- if (defined($key_name)) {
163
- $key_value = constant($key_name);
164
-
165
- if (is_bool($key_value)) {
166
- $key_value = ($key_value === true) ? 'True' : 'False';
167
- }
168
- } else {
169
- $key_value = $line_part;
170
- }
171
- }
172
- }
173
-
174
- // Remove the value of sensitive variables like the database password.
175
- if (in_array($key_name, $ignore_wp_rules)) {
176
- $key_value = 'hidden';
177
- }
178
-
179
- // Append the value to the configuration rules.
180
- $wp_config_rules[$key_name] = $key_value;
181
- }
182
- }
183
-
184
- // Pass the WordPress configuration rules to the template and show them.
185
- foreach ($wp_config_rules as $var_name => $var_value) {
186
- if (empty($var_value)) {
187
- $var_value = '--';
188
- }
189
-
190
- $params['WordpressConfig.Total'] += 1;
191
- $params['WordpressConfig.Rules'] .=
192
- SucuriScanTemplate::getSnippet('settings-webinfo-wpconfig', array(
193
- 'WordpressConfig.VariableName' => $var_name,
194
- 'WordpressConfig.VariableValue' => $var_value,
195
- ));
196
- }
197
- }
198
-
199
- return SucuriScanTemplate::getSection('settings-webinfo-wpconfig', $params);
200
- }
201
-
202
  /**
203
  * Find the main htaccess file for the site and check whether the rules of the
204
  * main htaccess file of the site are the default rules generated by WordPress.
35
  'Datetime_and_Timezone' => '',
36
  'Operating_system' => sprintf('%s (%d Bit)', PHP_OS, PHP_INT_SIZE * 8),
37
  'Server' => __('Unknown', SUCURISCAN_TEXTDOMAIN),
38
+ 'WordPress_debug' => __('NotActive', SUCURISCAN_TEXTDOMAIN),
39
  'Memory_usage' => __('Unknown', SUCURISCAN_TEXTDOMAIN),
40
  'MySQL_version' => '0.0',
41
  'SQL_mode' => __('NotSet', SUCURISCAN_TEXTDOMAIN),
43
  );
44
 
45
  $info_vars['Datetime_and_Timezone'] = sprintf(
46
+ '%s (%s)',
47
+ SucuriScan::datetime(),
48
+ SucuriScanOption::getOption(':timezone')
49
  );
50
 
51
  if (defined('WP_DEBUG') && WP_DEBUG) {
52
+ $info_vars['WordPress_debug'] = __('Active', SUCURISCAN_TEXTDOMAIN);
53
  }
54
 
55
  if (function_exists('memory_get_usage')) {
69
  }
70
  }
71
 
72
+ /* PHP INI Settings */
73
  $field_names = array(
74
  'safe_mode',
75
  'expose_php',
87
  $info_vars[$php_flag_name] = $php_flag_value ? $php_flag_value : 'N/A';
88
  }
89
 
90
+ /* PHP constants */
91
+ $constants = array(
92
+ 'ABSPATH',
93
+ // 'SUCURISCAN',
94
+ // 'SUCURISCAN_INIT',
95
+ 'SUCURISCAN_API_URL',
96
+ 'SUCURI_DATA_STORAGE',
97
+ // 'SUCURISCAN_ADMIN_INIT',
98
+ 'SUCURISCAN_GET_PLUGINS_LIFETIME',
99
+ 'SUCURISCAN_THROW_EXCEPTIONS',
100
+ );
101
+
102
+ foreach ($constants as $name) {
103
+ $info_vars[$name] = defined($name) ? constant($name) : '--';
104
+ }
105
+
106
  foreach ($info_vars as $var_name => $var_value) {
107
  $var_name = str_replace('_', "\x20", $var_name);
108
 
116
  return SucuriScanTemplate::getSection('settings-webinfo-details', $params);
117
  }
118
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  /**
120
  * Find the main htaccess file for the site and check whether the rules of the
121
  * main htaccess file of the site are the default rules generated by WordPress.
src/sitecheck.lib.php CHANGED
@@ -32,27 +32,39 @@ if (!defined('SUCURISCAN_INIT') || SUCURISCAN_INIT !== true) {
32
  */
33
  class SucuriScanSiteCheck extends SucuriScanAPI
34
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  /**
36
  * Executes a malware scan against the specified website.
37
  *
38
  * @see https://sitecheck.sucuri.net/
39
  *
40
- * @param string $domain The clean version of the website's domain.
41
  * @param bool $clear Request the results from a fresh scan or not.
42
  * @return array|bool JSON encoded website scan results.
43
  */
44
- public static function runMalwareScan($domain = '', $clear = true)
45
  {
46
- if (empty($domain)) {
47
- return false;
48
- }
49
-
50
  $params = array();
51
- $params['scan'] = $domain;
52
- $params['fromwp'] = 2;
53
  $params['json'] = 1;
 
 
54
 
55
- // Request a fresh scan or not.
56
  if ($clear === true) {
57
  $params['clear'] = 1;
58
  }
@@ -86,33 +98,19 @@ class SucuriScanSiteCheck extends SucuriScanAPI
86
  */
87
  public static function scanAndCollectData()
88
  {
89
- $tld = SucuriScan::getDomain();
90
  $cache = new SucuriScanCache('sitecheck');
91
  $results = $cache->get('scan_results', SUCURISCAN_SITECHECK_LIFETIME, 'array');
92
 
93
- /**
94
- * Allow the user to scan foreign domains.
95
- *
96
- * This condition allows for the execution of the malware scanner on a
97
- * website different than the one where the plugin is installed. This is
98
- * basically the same as scanning any domain on the SiteCheck website.
99
- * In this case, this is mostly used to allow the development execute
100
- * tests and to troubleshoot issues reported by other users.
101
- *
102
- * @var boolean
103
- */
104
- if ($custom = SucuriScanRequest::get('s')) {
105
- $tld = SucuriScan::escape($custom);
106
- $results = false /* invalid cache */;
107
- }
108
-
109
  /* return cached malware scan results. */
110
  if ($results && !empty($results)) {
111
  return $results;
112
  }
113
 
 
 
 
114
  /* send HTTP request to SiteCheck's API service. */
115
- $results = self::runMalwareScan($tld);
116
 
117
  /* check for error in the request's response. */
118
  if (is_string($results) || isset($results['SYSTEM']['ERROR'])) {
@@ -124,7 +122,6 @@ class SucuriScanSiteCheck extends SucuriScanAPI
124
  }
125
 
126
  /* cache the results for some time. */
127
- $cache = new SucuriScanCache('sitecheck');
128
  $cache->add('scan_results', $results);
129
 
130
  return $results;
@@ -398,23 +395,8 @@ class SucuriScanSiteCheck extends SucuriScanAPI
398
  */
399
  public static function iFramesContent()
400
  {
401
- $params = array();
402
  $data = self::scanAndCollectData();
403
-
404
- if (!isset($data['LINKS']['IFRAME'])) {
405
- return ''; /* empty content */
406
- }
407
-
408
- $params['SiteCheck.Resources'] = '';
409
-
410
- foreach ($data['LINKS']['IFRAME'] as $url) {
411
- $params['SiteCheck.Resources'] .=
412
- SucuriScanTemplate::getSnippet('sitecheck-links', array(
413
- 'SiteCheck.URL' => $url,
414
- ));
415
- }
416
-
417
- return SucuriScanTemplate::getSection('sitecheck-links', $params);
418
  }
419
 
420
  /**
@@ -424,64 +406,29 @@ class SucuriScanSiteCheck extends SucuriScanAPI
424
  */
425
  public static function linksContent()
426
  {
427
- $params = array();
428
  $data = self::scanAndCollectData();
429
-
430
- if (!isset($data['LINKS']['URL'])) {
431
- return ''; /* empty content */
432
- }
433
-
434
- $params['SiteCheck.Resources'] = '';
435
-
436
- foreach ($data['LINKS']['URL'] as $url) {
437
- $params['SiteCheck.Resources'] .=
438
- SucuriScanTemplate::getSnippet('sitecheck-links', array(
439
- 'SiteCheck.URL' => $url,
440
- ));
441
- }
442
-
443
- return SucuriScanTemplate::getSection('sitecheck-links', $params);
444
  }
445
 
446
  /**
447
  * Returns the content for the scripts section.
448
  *
449
- * @return string Content for the scripts section.
450
  */
451
  public static function scriptsContent()
452
  {
453
- $total = 0;
454
- $params = array();
455
  $data = self::scanAndCollectData();
456
 
457
- $params['SiteCheck.Resources'] = '';
458
-
459
  if (isset($data['LINKS']['JSLOCAL'])) {
460
- foreach ($data['LINKS']['JSLOCAL'] as $url) {
461
- $total++;
462
-
463
- $params['SiteCheck.Resources'] .=
464
- SucuriScanTemplate::getSnippet('sitecheck-links', array(
465
- 'SiteCheck.URL' => $url,
466
- ));
467
- }
468
  }
469
 
470
  if (isset($data['LINKS']['JSEXTERNAL'])) {
471
- foreach ($data['LINKS']['JSEXTERNAL'] as $url) {
472
- $total++;
473
- $params['SiteCheck.Resources'] .=
474
- SucuriScanTemplate::getSnippet('sitecheck-links', array(
475
- 'SiteCheck.URL' => $url,
476
- ));
477
- }
478
- }
479
-
480
- if ($total === 0) {
481
- return ''; /* empty content */
482
  }
483
 
484
- return SucuriScanTemplate::getSection('sitecheck-links', $params);
485
  }
486
 
487
  /**
@@ -516,9 +463,11 @@ class SucuriScanSiteCheck extends SucuriScanAPI
516
  $malware_parts = explode("\n", $malware[1]);
517
 
518
  if (isset($malware_parts[1])) {
519
- if (@preg_match('/(.+)\. Details: (.+)/', $malware_parts[0], $match)) {
520
- $data['malware_type'] = $match[1];
521
- $data['malware_docs'] = $match[2];
 
 
522
  }
523
 
524
  $data['malware_payload'] = trim($malware_parts[1]);
@@ -573,4 +522,25 @@ class SucuriScanSiteCheck extends SucuriScanAPI
573
 
574
  wp_send_json($response, 200);
575
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
576
  }
32
  */
33
  class SucuriScanSiteCheck extends SucuriScanAPI
34
  {
35
+ /**
36
+ * Returns the URL that will be scanned by SiteCheck.
37
+ *
38
+ * @return string URL to be scanned.
39
+ */
40
+ private static function targetURL()
41
+ {
42
+ $url = SucuriScan::getDomain();
43
+
44
+ /* allow to set a custom URL for the scans */
45
+ if ($custom = SucuriScanOption::getOption(':sitecheck_target')) {
46
+ return $custom;
47
+ }
48
+
49
+ return $url;
50
+ }
51
+
52
  /**
53
  * Executes a malware scan against the specified website.
54
  *
55
  * @see https://sitecheck.sucuri.net/
56
  *
 
57
  * @param bool $clear Request the results from a fresh scan or not.
58
  * @return array|bool JSON encoded website scan results.
59
  */
60
+ public static function runMalwareScan($clear = false)
61
  {
 
 
 
 
62
  $params = array();
 
 
63
  $params['json'] = 1;
64
+ $params['fromwp'] = 2;
65
+ $params['scan'] = self::targetURL();
66
 
67
+ /* force clear scan */
68
  if ($clear === true) {
69
  $params['clear'] = 1;
70
  }
98
  */
99
  public static function scanAndCollectData()
100
  {
 
101
  $cache = new SucuriScanCache('sitecheck');
102
  $results = $cache->get('scan_results', SUCURISCAN_SITECHECK_LIFETIME, 'array');
103
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  /* return cached malware scan results. */
105
  if ($results && !empty($results)) {
106
  return $results;
107
  }
108
 
109
+ /* delete expired cache */
110
+ $cache->delete('scan_results');
111
+
112
  /* send HTTP request to SiteCheck's API service. */
113
+ $results = self::runMalwareScan();
114
 
115
  /* check for error in the request's response. */
116
  if (is_string($results) || isset($results['SYSTEM']['ERROR'])) {
122
  }
123
 
124
  /* cache the results for some time. */
 
125
  $cache->add('scan_results', $results);
126
 
127
  return $results;
395
  */
396
  public static function iFramesContent()
397
  {
 
398
  $data = self::scanAndCollectData();
399
+ return isset($data['LINKS']['IFRAME']) ? $data['LINKS']['IFRAME'] : array();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
400
  }
401
 
402
  /**
406
  */
407
  public static function linksContent()
408
  {
 
409
  $data = self::scanAndCollectData();
410
+ return isset($data['LINKS']['URL']) ? $data['LINKS']['URL'] : array();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
411
  }
412
 
413
  /**
414
  * Returns the content for the scripts section.
415
  *
416
+ * @return array Content for the scripts section.
417
  */
418
  public static function scriptsContent()
419
  {
420
+ $links = array();
 
421
  $data = self::scanAndCollectData();
422
 
 
 
423
  if (isset($data['LINKS']['JSLOCAL'])) {
424
+ $links = array_merge($links, $data['LINKS']['JSLOCAL']);
 
 
 
 
 
 
 
425
  }
426
 
427
  if (isset($data['LINKS']['JSEXTERNAL'])) {
428
+ $links = array_merge($links, $data['LINKS']['JSEXTERNAL']);
 
 
 
 
 
 
 
 
 
 
429
  }
430
 
431
+ return $links;
432
  }
433
 
434
  /**
463
  $malware_parts = explode("\n", $malware[1]);
464
 
465
  if (isset($malware_parts[1])) {
466
+ $pattern = ".\x20Details:\x20";
467
+ if (strpos($malware_parts[0], $pattern) !== false) {
468
+ $offset = strpos($malware_parts[0], $pattern);
469
+ $data['malware_type'] = substr($malware_parts[0], 0, $offset);
470
+ $data['malware_docs'] = substr($malware_parts[0], $offset+11);
471
  }
472
 
473
  $data['malware_payload'] = trim($malware_parts[1]);
522
 
523
  wp_send_json($response, 200);
524
  }
525
+
526
+ /**
527
+ * Returns the HTML to configure the API SiteCheck service.
528
+ *
529
+ * @return string HTML for the API SiteCheck service option.
530
+ */
531
+ public static function targetURLOption()
532
+ {
533
+ $params = array();
534
+
535
+ if (SucuriScanInterface::checkNonce()) {
536
+ $custom = SucuriScanRequest::post(':sitecheck_target');
537
+ if ($custom !== false) {
538
+ SucuriScanOption::updateOption(':sitecheck_target', $custom);
539
+ }
540
+ }
541
+
542
+ $params['SiteCheck.Target'] = self::targetURL();
543
+
544
+ return SucuriScanTemplate::getSection('sitecheck-target', $params);
545
+ }
546
  }
src/sucuriscan.lib.php CHANGED
@@ -593,25 +593,31 @@ class SucuriScan
593
  */
594
  public static function isBehindFirewall($verbose = false)
595
  {
 
 
 
596
  $http_host = self::getTopLevelDomain();
597
 
598
- if (self::executeDNSLookups()) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
599
  $host_by_addr = @gethostbyname($http_host);
600
  $host_by_name = @gethostbyaddr($host_by_addr);
601
  $status = (bool) preg_match('/^cloudproxy[0-9]+\.sucuri\.net$/', $host_by_name);
602
- } else {
603
- $status = false;
604
- $host_by_addr = '::1';
605
- $host_by_name = 'localhost';
606
- }
607
-
608
- /*
609
- * If the DNS reversion failed but the firewall API key is set, then consider
610
- * the site as protected by a firewall. A fake key can be used to bypass the DNS
611
- * checking, but that is not something that will affect us, only the client.
612
- */
613
- if (!$status && SucuriScanFirewall::getKey()) {
614
- $status = true;
615
  }
616
 
617
  if ($verbose) {
@@ -697,17 +703,6 @@ class SucuriScan
697
  return $valid_users;
698
  }
699
 
700
- /**
701
- * Returns the current time measured in the number of seconds since the Unix Epoch.
702
- *
703
- * @see https://developer.wordpress.org/reference/functions/current_time/
704
- * @return int Return current Unix timestamp.
705
- */
706
- public static function localTime()
707
- {
708
- return current_time('timestamp', false);
709
- }
710
-
711
  /**
712
  * Retrieve the date in localized format, based on timestamp.
713
  *
@@ -715,70 +710,42 @@ class SucuriScan
715
  * take over the format for the date. If it isn't, then the date format string
716
  * will be used instead.
717
  *
718
- * @param int $timestamp Unix timestamp.
 
719
  * @return string The date, translated if locale specifies it.
720
  */
721
- public static function datetime($timestamp = null)
722
  {
723
- global $sucuriscan_date_format, $sucuriscan_time_format;
 
 
724
 
725
- $tz_format = $sucuriscan_date_format . "\x20" . $sucuriscan_time_format;
726
-
727
- if (is_numeric($timestamp) && $timestamp > 0) {
728
- return date_i18n($tz_format, $timestamp);
729
  }
730
 
731
- return date_i18n($tz_format);
732
- }
733
-
734
- /**
735
- * Retrieve the date in localized format based on the current time.
736
- *
737
- * @return string The date, translated if locale specifies it.
738
- */
739
- public static function currentDateTime()
740
- {
741
- return self::datetime();
742
- }
743
-
744
- /**
745
- * Return the time passed since the specified timestamp until now.
746
- *
747
- * @param int|string $timestamp Unix time of a day in the past.
748
- * @return string Time passed since the timestamp specified.
749
- */
750
- public static function timeAgo($timestamp = 0)
751
- {
752
- if (!is_numeric($timestamp)) {
753
- $timestamp = strtotime($timestamp);
754
  }
755
 
756
- $local_time = self::localTime();
757
- $diff = abs($local_time - intval($timestamp));
758
-
759
- if ($diff < 3) {
760
- return 'just now';
 
761
  }
762
 
763
- $intervals = array(
764
- 1 => array( 'year', 31556926, ),
765
- $diff < 31556926 => array( 'month', 2592000, ),
766
- $diff < 2592000 => array( 'week', 604800, ),
767
- $diff < 604800 => array( 'day', 86400, ),
768
- $diff < 86400 => array( 'hour', 3600, ),
769
- $diff < 3600 => array( 'minute', 60, ),
770
- $diff < 60 => array( 'second', 1, ),
771
- );
772
-
773
- $value = floor($diff / $intervals[1][1]);
774
- $time_ago = sprintf(
775
- '%s %s%s ago',
776
- $value,
777
- $intervals[1][0],
778
- ( $value > 1 ? 's' : '' )
779
- );
780
-
781
- return $time_ago;
782
  }
783
 
784
  /**
@@ -925,7 +892,7 @@ class SucuriScan
925
  */
926
  public static function isNginxServer()
927
  {
928
- return (bool) preg_match('/^nginx(\/[0-9\.]+)?$/', @$_SERVER['SERVER_SOFTWARE']);
929
  }
930
 
931
  /**
@@ -935,7 +902,7 @@ class SucuriScan
935
  */
936
  public static function isIISServer()
937
  {
938
- return (bool) preg_match('/Microsoft-IIS/i', @$_SERVER['SERVER_SOFTWARE']);
939
  }
940
 
941
  /**
593
  */
594
  public static function isBehindFirewall($verbose = false)
595
  {
596
+ $status = false;
597
+ $host_by_addr = '::1';
598
+ $host_by_name = 'localhost';
599
  $http_host = self::getTopLevelDomain();
600
 
601
+ /**
602
+ * Consider firewall protected if the API key is set.
603
+ *
604
+ * Assume that the Sucuri Firewall is protecting this website if there
605
+ * is a valid API key set in the Firewall page, otherwise execute the
606
+ * DNS lookup to try to find the name of the server which will help us
607
+ * determine if the website is behind the Sucuri Firewall or not.
608
+ *
609
+ * Notice that this DNS lookup may slow down a website that is hosted in
610
+ * a hosting pointing to a slow DNS server, the latency in the queries
611
+ * will be noticeable. Webmasters can disable this behavior by setting
612
+ * the ":dns_lookups" option as "disabled" or adding this constant to
613
+ * the WordPress configuration file: (NOT_USING_CLOUDPROXY, true)
614
+ */
615
+ if (SucuriScanFirewall::getKey()) {
616
+ $status = true;
617
+ } elseif (self::executeDNSLookups()) {
618
  $host_by_addr = @gethostbyname($http_host);
619
  $host_by_name = @gethostbyaddr($host_by_addr);
620
  $status = (bool) preg_match('/^cloudproxy[0-9]+\.sucuri\.net$/', $host_by_name);
 
 
 
 
 
 
 
 
 
 
 
 
 
621
  }
622
 
623
  if ($verbose) {
703
  return $valid_users;
704
  }
705
 
 
 
 
 
 
 
 
 
 
 
 
706
  /**
707
  * Retrieve the date in localized format, based on timestamp.
708
  *
710
  * take over the format for the date. If it isn't, then the date format string
711
  * will be used instead.
712
  *
713
+ * @param null|string|int $timestamp Unix timestamp.
714
+ * @param string $format Optional format for the date and time.
715
  * @return string The date, translated if locale specifies it.
716
  */
717
+ public static function datetime($timestamp = null, $format = null)
718
  {
719
+ $diff = 0; /* use server time */
720
+ $tz = SucuriScanOption::getOption(':timezone');
721
+ $length = strlen($tz); /* example: UTC+12.75 */
722
 
723
+ if ($timestamp === null) {
724
+ $timestamp = time();
 
 
725
  }
726
 
727
+ if ($length === 9
728
+ && substr($tz, 0, 3) === 'UTC'
729
+ && ($tz[3] === '-' || $tz[3] === '+')
730
+ && $tz[6] === '.'
731
+ ) {
732
+ $hour = (float) substr($tz, 4);
733
+ $sign = ($tz[3] === '-') ? -1 : +1;
734
+ $diff = ($hour * $sign);
735
+ } else {
736
+ /* reset; value seems to be corrupt */
737
+ SucuriScanOption::deleteOption(':timezone');
 
 
 
 
 
 
 
 
 
 
 
 
738
  }
739
 
740
+ if ($format === null) {
741
+ $format = sprintf(
742
+ "%s\x20%s",
743
+ SucuriScanOption::getOption('date_format'),
744
+ SucuriScanOption::getOption('time_format')
745
+ );
746
  }
747
 
748
+ return date($format, (intval($timestamp) + ($diff * 3600)));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
749
  }
750
 
751
  /**
892
  */
893
  public static function isNginxServer()
894
  {
895
+ return (bool) (stripos(@$_SERVER['SERVER_SOFTWARE'], 'nginx') !== false);
896
  }
897
 
898
  /**
902
  */
903
  public static function isIISServer()
904
  {
905
+ return (bool) (stripos(@$_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') !== false);
906
  }
907
 
908
  /**
src/template.lib.php CHANGED
@@ -292,7 +292,7 @@ class SucuriScanTemplate extends SucuriScanRequest
292
  /* replace the global pseudo-variables in the section/snippets templates. */
293
  if ($template == 'base'
294
  && array_key_exists('PageContent', $params)
295
- && @preg_match('/%%SUCURI\.(.+)%%/', $params['PageContent'])
296
  ) {
297
  $params['PageContent'] = self::replacePseudoVars($params['PageContent'], $params);
298
  }
@@ -432,7 +432,7 @@ class SucuriScanTemplate extends SucuriScanRequest
432
  */
433
  public static function pagination($base_url = '', $total_items = 0, $max_per_page = 1)
434
  {
435
- // Calculate the number of links for the pagination.
436
  $html_links = '';
437
  $page_number = self::pageNumber();
438
  $max_pages = ceil($total_items / $max_per_page);
@@ -440,13 +440,14 @@ class SucuriScanTemplate extends SucuriScanRequest
440
  $start_page = 1;
441
  $extra_url = '';
442
 
443
- // Fix for inline anchor URLs.
444
- if (@preg_match('/^(.+)(#.+)$/', $base_url, $match)) {
445
- $base_url = $match[1];
446
- $extra_url = $match[2];
 
447
  }
448
 
449
- // Keep the number of pagination buttons at limit.
450
  if ($max_pages > SUCURISCAN_MAX_PAGINATION_BUTTONS) {
451
  $final_page = SUCURISCAN_MAX_PAGINATION_BUTTONS;
452
  $middle = $final_page / 2; /* middle point */
@@ -457,7 +458,7 @@ class SucuriScanTemplate extends SucuriScanRequest
457
  }
458
  }
459
 
460
- // Generate the HTML links for the pagination.
461
  for ($j = $start_page; $j <= $final_page; $j++) {
462
  $link_class = 'sucuriscan-pagination-link';
463
 
292
  /* replace the global pseudo-variables in the section/snippets templates. */
293
  if ($template == 'base'
294
  && array_key_exists('PageContent', $params)
295
+ && strpos($params['PageContent'], '%%SUCURI.') !== false
296
  ) {
297
  $params['PageContent'] = self::replacePseudoVars($params['PageContent'], $params);
298
  }
432
  */
433
  public static function pagination($base_url = '', $total_items = 0, $max_per_page = 1)
434
  {
435
+ /* calculate the number of links for the pagination */
436
  $html_links = '';
437
  $page_number = self::pageNumber();
438
  $max_pages = ceil($total_items / $max_per_page);
440
  $start_page = 1;
441
  $extra_url = '';
442
 
443
+ /* fix for inline anchor URLs */
444
+ if (($offset = strpos($base_url, '#')) !== false) {
445
+ $clean_url = substr($base_url, 0, $offset);
446
+ $extra_url = substr($base_url, $offset);
447
+ $base_url = $clean_url;
448
  }
449
 
450
+ /* keep the number of pagination buttons at limit */
451
  if ($max_pages > SUCURISCAN_MAX_PAGINATION_BUTTONS) {
452
  $final_page = SUCURISCAN_MAX_PAGINATION_BUTTONS;
453
  $middle = $final_page / 2; /* middle point */
458
  }
459
  }
460
 
461
+ /* generate the HTML links for the pagination */
462
  for ($j = $start_page; $j <= $final_page; $j++) {
463
  $link_class = 'sucuriscan-pagination-link';
464
 
sucuri.php CHANGED
@@ -7,7 +7,7 @@
7
  * Author URI: https://sucuri.net/
8
  * Text Domain: sucuri-scanner
9
  * Author: Sucuri Inc.
10
- * Version: 1.8.7
11
  */
12
 
13
 
@@ -83,12 +83,7 @@ define('SUCURISCAN', 'sucuriscan');
83
  /**
84
  * Current version of the plugin's code.
85
  */
86
- define('SUCURISCAN_VERSION', '1.8.7');
87
-
88
- /**
89
- * The name of the Sucuri plugin main file.
90
- */
91
- define('SUCURISCAN_PLUGIN_FILE', 'sucuri.php');
92
 
93
  /**
94
  * Unique name of the plugin text domain.
@@ -111,15 +106,10 @@ define('SUCURISCAN_PLUGIN_FOLDER', basename(dirname(__FILE__)));
111
  */
112
  define('SUCURISCAN_PLUGIN_PATH', WP_PLUGIN_DIR . '/' . SUCURISCAN_PLUGIN_FOLDER);
113
 
114
- /**
115
- * The fullpath of the main plugin file.
116
- */
117
- define('SUCURISCAN_PLUGIN_FILEPATH', SUCURISCAN_PLUGIN_PATH . '/' . SUCURISCAN_PLUGIN_FILE);
118
-
119
  /**
120
  * The local URL where the plugin's files and assets are served.
121
  */
122
- define('SUCURISCAN_URL', site_url(dirname(str_replace(ABSPATH, '', SUCURISCAN_PLUGIN_FILEPATH))));
123
 
124
  /**
125
  * Remote URL where the public Sucuri API service is running.
7
  * Author URI: https://sucuri.net/
8
  * Text Domain: sucuri-scanner
9
  * Author: Sucuri Inc.
10
+ * Version: 1.8.8
11
  */
12
 
13
 
83
  /**
84
  * Current version of the plugin's code.
85
  */
86
+ define('SUCURISCAN_VERSION', '1.8.8');
 
 
 
 
 
87
 
88
  /**
89
  * Unique name of the plugin text domain.
106
  */
107
  define('SUCURISCAN_PLUGIN_PATH', WP_PLUGIN_DIR . '/' . SUCURISCAN_PLUGIN_FOLDER);
108
 
 
 
 
 
 
109
  /**
110
  * The local URL where the plugin's files and assets are served.
111
  */
112
+ define('SUCURISCAN_URL', plugin_dir_url(__FILE__));
113
 
114
  /**
115
  * Remote URL where the public Sucuri API service is running.