<commit_before>var Fabric = require('fabric').fabric || fabric;
var extend = Fabric.util.object.extend;

module.exports = (function(){

   var Fabric = require('fabric').fabric || fabric;

   return {
      _limitByDiagonal: true,

      /**
       * Resizes this line to make the most sense given the two points (they
       * will determine two opposite corners.
       */
      sizeByMousePos: function(x1, y1, x2, y2) {
         var xd = x2 - x1;
         var yd = y2 - y1;
         var rad = Math.sqrt(xd * xd + yd * yd);
         if (!rad) {
            xd = yd = this._limitDimension(rad);
            var ratio = 1;
         } else {
            var ratio = this._limitDimension(rad) / rad;
         }
         this.x1 = x1;
         this.y1 = y1;
         this.x2 = x1 + ratio * xd;
         this.y2 = y1 + ratio * yd;
         this._setWidthHeight();
         this.setCoords();
      },

      /**
       * Intercept the set('scaleX') calls during resize so we can flip the
       * order of the points when the cursor crosses the origin. Also, we reset
       * the scale to 1 and apply it to the width and height so there isn't a
       * scale transform present when drawing the stroke.
       */
      _set: function(key, value) {
         if (key === 'scaleX' && value < 0) {
            var x1 = this.x1
            this.x1 = this.x2; this.x2 = x1;
         }
         else if (key === 'scaleY' && value < 0) {
            var y1 = this.y1
            this.y1 = this.y2; this.y2 = y1;
         }

         this.callParent(key, value);
         this._resetScale();
         return this;
      },

      /**
       * Apply the scaling to the width and height and set scale to 1 so
       * that stroke width is independent of the scale transform
       */
      _resetScale: function() {
         // There is a brief period where scaleX == 0 and fabric.js disappears
         // objects that have width = 0 so we can't let that happen.
         if (this.scaleX == 0) {
            this.width = 1
         } else {
            // Note: there is a brief period (one frame) where the scale goes
            // negative when the resize control crosses an axis. Using abs()
            // keeps the motion fluid instead of a few pixel jump.
            this.width *= Math.abs(this.scaleX);
         }

         if (this.scaleY == 0) {
            this.height = 1;
         } else {
            this.height *= Math.abs(this.scaleY);
         }

         this.scaleX = 1;
         this.scaleY = 1;
      },

      /**
       * We don't want line-based shapes to have a bounding box (it looks dumb
       * around lines.
       */
      drawBorders: function(ctx) {
         return this;
      },

      /**
       * Override the `drawControls` to only draw handles at endpoints of the
       * line (two corners of the bounding box) instead of all corners and all
       * midpoints.
       */
      drawControls: function(ctx) {
         var self = this;
         if (!this.hasControls) return self;

         ctx.save();
         ctx.lineWidth = 1 / Math.max(self.scaleX, self.scaleY);
         ctx.globalAlpha = 0.9;
         ctx.strokeStyle = ctx.fillStyle = self.cornerColor;
         ctx.beginPath();

         function circle(x,y) {
            ctx.arc(x, y, self.cornerSize/1.4, 0, 2 * Math.PI, false);
         }

         var flipX = self.x1 > self.x2 ? 1 : -1;
         var flipY = self.y1 > self.y2 ? 1 : -1;
         var halfWidth  = self.width  === 1 ? 0 : self.width / 2;
         var halfHeight = self.height === 1 ? 0 : self.height / 2;
         // In this context, 0,0 is the center of the line so we draw a handle
         // half of the line length away from the origin in both directions.
         circle(halfWidth * flipX, halfHeight * flipY);
         circle(-halfWidth * flipX, -halfHeight * flipY);
         ctx.fill();

         ctx.restore();
         return self;
      },

      /**
       * If a line is perfectly vertical or horizontal and the outside edges of
       * the borders are not lined up with pixels exactly, canvas will antialias
       * them which looks bad.
       *
       * To prevent this, we calculate if the borders will be splitting pixels,
       * adjust the positioning, call the callback and restore the position.
       */
      _fixAndRestoreSubPixelPositioning: function(callback) {
         var oldT = this.top,
             oldL = this.left;

         // Preconditions: width, height, borderWidth are all ints
         // left, top represent the middle of the line
         // Note x % 1 effectively does x - (int)x
         var borderWidth = this.borderWidth + (this.outlineWidth * this.borderWidth);
         if (this.width <= 1) {
            this.left -= (this.left + borderWidth / 2) % 1;
         }
         if (this.height <= 1) {
            this.top -= (this.top + borderWidth / 2) % 1;
         }

         callback.call(this);

         this.top  = oldT;
         this.left = oldL;
      },

      getEndpoints: function() {
         var self = this;
         var flipX = this.flipX ? -1 :  1;
         var flipY = this.flipY ? -1 :  1;
         // Objects in fabric can't have 0-width, so a vertical line ends up
         // with witdth = 1 so we detect that and ensure the midpoint isn't on
         // a pixel boundary and the width actually ends up 0.
         var halfWidth  = self.width  === 1 ? 0 : self.width / 2;
         var halfHeight = self.height === 1 ? 0 : self.height / 2;
         var left = self.width  === 1 ? Math.floor(self.left) : self.left;
         var top  = self.height === 1 ? Math.floor(self.top)  : self.top;
         return {
            x1: (left + halfWidth * flipX),
            y1: (top + halfHeight * flipY),
            x2: (left - halfWidth * flipX),
            y2: (top - halfHeight * flipY)
         };
      },

      toMarkup: function(scale) {
         var p = this.getEndpoints();
         return [
             this.type,
             p.x1 / scale + 'x' + p.y1 / scale,
             p.x2 / scale + 'x' + p.y2 / scale,
             this.color
         ].join(',') + ';';
      },

      toObject: function(propertiesToInclude) {
         var points = this.getEndpoints();
         return extend(this.callParent(propertiesToInclude), points);
      },

      /**
       * Returns the angle of this line in radians
       * where horizontal and x1 < x2 * y2 = 0
       */
      _getAngle: function() {
         return Math.atan2(this._getDeltaY(), this._getDeltaX());
      },

      /**
       * Get the deltaX of the given line.
       * Note: rounds to 0 if <= 1 cause Fabric never allows 0-width
       * objects.
       */
      _getDeltaX: function() {
         var delta = this.x1 <= this.x2 ? -this.width : this.width;
         return Math.abs(delta) <= 1 ? 0 : delta;
      },

      /**
       * Get the deltaY of the given line.
       * Note: rounds to 0 if <= 1 cause Fabric never allows
       * 0-width objects.
       */
      _getDeltaY: function() {
         var delta = this.y1 <= this.y2 ? -this.height : this.height;
         return Math.abs(delta) <= 1 ? 0 : delta;
      },

      _getLength: function() {
         return Math.sqrt(this.width * this.width +
                          this.height * this.height);
      }
   }
})();
<commit_msg>Lines: update for new version of Fabric.js (v 1.5.0)<commit_after>var Fabric = require('fabric').fabric || fabric;
var extend = Fabric.util.object.extend;

module.exports = (function(){

   var Fabric = require('fabric').fabric || fabric;

   return {
      initialize: function() {
         // Disable all controls by default
         this._controlsVisibility = { };
         this._enableCorrectControls();
         this.callParent.apply(this, arguments);
      },

      _limitByDiagonal: true,

      /**
       * Resizes this line to make the most sense given the two points (they
       * will determine two opposite corners.
       */
      sizeByMousePos: function(x1, y1, x2, y2) {
         var xd = x2 - x1;
         var yd = y2 - y1;
         var rad = Math.sqrt(xd * xd + yd * yd);
         if (!rad) {
            xd = yd = this._limitDimension(rad);
            var ratio = 1;
         } else {
            var ratio = this._limitDimension(rad) / rad;
         }
         this.x1 = x1;
         this.y1 = y1;
         this.x2 = x1 + ratio * xd;
         this.y2 = y1 + ratio * yd;
         this._setWidthHeight();
         this._resetScale();
         this.setCoords();
      },

      /**
       * Enable only the controls that make sense for the given direction of
       * the line. This prevents the user from clicking controls that we don't
       * draw.
       */
      _enableCorrectControls: function () {
         var px = this._signOfDeltaX();
         var py = this._signOfDeltaY();
         var sameSign = px === py;
         this.setControlsVisibility({
            tl: sameSign,
            br: sameSign,
            tr: !sameSign,
            bl: !sameSign
         });
      },

      /**
       * Intercept the set('scaleX') calls during resize so we can flip the
       * order of the points when the cursor crosses the origin. Also, we reset
       * the scale to 1 and apply it to the width and height so there isn't a
       * scale transform present when drawing the stroke.
       */
      _set: function(key, value) {
         this.callParent(key, value);
         this._resetScale();
         return this;
      },

      /**
       * Apply the scaling to the width and height and set scale to 1 so
       * that stroke width is independent of the scale transform
       */
      _resetScale: function() {
         // There is a brief period where scaleX == 0 and fabric.js disappears
         // objects that have width = 0 so we can't let that happen.
         if (this.scaleX == 0) {
            this.width = 1
         } else {
            this.width *= this.scaleX;
         }

         if (this.scaleY == 0) {
            this.height = 1;
         } else {
            this.height *= this.scaleY;
         }

         this.scaleX = 1;
         this.scaleY = 1;
         this._enableCorrectControls();
      },

      /**
       * We don't want line-based shapes to have a bounding box (it looks dumb
       * around lines.
       */
      drawBorders: function(ctx) {
         return this;
      },

      /**
       * Override the `drawControls` to only draw handles at endpoints of the
       * line (two corners of the bounding box) instead of all corners and all
       * midpoints. Also, draw pretty circles instead of squares.
       */
      drawControls: function(ctx) {
         var self = this;
         if (!this.hasControls) return self;

         ctx.save();
         ctx.lineWidth = 1 / Math.max(self.scaleX, self.scaleY);
         ctx.globalAlpha = 0.9;
         ctx.strokeStyle = ctx.fillStyle = self.cornerColor;
         ctx.beginPath();

         function circle(x,y) {
            ctx.arc(x, y, self.cornerSize/1.4, 0, 2 * Math.PI, false);
         }

         var flipX = self._signOfDeltaX();
         var flipY = self._signOfDeltaY();
         var halfWidth  = self.width  === 1 ? 0 : self.width / 2;
         var halfHeight = self.height === 1 ? 0 : self.height / 2;
         // In this context, 0,0 is the center of the line so we draw a handle
         // half of the line length away from the origin in both directions.
         circle(halfWidth * flipX, halfHeight * flipY);
         circle(-halfWidth * flipX, -halfHeight * flipY);
         ctx.fill();

         ctx.restore();
         return self;
      },

      /**
       * If a line is perfectly vertical or horizontal and the outside edges of
       * the borders are not lined up with pixels exactly, canvas will antialias
       * them which looks bad.
       *
       * To prevent this, we calculate if the borders will be splitting pixels,
       * adjust the positioning, call the callback and restore the position.
       */
      _fixAndRestoreSubPixelPositioning: function(callback) {
         var oldT = this.top,
             oldL = this.left;

         // Preconditions: width, height, borderWidth are all ints
         // left, top represent the middle of the line
         // Note x % 1 effectively does x - (int)x
         var borderWidth = this.borderWidth + (this.outlineWidth * this.borderWidth);
         if (this.width <= 1) {
            this.left -= (this.left + borderWidth / 2) % 1;
         }
         if (this.height <= 1) {
            this.top -= (this.top + borderWidth / 2) % 1;
         }

         callback.call(this);

         this.top  = oldT;
         this.left = oldL;
      },

      getEndpoints: function() {
         var self = this;
         var flipX = self._signOfDeltaX();
         var flipY = self._signOfDeltaY();
         // Objects in fabric can't have 0-width, so a vertical line ends up
         // with witdth = 1 so we detect that and ensure the midpoint isn't on
         // a pixel boundary and the width actually ends up 0.
         var halfWidth  = self.width  === 1 ? 0 : self.width / 2;
         var halfHeight = self.height === 1 ? 0 : self.height / 2;
         var left = self.width  === 1 ? Math.floor(self.left) : self.left;
         var top  = self.height === 1 ? Math.floor(self.top)  : self.top;
         return {
            x1: (left + halfWidth * flipX),
            y1: (top + halfHeight * flipY),
            x2: (left - halfWidth * flipX),
            y2: (top - halfHeight * flipY)
         };
      },

      _signOfDeltaX: function() {
         // During creation, These point values change
         var flip = (this.x1 > this.x2) ? -1 :  1;
         // During sizing, the this.flip? values change
         return (this.flipX) ? -flip : flip;
      },

      _signOfDeltaY: function() {
         // During creation, These point values change
         var flip = (this.y1 > this.y2) ? -1 :  1;
         // During sizing, the this.flip? values change
         return (this.flipY) ? -flip : flip;
      },

      toMarkup: function(scale) {
         var p = this.getEndpoints();
         return [
             this.type,
             p.x1 / scale + 'x' + p.y1 / scale,
             p.x2 / scale + 'x' + p.y2 / scale,
             this.color
         ].join(',') + ';';
      },

      toObject: function(propertiesToInclude) {
         var points = this.getEndpoints();
         return extend(this.callParent(propertiesToInclude), points);
      },

      /**
       * Returns the angle of this line in radians
       * where horizontal and x1 < x2 * y2 = 0
       */
      _getAngle: function() {
         return Math.atan2(this._getDeltaY(), this._getDeltaX());
      },

      /**
       * Get the deltaX of the given line.
       * Note: rounds to 0 if <= 1 cause Fabric never allows 0-width
       * objects.
       */
      _getDeltaX: function() {
         var delta = this.x1 <= this.x2 ? -this.width : this.width;
         return Math.abs(delta) <= 1 ? 0 : delta;
      },

      /**
       * Get the deltaY of the given line.
       * Note: rounds to 0 if <= 1 cause Fabric never allows
       * 0-width objects.
       */
      _getDeltaY: function() {
         var delta = this.y1 <= this.y2 ? -this.height : this.height;
         return Math.abs(delta) <= 1 ? 0 : delta;
      },

      _getLength: function() {
         return Math.sqrt(this.width * this.width +
                          this.height * this.height);
      }
   }
})();
<|endoftext|>


<commit_before>'use strict';

var randu = require( '@stdlib/math/base/random/randu' );
var mean = require( './../lib' );

var alpha;
var beta;
var v;
var i;

for ( i = 0; i < 10; i++ ) {
	alpha = randu() * 10.0;
	beta = randu() * 10.0;
	v = mean( alpha, beta );
	console.log( 'α: %d, β: %d, E(X;α,β): %d',
		alpha.toFixed( 4 ),
		beta.toFixed( 4 ),
		v.toFixed( 4 )
	);
}

<commit_msg>Guard against NaN<commit_after>'use strict';

var randu = require( '@stdlib/math/base/random/randu' );
var EPS = require( '@stdlib/math/constants/float64-eps' );
var mean = require( './../lib' );

var alpha;
var beta;
var v;
var i;

for ( i = 0; i < 10; i++ ) {
	alpha = ( randu()*10.0 ) + EPS;
	beta = ( randu()*10.0 ) + EPS;
	v = mean( alpha, beta );
	console.log( 'α: %d, β: %d, E(X;α,β): %d', alpha.toFixed( 4 ), beta.toFixed( 4 ), v.toFixed( 4 ) );
}

<|endoftext|>


<commit_before>var request = require('request'),
    async = require('async');
var exception = require('./exception.js');

var create = function(err, data, callback) {
  async.waterfall([function(callback){
	  if (err) throw err;
	  validate_request(data);
	  request.post({url:'https://challonge.com/api/tournaments.json', data: data}, function done(err, httpResponse, body) {
	    if (err) {
	      console.error('upload failed:', err);
	    }
	    console.log('Upload successful!  Server responded with:', body);
	  });
  }], callback)
}

var save = function(err, data, callback) {
  async.waterfall([function(callback) {
	  if (err) throw err;
	  validate_request(data);
	  request.put({url:'https://challonge.com/api/tournaments.json', data: data}, function done(err, httpResponse, body) {
	    if (err) {
	      return console.error('upload failed:', err);
	    }
	    console.log('Update successful! Server responded with:', body);
	  });
  }], callback)
};

var delete = function(err, data, callback) {
  async.waterfall([function(callback) {
	  if (err) throw err;
	  validate_request(data);
	  console.log(data.tournament.toString());
  }], callback)
};

function validate_request(data) {
  if(!data.hasOwnProperty('api_key') || data.api_key === '') {
    throw new exception.MissingApiKeyException;
  }
}

module.exports = {
  createTournament: createTournament,
  saveTournament: saveTournament,
  deleteTournament: deleteTournament
}
<commit_msg>Fixed some things<commit_after>var request = require('request'),
    async = require('async');
var exception = require('./exception.js');

var create = function(err, data, callback) {
  async.waterfall([function(callback){
	  if (err) throw err;
	  validate_request(data);
	  request.post({url:'https://challonge.com/api/tournaments.json', data: data}, function done(err, httpResponse, body) {
	    if (err) {
	      console.error('upload failed:', err);
	    }
	    console.log('Upload successful!  Server responded with:', body);
	  });
  }], callback)
}

var save = function(err, data, callback) {
  async.waterfall([function(callback) {
	  if (err) throw err;
	  validate_request(data);
	  request.put({url:'https://challonge.com/api/tournaments.json', data: data}, function done(err, httpResponse, body) {
	    if (err) {
	      return console.error('upload failed:', err);
	    }
	    console.log('Update successful! Server responded with:', body);
	  });
  }], callback)
};

var destroy = function(err, data, callback) {
  async.waterfall([function(callback) {
	  if (err) throw err;
	  validate_request(data);
	  console.log(data.tournament.toString());
  }], callback)
};

function validate_request(data) {
  if(!data.hasOwnProperty('api_key') || data.api_key === '') {
    throw new exception.MissingApiKeyException;
  }
}

module.exports = {
  create: create,
  save: save,
  destroy: destroy
}
<|endoftext|>


<commit_before>const shortTypes = ['qp', 'ms', 'in', 'er', 'gt', 'ir', 'ci', 'sp', 'sm', 'sr']
const longTypes = [
  'question paper',
  'marking scheme',
  'insert',
  'examiner report',
  'grade thresholds',
  'confidential instructions',
  'confidential instructions',
  'specimen question paper',
  'specimen mark scheme',
  'specimen confidential instructions'
]

const shortMonths = ['m', 's', 'w', 'y']
const longMonths = ['Feb/March', 'May/June', 'Oct/Nov', 'For examination from']
const odashMonths = ['F/M', 'M/J', 'O/N', 'SP']

module.exports = {
  shortTypes, longTypes,
  shortMonths, longMonths, odashMonths,
  setToString: entity => `${entity.subject}_${entity.time}_${entity.paper}_${entity.variant}`,
  setEqual: (a, b) => a.subject === b.subject && a.time === b.time && a.paper === b.paper && a.variant === b.variant,
  getTypeString: shortType => {
    if (!shortType) return '--'
    let sIndex = shortTypes.indexOf(shortType)
    if (sIndex < 0) return shortType
    return longTypes[sIndex]
  },
  funcSortType: (t1, t2) => {
    t1 = t1.toLowerCase().trim()
    t2 = t2.toLowerCase().trim()
    let i1 = shortTypes.indexOf(t1)
    let i2 = shortTypes.indexOf(t2)
    if (i1 < 0 && i2 >= 0) {
      // t1 < t2
      return -1
    } else if (i2 < 0 && i1 >= 0) {
      return 1
    } else if (i1 < 0 && i2 < 0) {
      return 0
    } else {
      return Math.sign(i1 - i2)
    }
  },
  capitalizeFirst: str => {
    if (str.length === 0) return ''
    return str[0].toUpperCase() + str.substr(1)
  },
  funcSortSet: (b1, b2) => {
    ;[b1, b2].forEach(b => {
      if (!Number.isSafeInteger(b.paper) || !Number.isSafeInteger(b.variant)) {
        throw new Error('paper and variant must both be integer.')
      }
    })
    let sortSubj = Math.sign(parseInt(b1.subject) - parseInt(b2.subject))
    if (sortSubj !== 0 && !Number.isNaN(sortSubj)) return sortSubj

    let times = [b1, b2].map(b => b.time).map(t => [parseInt(t.substr(1)), t[0]])
    let sortYear = Math.sign(times[0][0] - times[1][0])
    if (sortYear !== 0 && !Number.isNaN(sortYear)) return sortYear
    else if (Number.isNaN(sortYear)) return Math.sign([0, 1].map(p => times[p][0]).map(x => Number.isNaN(x) ? -1 : 1).reduce((a, b) => a - b))

    let sortMonth = Math.sign(shortMonths.indexOf(times[0][1]) - shortMonths.indexOf(times[1][1]))
    if (sortMonth !== 0 && !Number.isNaN(sortMonth)) return sortMonth

    let sortP = Math.sign(b1.paper - b2.paper)
    if (sortP !== 0) return sortP

    return Math.sign(b1.variant - b2.variant)
  },
  myTimeToHumanTime: myt => {
    let m = myt[0]
    let y = parseInt(myt.substr(1))
    if (Number.isNaN(y)) return myt
    let mi = shortMonths.indexOf(m)
    if (mi < 0) return myt
    if (y < 10) y = '0' + y
    return `${longMonths[mi]} 20${y}`
  },
  odashMonthToMyMonth: odash => {
    let mi = odashMonths.indexOf(odash)
    if (mi < 0 && odash.match(/^[A-Z]{2}$/)) {
      mi = odashMonths.indexOf(`${odash[0]}/${odash[1]}`)
    }
    if (mi < 0) return odash
    return shortMonths[mi]
  }
}
<commit_msg>Marking scheme -> Mark scheme<commit_after>const shortTypes = ['qp', 'ms', 'in', 'er', 'gt', 'ir', 'ci', 'sp', 'sm', 'sr']
const longTypes = [
  'question paper',
  'mark scheme',
  'insert',
  'examiner report',
  'grade thresholds',
  'confidential instructions',
  'confidential instructions',
  'specimen question paper',
  'specimen mark scheme',
  'specimen confidential instructions'
]

const shortMonths = ['m', 's', 'w', 'y']
const longMonths = ['Feb/March', 'May/June', 'Oct/Nov', 'For examination from']
const odashMonths = ['F/M', 'M/J', 'O/N', 'SP']

module.exports = {
  shortTypes, longTypes,
  shortMonths, longMonths, odashMonths,
  setToString: entity => `${entity.subject}_${entity.time}_${entity.paper}_${entity.variant}`,
  setEqual: (a, b) => a.subject === b.subject && a.time === b.time && a.paper === b.paper && a.variant === b.variant,
  getTypeString: shortType => {
    if (!shortType) return '--'
    let sIndex = shortTypes.indexOf(shortType)
    if (sIndex < 0) return shortType
    return longTypes[sIndex]
  },
  funcSortType: (t1, t2) => {
    t1 = t1.toLowerCase().trim()
    t2 = t2.toLowerCase().trim()
    let i1 = shortTypes.indexOf(t1)
    let i2 = shortTypes.indexOf(t2)
    if (i1 < 0 && i2 >= 0) {
      // t1 < t2
      return -1
    } else if (i2 < 0 && i1 >= 0) {
      return 1
    } else if (i1 < 0 && i2 < 0) {
      return 0
    } else {
      return Math.sign(i1 - i2)
    }
  },
  capitalizeFirst: str => {
    if (str.length === 0) return ''
    return str[0].toUpperCase() + str.substr(1)
  },
  funcSortSet: (b1, b2) => {
    ;[b1, b2].forEach(b => {
      if (!Number.isSafeInteger(b.paper) || !Number.isSafeInteger(b.variant)) {
        throw new Error('paper and variant must both be integer.')
      }
    })
    let sortSubj = Math.sign(parseInt(b1.subject) - parseInt(b2.subject))
    if (sortSubj !== 0 && !Number.isNaN(sortSubj)) return sortSubj

    let times = [b1, b2].map(b => b.time).map(t => [parseInt(t.substr(1)), t[0]])
    let sortYear = Math.sign(times[0][0] - times[1][0])
    if (sortYear !== 0 && !Number.isNaN(sortYear)) return sortYear
    else if (Number.isNaN(sortYear)) return Math.sign([0, 1].map(p => times[p][0]).map(x => Number.isNaN(x) ? -1 : 1).reduce((a, b) => a - b))

    let sortMonth = Math.sign(shortMonths.indexOf(times[0][1]) - shortMonths.indexOf(times[1][1]))
    if (sortMonth !== 0 && !Number.isNaN(sortMonth)) return sortMonth

    let sortP = Math.sign(b1.paper - b2.paper)
    if (sortP !== 0) return sortP

    return Math.sign(b1.variant - b2.variant)
  },
  myTimeToHumanTime: myt => {
    let m = myt[0]
    let y = parseInt(myt.substr(1))
    if (Number.isNaN(y)) return myt
    let mi = shortMonths.indexOf(m)
    if (mi < 0) return myt
    if (y < 10) y = '0' + y
    return `${longMonths[mi]} 20${y}`
  },
  odashMonthToMyMonth: odash => {
    let mi = odashMonths.indexOf(odash)
    if (mi < 0 && odash.match(/^[A-Z]{2}$/)) {
      mi = odashMonths.indexOf(`${odash[0]}/${odash[1]}`)
    }
    if (mi < 0) return odash
    return shortMonths[mi]
  }
}
<|endoftext|>


<commit_before>TC.control = TC.control || {};

if (!TC.Control) {
    TC.syncLoadJS(TC.apiLocation + 'TC/Control');
}

TC.control.ExternalWMS = function (options) {
    if (TC.isLegacy) {
        console.warn("El control ExternalWMS no soporta modo legacy");
        return;
    }
    var self = this;
    this.count = 0;
    this._addedUrls = [];

    TC.Control.apply(self, arguments);

    self.allowReprojection = typeof self.options.allowReprojection === 'boolean' ? self.options.allowReprojection : true;
};

TC.inherit(TC.control.ExternalWMS, TC.Control);

(function () {
    var ctlProto = TC.control.ExternalWMS.prototype;

    ctlProto.CLASS = 'tc-ctl-xwms';

    /**
     * Marca como seleccionadas aquellas opciones del desplegable correspondientes a servicios WMS ya añadidos al TOC.
     */
    ctlProto.markServicesAsSelected = function (options) {
        if (options.length > 0) {
            const selectedOption = options[0];
            selectedOption.disabled = true;
            selectedOption.classList.add('tc-ctl-xwms-option-selected');
        }
    };

    ctlProto.register = function (map) {
        if (TC.isLegacy) {
            console.warn("El control ExternalWMS no soporta modo legacy");
            return;
        }

        const self = this;
        const result = TC.Control.prototype.register.call(self, map);

        self.div.addEventListener('change', TC.EventTarget.listenerBySelector('select', function (evt) {
            if (evt.target.value !== '') {
                var url = evt.target.value;
                if (url.indexOf('//') === 0) {
                    url = location.protocol + url;
                }
                self.div.querySelector('input').value = url;
                evt.target.value = '';
            }
        }));

        /**
         * Borra parámetros no necesarios de la URL del servicio WMS.
         */
        var _removeParamsFromUrl = function (url, unwantedParams) {
            for (var i = 0; i < unwantedParams.length; i++) {
                url = TC.Util.removeURLParameter(url, unwantedParams[i]);
            }
            if (url.match(/\?$/)) {
                url = url.substr(0, url.length - 1);
            }
            return url;
        }

        self.div.addEventListener('click', TC.EventTarget.listenerBySelector('button[name="agregar"]', function (evt) {
            var url = self.div.querySelector('input').value.trim();

            if (!url) {
                TC.alert(self.getLocaleString('typeAnAddress'));
            }
            else if (!/^((https?|ftp):)?(\/\/)?(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(url)) {
                TC.alert(self.getLocaleString('typeAValidAddress'));
            }
            else {
                if (self._addedUrls.some(function (addedUrl) {
                    return addedUrl.replace(/https?:\/\/|\/\//, '') === url.replace(/https?:\/\/|\/\//, '')
                })) {
                    TC.alert(self.getLocaleString('serviceAlreadyAdded'));
                }
                else {
                    var loadingCtrl = self.map.getControlsByClass("TC.control.LoadingIndicator")[0];
                    loadingCtrl.show();
                    var params = TC.Util.getQueryStringParams(url);

                    if (!/https?:\/\/|\/\//i.test(url)) {
                        url = "//" + url;
                    }

                    //Extraemos sólo los parámetros adicionales
                    var unwantedParams = ["version", "service", "request"];
                    var urlWithoutParams = _removeParamsFromUrl(url, Object.keys(params));

                    for (var item in params) {
                        if (unwantedParams.indexOf(item.toLowerCase()) >= 0) {
                            delete params[item];
                        }
                    }

                    const addButton = self.div.querySelector('button');
                    addButton.disabled = true;

                    var obj = {
                        id: 'xwms' + (++self.count),
                        //"title": "Servicio externo",
                        type: 'WMS',
                        url: urlWithoutParams,
                        hideTree: false,
                        queryParams: params
                    };
                    //URI: recorremos las opciones buscando el servicio que se va a agregar a ver si tiene parametro layerNames
                    for (var i = 0; i < self.options.suggestions.length; i++) {
                        var _current = $.grep(self.options.suggestions[i].items, function (item, i) {
                            return item.url === url;
                        });
                        if (_current.length > 0 && _current[0].layerNames) {
                            obj["layerNames"] = _current[0].layerNames;
                            break;
                        }
                    }

                    var layer = new TC.layer.Raster(obj);
                    layer.getCapabilitiesPromise().then(function (cap) {
                        if (typeof (cap.Capability) === 'undefined') {
                            TC.alert(self.getLocaleString('noLayersFoundInService'));
                            loadingCtrl.hide();
                            addButton.disabled = false;
                            return;
                        } else {
                            var root = cap.Capability.Layer;
                            if (root.CRS && root.CRS.indexOf(self.map.crs) == -1 && !self.allowReprojection) {
                                //no soportado. avisar y fallar
                                TC.alert(self.getLocaleString('serviceSrsNotCompatible'));
                                loadingCtrl.hide();
                                addButton.disabled = false;
                                return;
                            }

                            self.map.trigger(TC.Consts.event.EXTERNALSERVICEADDED, { layer: layer });
                            self.div.querySelector('input').value = '';

                            const selectedOptions = [];
                            self.div.querySelectorAll('select option').forEach(function (option) {
                                if (option.value.replace(/https?:\/\/|\/\//, '') === url.replace(/https?:\/\/|\/\//, '')) {
                                    selectedOptions.push(option);
                                }
                            });
                            self.markServicesAsSelected(selectedOptions);
                            self._addedUrls.push(url);
                            loadingCtrl.hide();
                            addButton.disabled = false;
                        }
                    },
                        function (error) {
                            TC.alert(self.getLocaleString('serviceCouldNotBeLoaded') + ":\n" + error);
                            loadingCtrl.hide();
                            addButton.disabled = false;
                        });
                }
            }

        }));

        map.on(TC.Consts.event.LAYERADD, function (e) {
            const layer = e.layer;
            if (layer && !layer.isBase) {
                var url = layer.url;

                if (url) {
                    self.pending_markServicesAsSelected = self.pending_markServicesAsSelected || [];
                    if (self.div.querySelectorAll('select option').length === 0 && url && self.pending_markServicesAsSelected.indexOf(url) === -1) {
                        self.pending_markServicesAsSelected.push(url);
                    }

                    const selectedOptions = [];
                    self.div.querySelectorAll('select option').forEach(function (option) {
                        if (option.value.replace(/https?:\/\/|\/\//, '') === url.replace(/https?:\/\/|\/\//, '')) {
                            selectedOptions.push(option);
                        }
                    });
                    self.markServicesAsSelected(selectedOptions);
                    self._addedUrls.push(url);
                }
            }
        });

        return result;
    };

    ctlProto.template = {};
    if (TC.isDebug) {
        ctlProto.template[ctlProto.CLASS] = TC.apiLocation + "TC/templates/ExternalWMS.html";
    }
    else {
        ctlProto.template[ctlProto.CLASS] = function () {
            dust.register(ctlProto.CLASS, body_0); function body_0(chk, ctx) { return chk.x(ctx.get(["title"], false), ctx, { "block": body_1 }, {}).w("

 <select id=\"add-wms-select\" class=\"tc-combo\" title=\"WMS (Web Map Service)\"><option value=\"\">WMS</option>").s(ctx.get(["suggestions"], false), ctx, { "block": body_2 }, {}).w("</select><input type=\"url\" class=\"tc-textbox\" placeholder=\"").h("i18n", ctx, {}, { "$key": "writeAddressOrSelect" }).w("\" />

<button type=\"button\" class=\"tc-button tc-icon-button\" title=\"").h("i18n", ctx, {}, { "$key": "addService.title" }).w("\" name=\"agregar\">").h("i18n", ctx, {}, { "$key": "addService" }).w("</button>

"); } body_0.__dustBody = !0; function body_1(chk, ctx) { return chk.w("
").h("i18n", ctx, {}, { "$key": "addMaps" }).w("
"); } body_1.__dustBody = !0; function body_2(chk, ctx) { return chk.x(ctx.get(["group"], false), ctx, { "block": body_3 }, {}).s(ctx.get(["items"], false), ctx, { "block": body_4 }, {}).x(ctx.get(["group"], false), ctx, { "block": body_5 }, {}); } body_2.__dustBody = !0; function body_3(chk, ctx) { return chk.w("<optgroup label=\"").f(ctx.get(["group"], false), ctx, "h").w("\">"); } body_3.__dustBody = !0; function body_4(chk, ctx) { return chk.w("<option value=\"").f(ctx.get(["url"], false), ctx, "h").w("\">").f(ctx.get(["name"], false), ctx, "h").w("</option>"); } body_4.__dustBody = !0; function body_5(chk, ctx) { return chk.w("\t</optgroup>"); } body_5.__dustBody = !0; return body_0
        };
    }

    ctlProto.render = function (callback) {
        const self = this;
        return self._set1stRenderPromise(self.renderData(self.options, function () {
            self.pending_markServicesAsSelected = self.pending_markServicesAsSelected || [];

            self.pending_markServicesAsSelected.forEach(function (elemUrl) {
                const selectedOptions = [];
                self.div.querySelectorAll('select option').forEach(function (option) {
                    if (TC.Util.addProtocol(option.value) === TC.Util.addProtocol(elemUrl)) {
                        selectedOptions.push(option);
                    }
                });

                self.markServicesAsSelected(selectedOptions);
                self._addedUrls.push(elemUrl);
            });

            self.pending_markServicesAsSelected = [];
        }));
    };

})();<commit_msg>Update ExternalWMS.js<commit_after>TC.control = TC.control || {};

if (!TC.Control) {
    TC.syncLoadJS(TC.apiLocation + 'TC/Control');
}

TC.control.ExternalWMS = function (options) {
    const self = this;
    self.count = 0;
    self._addedUrls = [];

    TC.Control.apply(self, arguments);

    self.allowReprojection = typeof self.options.allowReprojection === 'boolean' ? self.options.allowReprojection : true;
};

TC.inherit(TC.control.ExternalWMS, TC.Control);

(function () {
    var ctlProto = TC.control.ExternalWMS.prototype;

    ctlProto.CLASS = 'tc-ctl-xwms';

    /**
     * Marca como seleccionadas aquellas opciones del desplegable correspondientes a servicios WMS ya añadidos al TOC.
     */
    ctlProto.markServicesAsSelected = function (options) {
        if (options.length > 0) {
            const selectedOption = options[0];
            selectedOption.disabled = true;
            selectedOption.classList.add('tc-ctl-xwms-option-selected');
        }
    };

    ctlProto.register = function (map) {
        const self = this;
        const result = TC.Control.prototype.register.call(self, map);

        self.div.addEventListener('change', TC.EventTarget.listenerBySelector('select', function (evt) {
            if (evt.target.value !== '') {
                var url = evt.target.value;
                if (url.indexOf('//') === 0) {
                    url = location.protocol + url;
                }
                self.div.querySelector('input').value = url;
                evt.target.value = '';
            }
        }));

        /**
         * Borra parámetros no necesarios de la URL del servicio WMS.
         */
        var _removeParamsFromUrl = function (url, unwantedParams) {
            for (var i = 0; i < unwantedParams.length; i++) {
                url = TC.Util.removeURLParameter(url, unwantedParams[i]);
            }
            if (url.match(/\?$/)) {
                url = url.substr(0, url.length - 1);
            }
            return url;
        }

        const addWMS = function () {
            var url = self.div.querySelector('input').value.trim();

            if (!url) {
                TC.alert(self.getLocaleString('typeAnAddress'));
            }
            else if (!/^((https?|ftp):)?(\/\/)?(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(url)) {
                TC.alert(self.getLocaleString('typeAValidAddress'));
            }
            else {
                if (self._addedUrls.some(function (addedUrl) {
                    return addedUrl.replace(/https?:\/\/|\/\//, '') === url.replace(/https?:\/\/|\/\//, '')
                })) {
                    TC.alert(self.getLocaleString('serviceAlreadyAdded'));
                }
                else {
                    var loadingCtrl = self.map.getControlsByClass("TC.control.LoadingIndicator")[0];
                    loadingCtrl.show();
                    var params = TC.Util.getQueryStringParams(url);

                    if (!/https?:\/\/|\/\//i.test(url)) {
                        url = "//" + url;
                    }

                    //Extraemos sólo los parámetros adicionales
                    var unwantedParams = ["version", "service", "request"];
                    var urlWithoutParams = _removeParamsFromUrl(url, Object.keys(params));

                    for (var item in params) {
                        if (unwantedParams.indexOf(item.toLowerCase()) >= 0) {
                            delete params[item];
                        }
                    }

                    const addButton = self.div.querySelector('button');
                    addButton.disabled = true;

                    var obj = {
                        id: 'xwms' + (++self.count),
                        //"title": "Servicio externo",
                        type: 'WMS',
                        url: urlWithoutParams,
                        hideTree: false,
                        queryParams: params
                    };
                    //URI: recorremos las opciones buscando el servicio que se va a agregar a ver si tiene parametro layerNames
                    for (var i = 0; i < self.options.suggestions.length; i++) {
                        var _current = self.options.suggestions[i].items.filter(function (item, i) {
                            return item.url === url;
                        });
                        if (_current.length > 0 && _current[0].layerNames) {
                            obj["layerNames"] = _current[0].layerNames;
                            break;
                        }
                    }

                    var layer = new TC.layer.Raster(obj);
                    layer.getCapabilitiesPromise().then(function (cap) {
                        if (typeof (cap.Capability) === 'undefined') {
                            TC.alert(self.getLocaleString('noLayersFoundInService'));
                            loadingCtrl.hide();
                            addButton.disabled = false;
                            return;
                        } else {
                            var root = cap.Capability.Layer;
                            if (root.CRS && root.CRS.indexOf(self.map.crs) == -1 && !self.allowReprojection) {
                                //no soportado. avisar y fallar
                                TC.alert(self.getLocaleString('serviceSrsNotCompatible'));
                                loadingCtrl.hide();
                                addButton.disabled = false;
                                return;
                            }

                            self.map.trigger(TC.Consts.event.EXTERNALSERVICEADDED, { layer: layer });
                            self.div.querySelector('input').value = '';

                            const selectedOptions = [];
                            self.div.querySelectorAll('select option').forEach(function (option) {
                                if (option.value.replace(/https?:\/\/|\/\//, '') === url.replace(/https?:\/\/|\/\//, '')) {
                                    selectedOptions.push(option);
                                }
                            });
                            self.markServicesAsSelected(selectedOptions);
                            self._addedUrls.push(url);
                            loadingCtrl.hide();
                            addButton.disabled = false;
                        }
                    },
                        function (error) {
                            TC.alert(self.getLocaleString('serviceCouldNotBeLoaded') + ":\n" + error);
                            loadingCtrl.hide();
                            addButton.disabled = false;
                        });
                }
            }
        };

        self.renderPromise().then(() => {
            self.div.querySelector('input').addEventListener('keyup', (e) => {
                if (e.key && e.key.toLowerCase() === "enter" && self.div.querySelector('input').value.trim().length > 0) {
                    addWMS();
                }
            });
        });

        self.div.addEventListener('click', TC.EventTarget.listenerBySelector('button[name="agregar"]', addWMS));

        map.on(TC.Consts.event.LAYERADD, function (e) {
            const layer = e.layer;
            if (layer && !layer.isBase) {
                var url = layer.url;

                if (url) {
                    self.pending_markServicesAsSelected = self.pending_markServicesAsSelected || [];
                    if (self.div.querySelectorAll('select option').length === 0 && url && self.pending_markServicesAsSelected.indexOf(url) === -1) {
                        self.pending_markServicesAsSelected.push(url);
                    }

                    const selectedOptions = [];
                    self.div.querySelectorAll('select option').forEach(function (option) {
                        if (option.value.replace(/https?:\/\/|\/\//, '') === url.replace(/https?:\/\/|\/\//, '')) {
                            selectedOptions.push(option);
                        }
                    });
                    self.markServicesAsSelected(selectedOptions);
                    self._addedUrls.push(url);
                }
            }
        });

        return result;
    };

    ctlProto.template = {};
    if (TC.isDebug) {
        ctlProto.template[ctlProto.CLASS] = TC.apiLocation + "TC/templates/ExternalWMS.html";
    }
    else {
        ctlProto.template[ctlProto.CLASS] = function () {
            dust.register(ctlProto.CLASS, body_0); function body_0(chk, ctx) { return chk.x(ctx.get(["title"], false), ctx, { "block": body_1 }, {}).w("

 <select id=\"add-wms-select\" class=\"tc-combo\" title=\"WMS (Web Map Service)\"><option value=\"\">WMS</option>").s(ctx.get(["suggestions"], false), ctx, { "block": body_2 }, {}).w("</select><input type=\"url\" class=\"tc-textbox\" placeholder=\"").h("i18n", ctx, {}, { "$key": "writeAddressOrSelect" }).w("\" />

<button type=\"button\" class=\"tc-button tc-icon-button\" title=\"").h("i18n", ctx, {}, { "$key": "addService.title" }).w("\" name=\"agregar\">").h("i18n", ctx, {}, { "$key": "addService" }).w("</button>

"); } body_0.__dustBody = !0; function body_1(chk, ctx) { return chk.w("
").h("i18n", ctx, {}, { "$key": "addMaps" }).w("
"); } body_1.__dustBody = !0; function body_2(chk, ctx) { return chk.x(ctx.get(["group"], false), ctx, { "block": body_3 }, {}).s(ctx.get(["items"], false), ctx, { "block": body_4 }, {}).x(ctx.get(["group"], false), ctx, { "block": body_5 }, {}); } body_2.__dustBody = !0; function body_3(chk, ctx) { return chk.w("<optgroup label=\"").f(ctx.get(["group"], false), ctx, "h").w("\">"); } body_3.__dustBody = !0; function body_4(chk, ctx) { return chk.w("<option value=\"").f(ctx.get(["url"], false), ctx, "h").w("\">").f(ctx.get(["name"], false), ctx, "h").w("</option>"); } body_4.__dustBody = !0; function body_5(chk, ctx) { return chk.w("\t</optgroup>"); } body_5.__dustBody = !0; return body_0
        };
    }

    ctlProto.render = function (callback) {
        const self = this;
        return self._set1stRenderPromise(self.renderData(self.options, function () {
            self.pending_markServicesAsSelected = self.pending_markServicesAsSelected || [];

            self.pending_markServicesAsSelected.forEach(function (elemUrl) {
                const selectedOptions = [];
                self.div.querySelectorAll('select option').forEach(function (option) {
                    if (TC.Util.addProtocol(option.value) === TC.Util.addProtocol(elemUrl)) {
                        selectedOptions.push(option);
                    }
                });

                self.markServicesAsSelected(selectedOptions);
                self._addedUrls.push(elemUrl);
            });

            self.pending_markServicesAsSelected = [];
        }));
    };

})();<|endoftext|>


<commit_before>import fs from 'fs-extra'
import path from 'path'
import Promise, { promisify } from 'bluebird'

Promise.config({ cancellation: true })

const copy = promisify(fs.copy)
const ensureDir = promisify(fs.ensureDir)
const readFile = promisify(fs.readFile)
const writeFile = promisify(fs.writeFile)

/**
 * Copy file from `source` to `target`.
 *
 * @param {string} source - A file to be copied.
 * @param {string} target - A destination path where to copy.
 * @param {TransformFunc} [transform] - Optional transformation function.
 * @returns {Promise}
 */
export const copyFile = (source, target, transform) => new Promise((resolve) => {
  if (transform) {
    resolve(readFile(source).then((file) => {
      const transformed = transform(file, target)
      const isObject = typeof transformed === 'object'
      const data = (isObject && transformed.data) || transformed
      const newTarget = (isObject && transformed.target) || target

      return ensureDir(path.dirname(newTarget)).then(() => writeFile(newTarget, data))
    }))
  } else {
    resolve(ensureDir(path.dirname(target)).then(() => copy(source, target)))
  }
})

/**
 * Copy a directory from `source` to `target` (w/o contents).
 *
 * @param {string} source - A directory to be copied.
 * @param {string} target - A destination path where to copy.
 * @returns {Promise}
 */
export const copyDir = (source, target) => ensureDir(target)

/**
 * Remove a file or directory.
 *
 * @param {string} fileordir - The file or directory to remove.
 * @returns {Promise}
 */
export const remove = promisify(fs.remove)

export const stat = promisify(fs.stat)

/**
 * A custom function which transforms a given `file` contents and/or `target`.
 *
 * @typedef {function} TransformFunc
 * @param {File} file - A file object obtained by `fs.readFile`.
 * @param {string} target - The destination where to copy this `file`.
 * @returns {File|{data: File, target: string}} - Returns the transformed `file` and/or renamed `target`.
 */
<commit_msg>just add a test log<commit_after>import fs from 'fs-extra'
import path from 'path'
import Promise, { promisify } from 'bluebird'

Promise.config({ cancellation: true })

const copy = promisify(fs.copy)
const ensureDir = promisify(fs.ensureDir)
const readFile = promisify(fs.readFile)
const writeFile = promisify(fs.writeFile)

/**
 * Copy file from `source` to `target`.
 *
 * @param {string} source - A file to be copied.
 * @param {string} target - A destination path where to copy.
 * @param {TransformFunc} [transform] - Optional transformation function.
 * @returns {Promise}
 */
export const copyFile = (source, target, transform) => new Promise((resolve) => {
  if (transform) {
    resolve(readFile(source).then((file) => {
      const transformed = transform(file, target)
      const isObject = typeof transformed === 'object'
      const data = (isObject && transformed.data) || transformed
      const newTarget = (isObject && transformed.target) || target

      return ensureDir(path.dirname(newTarget)).then(() => writeFile(newTarget, data))
    }))
  } else {
    resolve(ensureDir(path.dirname(target)).then(() => {
      console.log(`##+++*** copy ${source} -> ${target}`)

      return copy(source, target)
    }))
  }
})

/**
 * Copy a directory from `source` to `target` (w/o contents).
 *
 * @param {string} source - A directory to be copied.
 * @param {string} target - A destination path where to copy.
 * @returns {Promise}
 */
export const copyDir = (source, target) => ensureDir(target)

/**
 * Remove a file or directory.
 *
 * @param {string} fileordir - The file or directory to remove.
 * @returns {Promise}
 */
export const remove = promisify(fs.remove)

export const stat = promisify(fs.stat)

/**
 * A custom function which transforms a given `file` contents and/or `target`.
 *
 * @typedef {function} TransformFunc
 * @param {File} file - A file object obtained by `fs.readFile`.
 * @param {string} target - The destination where to copy this `file`.
 * @returns {File|{data: File, target: string}} - Returns the transformed `file` and/or renamed `target`.
 */
<|endoftext|>


<commit_before>"use strict";

Cu.import("resource://gre/modules/devtools/Console.jsm");

let gMgr = Cc["@mozilla.org/memory-reporter-manager;1"]
             .getService(Ci.nsIMemoryReporterManager);

let gChildMemoryListener = undefined;
let gResult = {};

// Returns a promise of the memory footprint of the tab with the specified
// URL and (optionally) outer window ID.
function getMemoryFootprint(url, outerId)
{
  gResult = { total: 0, dom: 0, js: 0, other: 0 };
  let deferred = promise.defer();
  addChildObserversAndUpdate(() => {
    let os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
    os.removeObserver(gChildMemoryListener, "child-memory-reporter-update");
    deferred.resolve(processMemoryReporters(url, outerId));
  });
  return deferred.promise;
}

function addChildObserversAndUpdate(aUpdateFn)
{
  let os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
  os.notifyObservers(null, "child-memory-reporter-request", null);

  gChildMemoryListener = aUpdateFn;
  os.addObserver(gChildMemoryListener, "child-memory-reporter-update", false);

  gChildMemoryListener();
}

function processMemoryReporters(url, outerId)
{
  let e = gMgr.enumerateMultiReporters();
  while (e.hasMoreElements()) {
    let mr = e.getNext().QueryInterface(Ci.nsIMemoryMultiReporter);
    // |collectReports| never passes in a |presence| argument.
    let handleReport = function(aProcess, aUnsafePath, aKind,
                                aUnits, aAmount, aDescription) {
      if (!aUnsafePath.contains("strings/notable/string") &&
          flipBackslashes(aUnsafePath).contains(url) &&
          (!outerId || aUnsafePath.contains(", id=" + outerId))) {
        gResult.total += aAmount;
        // Now collect the more detailed measurements.
        let str = flipBackslashes(aUnsafePath);
        let index = str.lastIndexOf(url);
        str = str.slice(index+url.length);
        if (str.contains("/dom/")) {
          gResult.dom += aAmount;
        } else if (str.contains("/objects/") || str.contains("/objects-extra/")) {
          gResult.js += aAmount;
        } else {
          gResult.other += aAmount;
        }
      }
    }

    // We are only interested in the memory footprint of the current page.
    if (mr.name == "window-objects") {
      mr.collectReports(handleReport, null);
    }
  }
  return gResult;
}

function flipBackslashes(aUnsafeStr)
{
  // Save memory by only doing the replacement if it's necessary.
  return (aUnsafeStr.indexOf('\\') === -1)
         ? aUnsafeStr
         : aUnsafeStr.replace(/\\/g, '/');
}

function formatBytes(aBytes)
{
  let unit = " MB";

  let s;
  let mbytes = (aBytes / (1024 * 1024)).toFixed(2);
  let a = String(mbytes).split(".");
  // If the argument to formatInt() is -0, it will print the negative sign.
  s = formatInt(Number(a[0])) + "." + a[1] + unit;
  return s;
}

function formatInt(aN, aExtra)
{
  let neg = false;
  if (hasNegativeSign(aN)) {
    neg = true;
    aN = -aN;
  }
  let s = [];
  while (true) {
    let k = aN % 1000;
    aN = Math.floor(aN / 1000);
    if (aN > 0) {
      if (k < 10) {
        s.unshift(",00", k);
      } else if (k < 100) {
        s.unshift(",0", k);
      } else {
        s.unshift(",", k);
      }
    } else {
      s.unshift(k);
      break;
    }
  }
  if (neg) {
    s.unshift("-");
  }
  if (aExtra) {
    s.push(aExtra);
  }
  return s.join("");
}

function hasNegativeSign(aN)
{
  if (aN === 0) {                   // this succeeds for 0 and -0
    return 1 / aN === -Infinity;    // this succeeds for -0
  }
  return aN < 0;
}
<commit_msg>We no longer have any MultiReporters after bug 910517.<commit_after>"use strict";

Cu.import("resource://gre/modules/devtools/Console.jsm");

let gMgr = Cc["@mozilla.org/memory-reporter-manager;1"]
             .getService(Ci.nsIMemoryReporterManager);

let gChildMemoryListener = undefined;
let gResult = {};

// Returns a promise of the memory footprint of the tab with the specified
// URL and (optionally) outer window ID.
function getMemoryFootprint(url, outerId)
{
  gResult = { total: 0, dom: 0, js: 0, other: 0 };
  let deferred = promise.defer();
  addChildObserversAndUpdate(() => {
    let os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
    os.removeObserver(gChildMemoryListener, "child-memory-reporter-update");
    deferred.resolve(processMemoryReporters(url, outerId));
  });
  return deferred.promise;
}

function addChildObserversAndUpdate(aUpdateFn)
{
  let os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
  os.notifyObservers(null, "child-memory-reporter-request", null);

  gChildMemoryListener = aUpdateFn;
  os.addObserver(gChildMemoryListener, "child-memory-reporter-update", false);

  gChildMemoryListener();
}

function processMemoryReporters(url, outerId)
{
  let e = gMgr.enumerateReporters();
  while (e.hasMoreElements()) {
    let mr = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
    // |collectReports| never passes in a |presence| argument.
    let handleReport = function(aProcess, aUnsafePath, aKind,
                                aUnits, aAmount, aDescription) {
      if (!aUnsafePath.contains("strings/notable/string") &&
          flipBackslashes(aUnsafePath).contains(url) &&
          (!outerId || aUnsafePath.contains(", id=" + outerId))) {
        gResult.total += aAmount;
        // Now collect the more detailed measurements.
        let str = flipBackslashes(aUnsafePath);
        let index = str.lastIndexOf(url);
        str = str.slice(index+url.length);
        if (str.contains("/dom/")) {
          gResult.dom += aAmount;
        } else if (str.contains("/objects/") || str.contains("/objects-extra/")) {
          gResult.js += aAmount;
        } else {
          gResult.other += aAmount;
        }
      }
    }

    // We are only interested in the memory footprint of the current page.
    if (mr.name == "window-objects") {
      mr.collectReports(handleReport, null);
    }
  }
  return gResult;
}

function flipBackslashes(aUnsafeStr)
{
  // Save memory by only doing the replacement if it's necessary.
  return (aUnsafeStr.indexOf('\\') === -1)
         ? aUnsafeStr
         : aUnsafeStr.replace(/\\/g, '/');
}

function formatBytes(aBytes)
{
  let unit = " MB";

  let s;
  let mbytes = (aBytes / (1024 * 1024)).toFixed(2);
  let a = String(mbytes).split(".");
  // If the argument to formatInt() is -0, it will print the negative sign.
  s = formatInt(Number(a[0])) + "." + a[1] + unit;
  return s;
}

function formatInt(aN, aExtra)
{
  let neg = false;
  if (hasNegativeSign(aN)) {
    neg = true;
    aN = -aN;
  }
  let s = [];
  while (true) {
    let k = aN % 1000;
    aN = Math.floor(aN / 1000);
    if (aN > 0) {
      if (k < 10) {
        s.unshift(",00", k);
      } else if (k < 100) {
        s.unshift(",0", k);
      } else {
        s.unshift(",", k);
      }
    } else {
      s.unshift(k);
      break;
    }
  }
  if (neg) {
    s.unshift("-");
  }
  if (aExtra) {
    s.push(aExtra);
  }
  return s.join("");
}

function hasNegativeSign(aN)
{
  if (aN === 0) {                   // this succeeds for 0 and -0
    return 1 / aN === -Infinity;    // this succeeds for -0
  }
  return aN < 0;
}
<|endoftext|>


<commit_before>TC.control = TC.control || {};

if (!TC.Control) {
    TC.syncLoadJS(TC.apiLocation + 'TC/Control');
}

TC.control.MapContents = function () {
    var self = this;

    TC.Control.apply(self, arguments);

    self.layerTrees = {};
};

TC.inherit(TC.control.MapContents, TC.Control);

(function () {
    var ctlProto = TC.control.MapContents.prototype;

    ctlProto.CLASS = 'tc-ctl-mc';

    var _dataKeys = {
        layer: 'tcLayer',
        img: 'tcImg'
    };

    ctlProto.render = function (callback) {
        var self = this;
        if (self.map) {
            self.renderData(self.map.getLayerTree(), callback);
        }
    };

    ctlProto.register = function (map) {
        var self = this;
        TC.Control.prototype.register.call(self, map);
        self.render(function () {

            for (var i = 0, len = map.layers.length; i < len; i++) {
                self.updateLayerTree(map.layers[i]);
            }

            map.on(TC.Consts.event.ZOOM + ' ' + TC.Consts.event.PROJECTIONCHANGE, function () {
                self.updateScale();
            }).on(TC.Consts.event.UPDATEPARAMS, function (e) {
                var names = e.layer.names;
                var containsName = function containsName(node) {
                    var result = false;
                    if (node) {
                        if ($.inArray(node.name, names) >= 0) {
                            result = true;
                        }
                        else {
                            for (var i = 0; i < node.children.length; i++) {
                                if (containsName(node.children[i])) {
                                    result = true;
                                    break;
                                }
                            }
                        }
                    }
                    return result;
                };
                if (containsName(self.layerTrees[e.layer.id]) || names.length === 0) {
                    self.update();
                }
                else {
                    self.updateLayerTree(e.layer);
                }
            }).on(TC.Consts.event.LAYERVISIBILITY, function (e) {
                self.updateLayerVisibility(e.layer);
            }).on(TC.Consts.event.LAYERADD, function (e) {
                self.updateLayerTree(e.layer);
            }).on(TC.Consts.event.VECTORUPDATE + ' ' + TC.Consts.event.FEATUREADD + ' ' + TC.Consts.event.FEATURESADD, function (e) {
                // Se introduce un timeout porque pueden venir muchos eventos de este tipo seguidos y no tiene sentido actualizar con cada uno
                if (self._updateLayerTreeTimeout) {
                    clearTimeout(self._updateLayerTreeTimeout);
                }
                self._updateLayerTreeTimeout = setTimeout(function () {
                    if (self.map.workLayers.indexOf(e.layer) > -1) {
                        // GLS: Validamos si la capa que ha provocado el evento sigue en worklayers, si es borrada debido a la espera del timeout el TOC puede reflejar capas que ya no están
                        self.updateLayerTree(e.layer);
                        delete self._updateLayerTreeTimeout;
                    }
                }, 100);
            }).on(TC.Consts.event.LAYERREMOVE, function (e) {
                self.removeLayer(e.layer);
            }).on(TC.Consts.event.LAYERORDER, function (e) {
                self.updateLayerOrder(e.layer, e.oldIndex, e.newIndex);
            });
        });
    };

    ctlProto.updateScale = function () {
    };

    ctlProto.updateLayerVisibility = function (layer) {
    };

    ctlProto.updateLayerTree = function (layer) {
        this.layerTrees[layer.id] = layer.getTree();
    };

    ctlProto.updateLayerOrder = function (layer, oldIdx, newIdx) {
        var self = this;
        if (oldIdx >= 0 && oldIdx !== newIdx) {
            var $currentElm, $previousElm;
            var $elms = self.getLayerUIElements();
            for (var i = self.map.workLayers.length - 1; i >= 0; i--) {
                var l = self.map.workLayers[i];
                $previousElm = $currentElm;
                $elms.each(function (idx, elm) {
                    var $elm = $(elm);
                    if ($elm.data(_dataKeys.layer) === l) {
                        $currentElm = $elm;
                        return false;
                    }
                });
                if (l === layer) {
                    if ($previousElm) {
                        $previousElm.after($currentElm);
                    }
                    else {
                        $elms.parent().prepend($currentElm);
                    }
                    break;
                }
            }
        }
    };

    ctlProto.removeLayer = function (layer) {
        this.update();
    };

    ctlProto.getLayerUIElements = function () {
        var self = this;
        return self._$div.find('ul').first().children();
    };

    var isGetLegendGraphic = function (url) {
        return /[&?]REQUEST=getLegendGraphic/i.test(url);
    };

    /**
     * Carga y le da estilo a la imagen de la leyenda.
     * @param {string} requestMethod Si queremos pedir la imagen de la leyenda por POST, podemos especificarlo utilizando el parámetro requestMethod.
     */
    ctlProto.styleLegendImage = function ($img, layer) {
        if (!$img.attr('src')) {
            var imgSrc = $img.data(_dataKeys.img);

            var ERROR = 'error.tc';
            $img.off(ERROR).on(ERROR, function () {
                var imgSRC_protocol = $img.attr('src');
                // GLS: hemos modificado el protocolo?¿
                if (imgSRC_protocol.indexOf(layer.url) === -1) {
                    var protocolRegex = /^(https?:\/\/)/i;
                    if (protocolRegex.test(imgSRC_protocol) && protocolRegex.test(layer.url)) {
                        imgSRC_protocol = imgSRC_protocol.replace(imgSRC_protocol.match(protocolRegex)[1], layer.url.match(protocolRegex)[1]);
                    }
                }

                $img.off('error.tc');

                $img.attr('src', layer instanceof TC.layer.Raster ? layer.getByProxy_(imgSRC_protocol) : TC.proxify(imgSRC_protocol));
            }.bind(layer));

            if (layer && layer.options.method && layer.options.method === "POST") {
                layer.getLegendGraphicImage()
                .done(function (src) {
                    $img.attr('src', layer.getLegendUrl(src));
                })
                .fail(function (err) { TC.error(err); });
            } else {
                if (isGetLegendGraphic(imgSrc)) {
                    var $watch = $img.parent();
                    // A\u00f1adimos el par\u00e1metro que define el estilo de los textos en la imagen
                    var colorStr = $watch.css('color');
                    // Convertimos el color de formato rgb(r,g,b) a 0xRRGGBB
                    var openIdx = colorStr.indexOf('(');
                    var closeIdx = colorStr.indexOf(')');
                    if (openIdx >= 0 && closeIdx > openIdx) {
                        color = colorStr
                            .substr(0, closeIdx)
                            .substr(openIdx + 1)
                            .split(',');
                        colorStr = '0x';
                        for (var i = 0; i < 3; i++) {
                            var component = parseInt(color[i]).toString(16);
                            colorStr += component.length === 1 ? '0' + component : component;
                        }
                    }
                    else {
                        colorStr.replace('#', '0x');
                    }
                    imgSrc += '&LEGEND_OPTIONS=fontName:' + $watch.css('font-family') +
                        ';fontSize:' + parseInt($watch.css('font-size')) +
                        ';fontColor:' + colorStr +
                        ';fontAntiAliasing:true';
                    if (layer.params && layer.params.sld_body) {
                        imgSrc = TC.Util.addURLParameters(imgSrc, { sld_body: layer.params.sld_body });
                    }
                    $img.data(_dataKeys.img, layer.getLegendUrl(imgSrc));
                }
                $img.attr('src', layer.getLegendUrl(imgSrc));
            }
        }
    };

})();<commit_msg>Add options to MapContents controls<commit_after>TC.control = TC.control || {};

if (!TC.Control) {
    TC.syncLoadJS(TC.apiLocation + 'TC/Control');
}

TC.control.MapContents = function () {
    var self = this;

    TC.Control.apply(self, arguments);

    self.layerTrees = {};
};

TC.inherit(TC.control.MapContents, TC.Control);

(function () {
    var ctlProto = TC.control.MapContents.prototype;

    ctlProto.CLASS = 'tc-ctl-mc';

    var _dataKeys = {
        layer: 'tcLayer',
        img: 'tcImg'
    };

    ctlProto.render = function (callback, options) {
        var self = this;
        if (self.map) {
            self.renderData(options ? $.extend(self.map.getLayerTree(), options) : self.map.getLayerTree(), callback);
        }
    };

    ctlProto.register = function (map) {
        var self = this;
        TC.Control.prototype.register.call(self, map);
        self.render(function () {

            for (var i = 0, len = map.layers.length; i < len; i++) {
                self.updateLayerTree(map.layers[i]);
            }

            map.on(TC.Consts.event.ZOOM + ' ' + TC.Consts.event.PROJECTIONCHANGE, function () {
                self.updateScale();
            }).on(TC.Consts.event.UPDATEPARAMS, function (e) {
                var names = e.layer.names;
                var containsName = function containsName(node) {
                    var result = false;
                    if (node) {
                        if ($.inArray(node.name, names) >= 0) {
                            result = true;
                        }
                        else {
                            for (var i = 0; i < node.children.length; i++) {
                                if (containsName(node.children[i])) {
                                    result = true;
                                    break;
                                }
                            }
                        }
                    }
                    return result;
                };
                if (containsName(self.layerTrees[e.layer.id]) || names.length === 0) {
                    self.update();
                }
                else {
                    self.updateLayerTree(e.layer);
                }
            }).on(TC.Consts.event.LAYERVISIBILITY, function (e) {
                self.updateLayerVisibility(e.layer);
            }).on(TC.Consts.event.LAYERADD, function (e) {
                self.updateLayerTree(e.layer);
            }).on(TC.Consts.event.VECTORUPDATE + ' ' + TC.Consts.event.FEATUREADD + ' ' + TC.Consts.event.FEATURESADD, function (e) {
                // Se introduce un timeout porque pueden venir muchos eventos de este tipo seguidos y no tiene sentido actualizar con cada uno
                if (self._updateLayerTreeTimeout) {
                    clearTimeout(self._updateLayerTreeTimeout);
                }
                self._updateLayerTreeTimeout = setTimeout(function () {
                    if (self.map.workLayers.indexOf(e.layer) > -1) {
                        // GLS: Validamos si la capa que ha provocado el evento sigue en worklayers, si es borrada debido a la espera del timeout el TOC puede reflejar capas que ya no están
                        self.updateLayerTree(e.layer);
                        delete self._updateLayerTreeTimeout;
                    }
                }, 100);
            }).on(TC.Consts.event.LAYERREMOVE, function (e) {
                self.removeLayer(e.layer);
            }).on(TC.Consts.event.LAYERORDER, function (e) {
                self.updateLayerOrder(e.layer, e.oldIndex, e.newIndex);
            });
        });
    };

    ctlProto.updateScale = function () {
    };

    ctlProto.updateLayerVisibility = function (layer) {
    };

    ctlProto.updateLayerTree = function (layer) {
        this.layerTrees[layer.id] = layer.getTree();
    };

    ctlProto.updateLayerOrder = function (layer, oldIdx, newIdx, collection) {
        var self = this;
        if (oldIdx >= 0 && oldIdx !== newIdx) {
            var $currentElm, $previousElm;
            var $elms = self.getLayerUIElements();

            collection = collection || self.map.workLayers;

            for (var i = collection.length - 1; i >= 0; i--) {
                var l = collection[i];
                $previousElm = $currentElm;
                $elms.each(function (idx, elm) {
                    var $elm = $(elm);
                    if ($elm.data(_dataKeys.layer) === l) {
                        $currentElm = $elm;
                        return false;
                    }
                });
                if (l === layer) {
                    if ($previousElm) {
                        $previousElm.after($currentElm);
                    }
                    else {
                        $elms.parent().prepend($currentElm);
                    }
                    break;
                }
            }
        }
    };

    ctlProto.removeLayer = function (layer) {
        this.update();
    };

    ctlProto.getLayerUIElements = function () {
        var self = this;
        return self._$div.find('ul').first().children();
    };

    var isGetLegendGraphic = function (url) {
        return /[&?]REQUEST=getLegendGraphic/i.test(url);
    };

    /**
     * Carga y le da estilo a la imagen de la leyenda.
     * @param {string} requestMethod Si queremos pedir la imagen de la leyenda por POST, podemos especificarlo utilizando el parámetro requestMethod.
     */
    ctlProto.styleLegendImage = function ($img, layer) {
        if (!$img.attr('src')) {
            var imgSrc = $img.data(_dataKeys.img);

            var ERROR = 'error.tc';
            $img.off(ERROR).on(ERROR, function () {
                var imgSRC_protocol = $img.attr('src');
                // GLS: hemos modificado el protocolo?¿
                if (imgSRC_protocol.indexOf(layer.url) === -1) {
                    var protocolRegex = /^(https?:\/\/)/i;
                    if (protocolRegex.test(imgSRC_protocol) && protocolRegex.test(layer.url)) {
                        imgSRC_protocol = imgSRC_protocol.replace(imgSRC_protocol.match(protocolRegex)[1], layer.url.match(protocolRegex)[1]);
                    }
                }

                $img.off('error.tc');

                $img.attr('src', layer instanceof TC.layer.Raster ? layer.getByProxy_(imgSRC_protocol) : TC.proxify(imgSRC_protocol));
            }.bind(layer));

            if (layer && layer.options.method && layer.options.method === "POST") {
                layer.getLegendGraphicImage()
                .done(function (src) {
                    $img.attr('src', layer.getLegendUrl(src));
                })
                .fail(function (err) { TC.error(err); });
            } else {
                if (isGetLegendGraphic(imgSrc)) {
                    var $watch = $img.parent();
                    // A\u00f1adimos el par\u00e1metro que define el estilo de los textos en la imagen
                    var colorStr = $watch.css('color');
                    // Convertimos el color de formato rgb(r,g,b) a 0xRRGGBB
                    var openIdx = colorStr.indexOf('(');
                    var closeIdx = colorStr.indexOf(')');
                    if (openIdx >= 0 && closeIdx > openIdx) {
                        color = colorStr
                            .substr(0, closeIdx)
                            .substr(openIdx + 1)
                            .split(',');
                        colorStr = '0x';
                        for (var i = 0; i < 3; i++) {
                            var component = parseInt(color[i]).toString(16);
                            colorStr += component.length === 1 ? '0' + component : component;
                        }
                    }
                    else {
                        colorStr.replace('#', '0x');
                    }
                    imgSrc += '&LEGEND_OPTIONS=fontName:' + $watch.css('font-family') +
                        ';fontSize:' + parseInt($watch.css('font-size')) +
                        ';fontColor:' + colorStr +
                        ';fontAntiAliasing:true';
                    if (layer.params && layer.params.sld_body) {
                        imgSrc = TC.Util.addURLParameters(imgSrc, { sld_body: layer.params.sld_body });
                    }
                    $img.data(_dataKeys.img, layer.getLegendUrl(imgSrc));
                }
                $img.attr('src', layer.getLegendUrl(imgSrc));
            }
        }
    };

})();<|endoftext|>


<commit_before>// Copyright 2010 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview An alternative imageless button renderer that uses CSS3 rather
 * than voodoo to render custom buttons with rounded corners and dimensionality
 * (via a subtle flat shadow on the bottom half of the button) without the use
 * of images.
 *
 * Based on the Custom Buttons 3.1 visual specification, see
 * http://go/custombuttons
 *
 * Tested and verified to work in Gecko 1.9.2+ and WebKit 528+.
 *
 * @see ../demos/css3button.html
 */

goog.provide('goog.ui.Css3ButtonRenderer');

goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.dom.classes');
goog.require('goog.ui.Button');
goog.require('goog.ui.ButtonRenderer');
goog.require('goog.ui.ControlContent');
goog.require('goog.ui.INLINE_BLOCK_CLASSNAME');
goog.require('goog.ui.registry');

/**
 * Custom renderer for {@link goog.ui.Button}s. Css3 buttons can contain
 * almost arbitrary HTML content, will flow like inline elements, but can be
 * styled like block-level elements.
 *
 * @constructor
 * @extends {goog.ui.ButtonRenderer}
 */
goog.ui.Css3ButtonRenderer = function() {
  goog.ui.ButtonRenderer.call(this);
};
goog.inherits(goog.ui.Css3ButtonRenderer, goog.ui.ButtonRenderer);

/**
 * The singleton instance of this renderer class.
 * @type {goog.ui.Css3ButtonRenderer?}
 * @private
 */
goog.ui.Css3ButtonRenderer.instance_ = null;
goog.addSingletonGetter(goog.ui.Css3ButtonRenderer);

/**
 * Default CSS class to be applied to the root element of components rendered
 * by this renderer.
 * @type {string}
 */
goog.ui.Css3ButtonRenderer.CSS_CLASS = goog.getCssName('goog-css3-button');

/** @inheritDoc */
goog.ui.Css3ButtonRenderer.prototype.getContentElement = function(element) {
  return /** @type {Element} */ (element);
};

/**
 * Returns the button's contents wrapped in the following DOM structure:
 *

 *      Contents...
 *

 * Overrides {@link goog.ui.ButtonRenderer#createDom}.
 * @param {goog.ui.Button} button Button to render.
 * @return {Element} Root element for the button.
 */
goog.ui.Css3ButtonRenderer.prototype.createDom = function(button) {
  var attr = {
    'class': goog.ui.INLINE_BLOCK_CLASSNAME + ' ' + this.getCssClass(),
    'title': button.getTooltip() || ''
  };
  return button.getDomHelper().createDom('div', attr, button.getContent());
};

/**
 * Returns true if this renderer can decorate the element.  Overrides
 * {@link goog.ui.ButtonRenderer#canDecorate} by returning true if the
 * element is a DIV, false otherwise.
 * @param {Element} element Element to decorate.
 * @return {boolean} Whether the renderer can decorate the element.
 */
goog.ui.Css3ButtonRenderer.prototype.canDecorate = function(element) {
  return element.tagName == goog.dom.TagName.DIV;
};

/** @inheritDoc */
goog.ui.Css3ButtonRenderer.prototype.decorate = function(button, element) {
  goog.dom.classes.add(element, goog.ui.INLINE_BLOCK_CLASSNAME,
      this.getCssClass());
  return goog.ui.Css3ButtonRenderer.superClass_.decorate.call(this, button,
      element);
};

/**
 * Returns the CSS class to be applied to the root element of components
 * rendered using this renderer.
 * @return {string} Renderer-specific CSS class.
 * @override
 */
goog.ui.Css3ButtonRenderer.prototype.getCssClass = function() {
  return goog.ui.Css3ButtonRenderer.CSS_CLASS;
};

// Register a decorator factory function for goog.ui.Css3ButtonRenderer.
goog.ui.registry.setDecoratorByClassName(
    goog.ui.Css3ButtonRenderer.CSS_CLASS,
    function() {
      return new goog.ui.Button(null,
          goog.ui.Css3ButtonRenderer.getInstance());
    });

// Register a decorator factory function for toggle buttons using the
// goog.ui.Css3ButtonRenderer.
goog.ui.registry.setDecoratorByClassName(
    goog.getCssName('goog-css3-toggle-button'),
    function() {
      var button = new goog.ui.Button(null,
          goog.ui.Css3ButtonRenderer.getInstance());
      button.setSupportedState(goog.ui.Component.State.CHECKED, true);
      return button;
    });
<commit_msg><commit_after>// Copyright 2010 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview An alternative imageless button renderer that uses CSS3 rather
 * than voodoo to render custom buttons with rounded corners and dimensionality
 * (via a subtle flat shadow on the bottom half of the button) without the use
 * of images.
 *
 * Based on the Custom Buttons 3.1 visual specification, see
 * http://go/custombuttons
 *
 * Tested and verified to work in Gecko 1.9.2+ and WebKit 528+.
 *
 * @see ../demos/css3button.html
 */

goog.provide('goog.ui.Css3ButtonRenderer');

goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.dom.classes');
goog.require('goog.ui.Button');
goog.require('goog.ui.ButtonRenderer');
goog.require('goog.ui.ControlContent');
goog.require('goog.ui.INLINE_BLOCK_CLASSNAME');
goog.require('goog.ui.registry');

/**
 * Custom renderer for {@link goog.ui.Button}s. Css3 buttons can contain
 * almost arbitrary HTML content, will flow like inline elements, but can be
 * styled like block-level elements.
 *
 * @constructor
 * @extends {goog.ui.ButtonRenderer}
 */
goog.ui.Css3ButtonRenderer = function() {
  goog.ui.ButtonRenderer.call(this);
};
goog.inherits(goog.ui.Css3ButtonRenderer, goog.ui.ButtonRenderer);

/**
 * The singleton instance of this renderer class.
 * @type {goog.ui.Css3ButtonRenderer?}
 * @private
 */
goog.ui.Css3ButtonRenderer.instance_ = null;
goog.addSingletonGetter(goog.ui.Css3ButtonRenderer);

/**
 * Default CSS class to be applied to the root element of components rendered
 * by this renderer.
 * @type {string}
 */
goog.ui.Css3ButtonRenderer.CSS_CLASS = goog.getCssName('goog-css3-button');

/** @inheritDoc */
goog.ui.Css3ButtonRenderer.prototype.getContentElement = function(element) {
  return /** @type {Element} */ (element);
};

/**
 * Returns the button's contents wrapped in the following DOM structure:
 *

 *      Contents...
 *

 * Overrides {@link goog.ui.ButtonRenderer#createDom}.
 * @param {goog.ui.Button} button Button to render.
 * @return {Element} Root element for the button.
 */
goog.ui.Css3ButtonRenderer.prototype.createDom = function(button) {
  var classNames = this.getClassNames(button);
  var attr = {
    'class': goog.ui.INLINE_BLOCK_CLASSNAME + ' ' + classNames.join(' '),
    'title': button.getTooltip() || ''
  };
  return button.getDomHelper().createDom('div', attr, button.getContent());
};

/**
 * Returns true if this renderer can decorate the element.  Overrides
 * {@link goog.ui.ButtonRenderer#canDecorate} by returning true if the
 * element is a DIV, false otherwise.
 * @param {Element} element Element to decorate.
 * @return {boolean} Whether the renderer can decorate the element.
 */
goog.ui.Css3ButtonRenderer.prototype.canDecorate = function(element) {
  return element.tagName == goog.dom.TagName.DIV;
};

/** @inheritDoc */
goog.ui.Css3ButtonRenderer.prototype.decorate = function(button, element) {
  goog.dom.classes.add(element, goog.ui.INLINE_BLOCK_CLASSNAME,
      this.getCssClass());
  return goog.ui.Css3ButtonRenderer.superClass_.decorate.call(this, button,
      element);
};

/**
 * Returns the CSS class to be applied to the root element of components
 * rendered using this renderer.
 * @return {string} Renderer-specific CSS class.
 * @override
 */
goog.ui.Css3ButtonRenderer.prototype.getCssClass = function() {
  return goog.ui.Css3ButtonRenderer.CSS_CLASS;
};

// Register a decorator factory function for goog.ui.Css3ButtonRenderer.
goog.ui.registry.setDecoratorByClassName(
    goog.ui.Css3ButtonRenderer.CSS_CLASS,
    function() {
      return new goog.ui.Button(null,
          goog.ui.Css3ButtonRenderer.getInstance());
    });

// Register a decorator factory function for toggle buttons using the
// goog.ui.Css3ButtonRenderer.
goog.ui.registry.setDecoratorByClassName(
    goog.getCssName('goog-css3-toggle-button'),
    function() {
      var button = new goog.ui.Button(null,
          goog.ui.Css3ButtonRenderer.getInstance());
      button.setSupportedState(goog.ui.Component.State.CHECKED, true);
      return button;
    });
<|endoftext|>