<commit_before>// var CommonSpec = require('./CommonSpec');

describe('LabelSpec', function() {

    var container;
    var map;
    var tile;
    var center = new Z.Coordinate(118.846825, 32.046534);
    var layer;

    beforeEach(function() {
        var setups = commonSetupMap(center);
        container = setups.container;
        map = setups.map;
    });

    afterEach(function() {
        map.removeLayer(layer);
        document.body.removeChild(container);
    });

    describe('label fires events', function() {
        it('svg events', function() {
            var vector = new maptalks.Label('test label', center);
            new GeoEventsTester().testSVGEvents(vector, map);
        });

        it('canvas events', function() {
            var vector = new maptalks.Label('test label', center);
            new GeoEventsTester().testCanvasEvents(vector, map, vector.getCenter());
        });
    });

    describe('change position',function() {
        it('events',function() {
            var spy = sinon.spy();

            var vector = new maptalks.Label('test label',center);
            vector.on('positionchange',spy);

            function evaluate() {
                var rnd = Math.random()*0.001;
                var coordinates = new Z.Coordinate(center.x+rnd, center.y+rnd);
                var radius = 1000*rnd;

                vector.setCoordinates(coordinates);
                expect(spy.calledOnce).to.be.ok();
                expect(vector.getCoordinates()).to.eql(coordinates);
                spy.reset();
            }

            evaluate();

            layer = new Z.VectorLayer('id');
            map.addLayer(layer);
            layer.addGeometry(vector);
            evaluate();
            vector.remove();
        });
    });

    describe('can get/set content',function() {
        it("get/set content",function() {
            var label = '中文标签';
            var vector = new maptalks.Label(label,center);
            layer = new Z.VectorLayer('id');
            map.addLayer(layer);
            layer.addGeometry(vector);
            expect(vector.getContent()).to.be.eql(label);
            label = '中文标签-2';
            vector.setContent(label);
            expect(vector.getContent()).to.be.eql(label);
        });
    });

    describe('can get/set textAlign',function() {
        it("get/set textAlign",function() {
            var label = '中文标签';
            var vector = new maptalks.Label(label,center);
            vector.config('boxAutoSize',false);
            //default textalign
            expect(vector.getTextAlign()).to.be.eql('center');
            vector.setTextAlign('right');
            expect(vector.getTextAlign()).to.be.eql('right');
            layer = new Z.VectorLayer('id');
            map.addLayer(layer);
            layer.addGeometry(vector);
            expect(vector.getTextAlign()).to.be.eql('right');
            vector.setTextAlign('left');
            expect(vector.getTextAlign()).to.be.eql('left');
        });
    });

    describe('can get/set symbol',function() {
        it("get/set symbol",function() {
            var label = '中文标签';
            var vector = new maptalks.Label(label,center);
            vector.setSymbol(null);
            //null symbol is allowed, means set to default symbol.
            expect(vector.getSymbol()).not.to.be.empty();
            layer = new Z.VectorLayer('id');
            map.addLayer(layer);
            layer.addGeometry(vector);
            var labelSymbol = {
                // 'markerType': 'ellipse',
                'markerLineColor': '#ff0000',
                'markerLineWidth': 2,
                'markerLineOpacity': 0.9,
                'markerLineDasharray': null,
                // 'markerFill': '#4e98dd',
                'markerFillOpacity': 0.6,

                'textFaceName': 'arial',
                'textSize': 12,
                // 'textFill': '#ff0000',
                'textOpacity': 1,
                'textSpacing': 30,
                'textWrapWidth': null,//auto
                'textWrapBefore': false,
                'textWrapCharacter': '\n',
                'textLineSpacing': 8,
                'textHorizontalAlignment': 'middle',//left middle right
                'textVerticalAlignment': 'top'//top middle bottom
            };
            vector.setSymbol(labelSymbol);
            //symbol's textName will be set.
            expect(vector.getSymbol()['textName']).not.to.be.empty();
        });
    });

    describe('can config',function() {
        it("configs",function() {
            var vector = new maptalks.Label('label',center);
            var defaultConfig = vector.config();
            expect(defaultConfig).to.be.empty();

        });
    });
});
<commit_msg>updates label specs<commit_after>// var CommonSpec = require('./CommonSpec');

describe('LabelSpec', function() {

    var container;
    var map;
    var tile;
    var center = new Z.Coordinate(118.846825, 32.046534);
    var layer;

    beforeEach(function() {
        var setups = commonSetupMap(center);
        container = setups.container;
        map = setups.map;
    });

    afterEach(function() {
        map.removeLayer(layer);
        document.body.removeChild(container);
    });

    describe('label fires events', function() {
        it('svg events', function() {
            var vector = new maptalks.Label('test label', center);
            new GeoEventsTester().testSVGEvents(vector, map);
        });

        it('canvas events', function() {
            var vector = new maptalks.Label('test label', center);
            new GeoEventsTester().testCanvasEvents(vector, map, vector.getCenter());
        });
    });

    describe('change position',function() {
        it('events',function() {
            var spy = sinon.spy();

            var vector = new maptalks.Label('test label',center);
            vector.on('positionchange',spy);

            function evaluate() {
                var rnd = Math.random()*0.001;
                var coordinates = new Z.Coordinate(center.x+rnd, center.y+rnd);
                var radius = 1000*rnd;

                vector.setCoordinates(coordinates);
                expect(spy.calledOnce).to.be.ok();
                expect(vector.getCoordinates()).to.eql(coordinates);
                spy.reset();
            }

            evaluate();

            layer = new Z.VectorLayer('id');
            map.addLayer(layer);
            layer.addGeometry(vector);
            evaluate();
            vector.remove();
        });
    });

    describe('can get/set content',function() {
        it("get/set content",function() {
            var label = '中文标签';
            var vector = new maptalks.Label(label,center);
            layer = new Z.VectorLayer('id');
            map.addLayer(layer);
            layer.addGeometry(vector);
            expect(vector.getContent()).to.be.eql(label);
            label = '中文标签-2';
            vector.setContent(label);
            expect(vector.getContent()).to.be.eql(label);
        });
    });

    describe('can get/set textAlign',function() {
        it("get/set textAlign",function() {
            var label = '中文标签';
            var vector = new maptalks.Label(label,center);
            vector.config('boxAutoSize',false);
            //default textalign
            expect(vector.config('boxTextAlign')).to.be.eql('middle');
            vector.config('boxTextAlign','right');
            expect(vector.config('boxTextAlign')).to.be.eql('right');
            layer = new Z.VectorLayer('id');
            map.addLayer(layer);
            layer.addGeometry(vector);
            expect(vector.config('boxTextAlign')).to.be.eql('right');
            vector.config('boxTextAlign','left');
            expect(vector.config('boxTextAlign')).to.be.eql('left');
        });
    });

    describe('can get/set symbol',function() {
        it("get/set symbol",function() {
            var label = '中文标签';
            var vector = new maptalks.Label(label,center);
            vector.setSymbol(null);
            //null symbol is allowed, means set to default symbol.
            expect(vector.getSymbol()).not.to.be.empty();
            layer = new Z.VectorLayer('id');
            map.addLayer(layer);
            layer.addGeometry(vector);
            var labelSymbol = {
                // 'markerType': 'ellipse',
                'markerLineColor': '#ff0000',
                'markerLineWidth': 2,
                'markerLineOpacity': 0.9,
                'markerLineDasharray': null,
                // 'markerFill': '#4e98dd',
                'markerFillOpacity': 0.6,

                'textFaceName': 'arial',
                'textSize': 12,
                // 'textFill': '#ff0000',
                'textOpacity': 1,
                'textSpacing': 30,
                'textWrapWidth': null,//auto
                'textWrapBefore': false,
                'textWrapCharacter': '\n',
                'textLineSpacing': 8,
                'textHorizontalAlignment': 'middle',//left middle right
                'textVerticalAlignment': 'top'//top middle bottom
            };
            vector.setSymbol(labelSymbol);
            //symbol's textName will be set.
            expect(vector.getSymbol()['textName']).not.to.be.empty();
        });
    });

    describe('can config',function() {
        it("configs",function() {
            var vector = new maptalks.Label('label',center);
            var defaultConfig = vector.config();
            expect(defaultConfig).to.be.empty();

        });
    });
});
<|endoftext|>


<commit_before>/*
---

script: Submittable.js

description: Makes widget result in either submission or cancellation

license: Public domain (http://unlicense.org).

authors: Yaroslaff Fedin

requires:
  - LSD.Mixin

provides:
  - LSD.Mixin.Submittable

...
*/

LSD.Mixin.Submittable = new Class({
  options: {
    actions: {
      autosubmission: {
        enable: function() {
          if (this.attributes.autosubmit) this.submit();
        }
      }
    },
    has: {
      many: {
        submitters: {
          selector: ':submitter',
          as: 'submittable',
          scope: {
            'default': {
              filter: '[default]'
            }
          },
          options: {
            chain: {
              submission: function() {
                return {action: 'submit', target: this.submittable};
              }
            }
          },
          callbacks: {
            fill: function() {
              if (LSD.toLowerCase(this.element.tagName) == 'form')
                this.properties.watch('rendered', this.bind(LSD.Mixin.Submittable.watchNativeSubmission));
            },
            empty: function() {
              if (LSD.toLowerCase(this.element.tagName) == 'form')
                this.properties.unwatch('rendered', this.bind(LSD.Mixin.Submittable.watchNativeSubmission));
            }
          }
        }
      }
    },
    events: {
      _form: {
        attach: function(element) {
          if (LSD.toLowerCase(element.tagName) == 'form') element.addEvent('submit', this.bind('submit'));
        },
        detach: function(element) {
          if (LSD.toLowerCase(element.tagName) == 'form') element.removeEvent('submit', this.bind('submit'));
        }
      }
    }
  },

  submit: function(event) {
    if (event && event.type == 'submit' && event.target == this.element) event.preventDefault();
    if (this.submitting) return true;
    this.submitting = true;
    this.fireEvent('beforeSubmit', arguments);
    var submission = this.captureEvent('submit', arguments);
    if (submission) return submission;
    else if (submission !== false) this.callChain();
    this.fireEvent('afterSubmit', arguments);
    delete this.submitting;
    return this;
  },

  cancel: function() {
    var submission = this.captureEvent('cancel', arguments);
    if (submission) return submission;
    else if (submission !== false) {
      var target = this.getSubmissionTarget();
      if (target) target.uncallChain();
      this.uncallChain();
    };
    return this;
  }
});

/*
  Injects native submit button at top of the form that gets activated
  when `enter` button is pressed in the form field. It stops the
  native submission, and submits the widget form instead.

  The first submitter widget in the form is considered activated and
  its value is used for submission data.
*/
LSD.Mixin.Submittable.watchNativeSubmission = function(state) {
  if (state) {
    this.allocate('submit').inject(this.element, 'top').addEvent('click', this.bind('submit'))
  } else {
    this.release('submit').dispose().removeEvent('click', this.bind('submit'));
  }
  /*
    novalidate html attribute disables internal form validation
    on form submission. Chrome and Safari will block form
    submission without any visual clues otherwise.
  */
  this.element[state ? 'setAttribute' : 'removeAttribute']('novalidate', '');
};

LSD.Behavior.define(':submittable', 'submittable');<commit_msg>Make submission prevent default 'click' event when a clicked target is <input type=submit>. Thus, a native submission is never triggered<commit_after>/*
---

script: Submittable.js

description: Makes widget result in either submission or cancellation

license: Public domain (http://unlicense.org).

authors: Yaroslaff Fedin

requires:
  - LSD.Mixin

provides:
  - LSD.Mixin.Submittable

...
*/

LSD.Mixin.Submittable = new Class({
  options: {
    actions: {
      autosubmission: {
        enable: function() {
          if (this.attributes.autosubmit) this.submit();
        }
      }
    },
    has: {
      many: {
        submitters: {
          selector: ':submitter',
          as: 'submittable',
          scope: {
            'default': {
              filter: '[default]'
            }
          },
          options: {
            chain: {
              submission: function() {
                return {action: 'submit', target: this.submittable};
              }
            }
          },
          callbacks: {
            fill: function() {
              if (LSD.toLowerCase(this.element.tagName) == 'form')
                this.properties.watch('rendered', this.bind(LSD.Mixin.Submittable.watchNativeSubmission));
            },
            empty: function() {
              if (LSD.toLowerCase(this.element.tagName) == 'form')
                this.properties.unwatch('rendered', this.bind(LSD.Mixin.Submittable.watchNativeSubmission));
            }
          }
        }
      }
    },
    events: {
      _form: {
        attach: function(element) {
          if (LSD.toLowerCase(element.tagName) == 'form') element.addEvent('submit', this.bind('submit'));
        },
        detach: function(element) {
          if (LSD.toLowerCase(element.tagName) == 'form') element.removeEvent('submit', this.bind('submit'));
        }
      }
    }
  },

  submit: function(event) {
    this.fireEvent('beforeSubmit', arguments);
    if (event) {
      switch (event.type) {
        case "submit":
          if (event.target == this.element) event.preventDefault();
          break;
        case "click":
          if (LSD.toLowerCase(event.target.tagName) == 'input' && event.target.type == 'submit')
            event.preventDefault();
      }
    }
    var submission = this.captureEvent('submit', arguments);
    if (!submission && submission !== false) this.callChain();
    this.fireEvent('afterSubmit', arguments);
    return submission;
  },

  cancel: function() {
    var submission = this.captureEvent('cancel', arguments);
    if (!submission && submission !== false) {
      var target = this.getSubmissionTarget();
      if (target) target.uncallChain();
      this.uncallChain();
    };
    return submission;
  }
});

/*
  Injects native submit button at top of the form that gets activated
  when `enter` button is pressed in the form field. It stops the
  native submission, and submits the widget form instead.

  The first submitter widget in the form is considered activated and
  its value is used for submission data.
*/
LSD.Mixin.Submittable.watchNativeSubmission = function(state) {
  if (state) {
    this.allocate('submit').inject(this.element, 'top').addEvent('click', this.bind('submit'))
  } else {
    this.release('submit').dispose().removeEvent('click', this.bind('submit'));
  }
  /*
    novalidate html attribute disables internal form validation
    on form submission. Chrome and Safari will block form
    submission without any visual clues otherwise.
  */
  this.element[state ? 'setAttribute' : 'removeAttribute']('novalidate', '');
};

LSD.Behavior.define(':submittable', 'submittable');<|endoftext|>


<commit_before>/*global define*/
define([
        '../Core/BoundingSphere',
        '../Core/Cartesian3',
        '../Core/ComponentDatatype',
        '../Core/defined',
        '../Core/DeveloperError',
        '../Core/IndexDatatype',
        '../Core/TerrainProvider',
        '../Core/TileProviderError',
        '../Renderer/BufferUsage',
        '../ThirdParty/when',
        './TerrainState',
        './terrainAttributeLocations'
    ], function(
        BoundingSphere,
        Cartesian3,
        ComponentDatatype,
        defined,
        DeveloperError,
        IndexDatatype,
        TerrainProvider,
        TileProviderError,
        BufferUsage,
        when,
        TerrainState,
        terrainAttributeLocations) {
    "use strict";

    /**
     * Manages details of the terrain load or upsample process.
     *
     * @alias TileTerrain
     * @constructor
     * @private
     *
     * @param {TerrainData} [upsampleDetails.data] The terrain data being upsampled.
     * @param {Number} [upsampleDetails.x] The X coordinate of the tile being upsampled.
     * @param {Number} [upsampleDetails.y] The Y coordinate of the tile being upsampled.
     * @param {Number} [upsampleDetails.level] The level coordinate of the tile being upsampled.
     */
    var TileTerrain = function TileTerrain(upsampleDetails) {
        /**
         * The current state of the terrain in the terrain processing pipeline.
         * @type {TerrainState}
         * @default {@link TerrainState.UNLOADED}
         */
        this.state = TerrainState.UNLOADED;
        this.data = undefined;
        this.mesh = undefined;
        this.vertexArray = undefined;
        this.upsampleDetails = upsampleDetails;
    };

    TileTerrain.prototype.freeResources = function() {
        this.state = TerrainState.UNLOADED;
        this.data = undefined;
        this.mesh = undefined;

        if (defined(this.vertexArray)) {
            var indexBuffer = this.vertexArray.indexBuffer;

            this.vertexArray.destroy();
            this.vertexArray = undefined;

            if (!indexBuffer.isDestroyed() && defined(indexBuffer.referenceCount)) {
                --indexBuffer.referenceCount;
                if (indexBuffer.referenceCount === 0) {
                    indexBuffer.destroy();
                }
            }
        }
    };

    TileTerrain.prototype.publishToTile = function(tile) {
        var mesh = this.mesh;
        Cartesian3.clone(mesh.center, tile.center);
        tile.minimumHeight = mesh.minimumHeight;
        tile.maximumHeight = mesh.maximumHeight;
        tile.boundingSphere3D = BoundingSphere.clone(mesh.boundingSphere3D, tile.boundingSphere3D);

        tile.occludeePointInScaledSpace = Cartesian3.clone(mesh.occludeePointInScaledSpace, tile.occludeePointInScaledSpace);

        // Free the tile's existing vertex array, if any.
        tile.freeVertexArray();

        // Transfer ownership of the vertex array to the tile itself.
        tile.vertexArray = this.vertexArray;
        this.vertexArray = undefined;
    };

    TileTerrain.prototype.processLoadStateMachine = function(context, terrainProvider, x, y, level) {
        if (this.state === TerrainState.UNLOADED) {
            requestTileGeometry(this, terrainProvider, x, y, level);
        }

        if (this.state === TerrainState.RECEIVED) {
            transform(this, context, terrainProvider, x, y, level);
        }

        if (this.state === TerrainState.TRANSFORMED) {
            createResources(this, context, terrainProvider, x, y, level);
        }
    };

    function requestTileGeometry(tileTerrain, terrainProvider, x, y, level) {
        function success(terrainData) {
            tileTerrain.data = terrainData;
            tileTerrain.state = TerrainState.RECEIVED;
        }

        function failure() {
            // Initially assume failure.  handleError may retry, in which case the state will
            // change to RECEIVING or UNLOADED.
            tileTerrain.state = TerrainState.FAILED;

            var message = 'Failed to obtain terrain tile X: ' + x + ' Y: ' + y + ' Level: ' + level + '.';
            terrainProvider._requestError = TileProviderError.handleError(
                    terrainProvider._requestError,
                    terrainProvider,
                    terrainProvider.errorEvent,
                    message,
                    x, y, level,
                    doRequest);
        }

        function doRequest() {
            // Request the terrain from the terrain provider.
            tileTerrain.data = terrainProvider.requestTileGeometry(x, y, level);

            // If the request method returns undefined (instead of a promise), the request
            // has been deferred.
            if (defined(tileTerrain.data)) {
                tileTerrain.state = TerrainState.RECEIVING;

                when(tileTerrain.data, success, failure);
            } else {
                // Deferred - try again later.
                tileTerrain.state = TerrainState.UNLOADED;
            }
        }

        doRequest();
    }

    TileTerrain.prototype.processUpsampleStateMachine = function(context, terrainProvider, x, y, level) {
        if (this.state === TerrainState.UNLOADED) {
            var upsampleDetails = this.upsampleDetails;

            //>>includeStart('debug', pragmas.debug);
            if (!defined(upsampleDetails)) {
                throw new DeveloperError('TileTerrain cannot upsample unless provided upsampleDetails.');
            }
            //>>includeEnd('debug');

            var sourceData = upsampleDetails.data;
            var sourceX = upsampleDetails.x;
            var sourceY = upsampleDetails.y;
            var sourceLevel = upsampleDetails.level;

            this.data = sourceData.upsample(terrainProvider.tilingScheme, sourceX, sourceY, sourceLevel, x, y, level);
            if (!defined(this.data)) {
                // The upsample request has been deferred - try again later.
                return;
            }

            this.state = TerrainState.RECEIVING;

            var that = this;
            when(this.data, function(terrainData) {
                that.data = terrainData;
                that.state = TerrainState.RECEIVED;
            }, function() {
                that.state = TerrainState.FAILED;
            });
        }

        if (this.state === TerrainState.RECEIVED) {
            transform(this, context, terrainProvider, x, y, level);
        }

        if (this.state === TerrainState.TRANSFORMED) {
            createResources(this, context, terrainProvider, x, y, level);
        }
    };

    function transform(tileTerrain, context, terrainProvider, x, y, level) {
        var tilingScheme = terrainProvider.tilingScheme;

        var terrainData = tileTerrain.data;
        var meshPromise = terrainData.createMesh(tilingScheme, x, y, level);

        if (!defined(meshPromise)) {
            // Postponed.
            return;
        }

        tileTerrain.state = TerrainState.TRANSFORMING;

        when(meshPromise, function(mesh) {
            tileTerrain.mesh = mesh;
            tileTerrain.state = TerrainState.TRANSFORMED;
        }, function() {
            tileTerrain.state = TerrainState.FAILED;
        });
    }

    function createResources(tileTerrain, context, terrainProvider, x, y, level) {
        var datatype = ComponentDatatype.FLOAT;
        var typedArray = tileTerrain.mesh.vertices;
        var buffer = context.createVertexBuffer(typedArray, BufferUsage.STATIC_DRAW);
        var stride = 6 * datatype.sizeInBytes;
        var position3DAndHeightLength = 4;

        var attributes = [{
            index : terrainAttributeLocations.position3DAndHeight,
            vertexBuffer : buffer,
            componentDatatype : datatype,
            componentsPerAttribute : position3DAndHeightLength,
            offsetInBytes : 0,
            strideInBytes : stride
        }, {
            index : terrainAttributeLocations.textureCoordinates,
            vertexBuffer : buffer,
            componentDatatype : datatype,
            componentsPerAttribute : 2,
            offsetInBytes : position3DAndHeightLength * datatype.sizeInBytes,
            strideInBytes : stride
        }];

        var indexBuffers = tileTerrain.mesh.indices.indexBuffers || {};
        var indexBuffer = indexBuffers[context.id];
        if (!defined(indexBuffer) || indexBuffer.isDestroyed()) {
            var indices = tileTerrain.mesh.indices;
            indexBuffer = context.createIndexBuffer(indices, BufferUsage.STATIC_DRAW, IndexDatatype.UNSIGNED_SHORT);
            indexBuffer.vertexArrayDestroyable = false;
            indexBuffer.referenceCount = 1;
            indexBuffers[context.id] = indexBuffer;
            tileTerrain.mesh.indices.indexBuffers = indexBuffers;
        } else {
            ++indexBuffer.referenceCount;
        }

        tileTerrain.vertexArray = context.createVertexArray(attributes, indexBuffer);

        tileTerrain.state = TerrainState.READY;
    }

    return TileTerrain;
});
<commit_msg>Fix require order.<commit_after>/*global define*/
define([
        '../Core/BoundingSphere',
        '../Core/Cartesian3',
        '../Core/ComponentDatatype',
        '../Core/defined',
        '../Core/DeveloperError',
        '../Core/IndexDatatype',
        '../Core/TerrainProvider',
        '../Core/TileProviderError',
        '../Renderer/BufferUsage',
        '../ThirdParty/when',
        './terrainAttributeLocations',
        './TerrainState'
    ], function(
        BoundingSphere,
        Cartesian3,
        ComponentDatatype,
        defined,
        DeveloperError,
        IndexDatatype,
        TerrainProvider,
        TileProviderError,
        BufferUsage,
        when,
        terrainAttributeLocations,
        TerrainState) {
    "use strict";

    /**
     * Manages details of the terrain load or upsample process.
     *
     * @alias TileTerrain
     * @constructor
     * @private
     *
     * @param {TerrainData} [upsampleDetails.data] The terrain data being upsampled.
     * @param {Number} [upsampleDetails.x] The X coordinate of the tile being upsampled.
     * @param {Number} [upsampleDetails.y] The Y coordinate of the tile being upsampled.
     * @param {Number} [upsampleDetails.level] The level coordinate of the tile being upsampled.
     */
    var TileTerrain = function TileTerrain(upsampleDetails) {
        /**
         * The current state of the terrain in the terrain processing pipeline.
         * @type {TerrainState}
         * @default {@link TerrainState.UNLOADED}
         */
        this.state = TerrainState.UNLOADED;
        this.data = undefined;
        this.mesh = undefined;
        this.vertexArray = undefined;
        this.upsampleDetails = upsampleDetails;
    };

    TileTerrain.prototype.freeResources = function() {
        this.state = TerrainState.UNLOADED;
        this.data = undefined;
        this.mesh = undefined;

        if (defined(this.vertexArray)) {
            var indexBuffer = this.vertexArray.indexBuffer;

            this.vertexArray.destroy();
            this.vertexArray = undefined;

            if (!indexBuffer.isDestroyed() && defined(indexBuffer.referenceCount)) {
                --indexBuffer.referenceCount;
                if (indexBuffer.referenceCount === 0) {
                    indexBuffer.destroy();
                }
            }
        }
    };

    TileTerrain.prototype.publishToTile = function(tile) {
        var mesh = this.mesh;
        Cartesian3.clone(mesh.center, tile.center);
        tile.minimumHeight = mesh.minimumHeight;
        tile.maximumHeight = mesh.maximumHeight;
        tile.boundingSphere3D = BoundingSphere.clone(mesh.boundingSphere3D, tile.boundingSphere3D);

        tile.occludeePointInScaledSpace = Cartesian3.clone(mesh.occludeePointInScaledSpace, tile.occludeePointInScaledSpace);

        // Free the tile's existing vertex array, if any.
        tile.freeVertexArray();

        // Transfer ownership of the vertex array to the tile itself.
        tile.vertexArray = this.vertexArray;
        this.vertexArray = undefined;
    };

    TileTerrain.prototype.processLoadStateMachine = function(context, terrainProvider, x, y, level) {
        if (this.state === TerrainState.UNLOADED) {
            requestTileGeometry(this, terrainProvider, x, y, level);
        }

        if (this.state === TerrainState.RECEIVED) {
            transform(this, context, terrainProvider, x, y, level);
        }

        if (this.state === TerrainState.TRANSFORMED) {
            createResources(this, context, terrainProvider, x, y, level);
        }
    };

    function requestTileGeometry(tileTerrain, terrainProvider, x, y, level) {
        function success(terrainData) {
            tileTerrain.data = terrainData;
            tileTerrain.state = TerrainState.RECEIVED;
        }

        function failure() {
            // Initially assume failure.  handleError may retry, in which case the state will
            // change to RECEIVING or UNLOADED.
            tileTerrain.state = TerrainState.FAILED;

            var message = 'Failed to obtain terrain tile X: ' + x + ' Y: ' + y + ' Level: ' + level + '.';
            terrainProvider._requestError = TileProviderError.handleError(
                    terrainProvider._requestError,
                    terrainProvider,
                    terrainProvider.errorEvent,
                    message,
                    x, y, level,
                    doRequest);
        }

        function doRequest() {
            // Request the terrain from the terrain provider.
            tileTerrain.data = terrainProvider.requestTileGeometry(x, y, level);

            // If the request method returns undefined (instead of a promise), the request
            // has been deferred.
            if (defined(tileTerrain.data)) {
                tileTerrain.state = TerrainState.RECEIVING;

                when(tileTerrain.data, success, failure);
            } else {
                // Deferred - try again later.
                tileTerrain.state = TerrainState.UNLOADED;
            }
        }

        doRequest();
    }

    TileTerrain.prototype.processUpsampleStateMachine = function(context, terrainProvider, x, y, level) {
        if (this.state === TerrainState.UNLOADED) {
            var upsampleDetails = this.upsampleDetails;

            //>>includeStart('debug', pragmas.debug);
            if (!defined(upsampleDetails)) {
                throw new DeveloperError('TileTerrain cannot upsample unless provided upsampleDetails.');
            }
            //>>includeEnd('debug');

            var sourceData = upsampleDetails.data;
            var sourceX = upsampleDetails.x;
            var sourceY = upsampleDetails.y;
            var sourceLevel = upsampleDetails.level;

            this.data = sourceData.upsample(terrainProvider.tilingScheme, sourceX, sourceY, sourceLevel, x, y, level);
            if (!defined(this.data)) {
                // The upsample request has been deferred - try again later.
                return;
            }

            this.state = TerrainState.RECEIVING;

            var that = this;
            when(this.data, function(terrainData) {
                that.data = terrainData;
                that.state = TerrainState.RECEIVED;
            }, function() {
                that.state = TerrainState.FAILED;
            });
        }

        if (this.state === TerrainState.RECEIVED) {
            transform(this, context, terrainProvider, x, y, level);
        }

        if (this.state === TerrainState.TRANSFORMED) {
            createResources(this, context, terrainProvider, x, y, level);
        }
    };

    function transform(tileTerrain, context, terrainProvider, x, y, level) {
        var tilingScheme = terrainProvider.tilingScheme;

        var terrainData = tileTerrain.data;
        var meshPromise = terrainData.createMesh(tilingScheme, x, y, level);

        if (!defined(meshPromise)) {
            // Postponed.
            return;
        }

        tileTerrain.state = TerrainState.TRANSFORMING;

        when(meshPromise, function(mesh) {
            tileTerrain.mesh = mesh;
            tileTerrain.state = TerrainState.TRANSFORMED;
        }, function() {
            tileTerrain.state = TerrainState.FAILED;
        });
    }

    function createResources(tileTerrain, context, terrainProvider, x, y, level) {
        var datatype = ComponentDatatype.FLOAT;
        var typedArray = tileTerrain.mesh.vertices;
        var buffer = context.createVertexBuffer(typedArray, BufferUsage.STATIC_DRAW);
        var stride = 6 * datatype.sizeInBytes;
        var position3DAndHeightLength = 4;

        var attributes = [{
            index : terrainAttributeLocations.position3DAndHeight,
            vertexBuffer : buffer,
            componentDatatype : datatype,
            componentsPerAttribute : position3DAndHeightLength,
            offsetInBytes : 0,
            strideInBytes : stride
        }, {
            index : terrainAttributeLocations.textureCoordinates,
            vertexBuffer : buffer,
            componentDatatype : datatype,
            componentsPerAttribute : 2,
            offsetInBytes : position3DAndHeightLength * datatype.sizeInBytes,
            strideInBytes : stride
        }];

        var indexBuffers = tileTerrain.mesh.indices.indexBuffers || {};
        var indexBuffer = indexBuffers[context.id];
        if (!defined(indexBuffer) || indexBuffer.isDestroyed()) {
            var indices = tileTerrain.mesh.indices;
            indexBuffer = context.createIndexBuffer(indices, BufferUsage.STATIC_DRAW, IndexDatatype.UNSIGNED_SHORT);
            indexBuffer.vertexArrayDestroyable = false;
            indexBuffer.referenceCount = 1;
            indexBuffers[context.id] = indexBuffer;
            tileTerrain.mesh.indices.indexBuffers = indexBuffers;
        } else {
            ++indexBuffer.referenceCount;
        }

        tileTerrain.vertexArray = context.createVertexArray(attributes, indexBuffer);

        tileTerrain.state = TerrainState.READY;
    }

    return TileTerrain;
});
<|endoftext|>


<commit_before>'use strict';

const expect = require('chai').expect;
const fs = require('fs-extra');

describe('Main Installer', function () {
  it('should copy conf.yml to the root directory', function () {
    expect(fs.existsSync('conf.yml')).to.equal(true);
  });

  it('should copy patternlab-config.json to the root directory', function () {
    expect(fs.existsSync('patternlab-config.json')).to.equal(true);
  });

  it('should complete with pref.yml in the root directory', function () {
    expect(fs.existsSync('pref.yml')).to.equal(true);
  });

  it('should complete with source in the root directory', function () {
    expect(fs.existsSync('source')).to.equal(true);
  });

  it('should copy extend to the root directory', function () {
    expect(fs.existsSync('extend')).to.equal(true);
  });

  it('should install npms in the extend directory', function () {
    expect(fs.existsSync('extend/node_modules')).to.equal(true);
  });

  it('should install npms in the public directory', function () {
    expect(fs.existsSync('public/node_modules')).to.equal(true);
  });

  it('should compile styleguide.html to public/node_modules/fepper-ui/', function () {
    expect(fs.existsSync('public/node_modules/fepper-ui/styleguide.html')).to.equal(true);
  });
});
<commit_msg>unit test checks for index.mustache<commit_after>'use strict';

const expect = require('chai').expect;
const fs = require('fs-extra');

describe('Main Installer', function () {
  it('should copy conf.yml to the root directory', function () {
    expect(fs.existsSync('conf.yml')).to.equal(true);
  });

  it('should copy patternlab-config.json to the root directory', function () {
    expect(fs.existsSync('patternlab-config.json')).to.equal(true);
  });

  it('should complete with pref.yml in the root directory', function () {
    expect(fs.existsSync('pref.yml')).to.equal(true);
  });

  it('should complete with source in the root directory', function () {
    expect(fs.existsSync('source')).to.equal(true);
  });

  it('should copy extend to the root directory', function () {
    expect(fs.existsSync('extend')).to.equal(true);
  });

  it('should install npms in the extend directory', function () {
    expect(fs.existsSync('extend/node_modules')).to.equal(true);
  });

  it('should install npms in the public directory', function () {
    expect(fs.existsSync('public/node_modules')).to.equal(true);
  });

  it('should compile index.mustache to node_modules/fepper/ui/core/styleguide/', function () {
    expect(fs.existsSync('node_modules/fepper/ui/core/styleguide/index.mustache')).to.equal(true);
  });

  it('should compile styleguide.html to public/node_modules/fepper-ui/', function () {
    expect(fs.existsSync('public/node_modules/fepper-ui/styleguide.html')).to.equal(true);
  });
});
<|endoftext|>


<commit_before>/* global describe, it */
'use strict';

var assert = require('assert')
var bitcoin = require('../../')

describe('bitcoinjs-lib (blocks)', function () {
  it('can extract a height from a CoinBase transaction', function () {
    // from 00000000000000000097669cdca131f24d40c4cc7d80eaa65967a2d09acf6ce6
    let txHex = '010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff50037f9a07174d696e656420627920416e74506f6f6c685b205a2b1f7bfabe6d6d36afe1910eca9405b66f97750940a656e38e2c0312958190ff8e98fd16761d220400000000000000aa340000d49f0000ffffffff02b07fc366000000001976a9148349212dc27ce3ab4c5b29b85c4dec643d764b1788ac0000000000000000266a24aa21a9ed72d9432948505e3d3062f1307a3f027a5dea846ff85e47159680919c12bf1e400120000000000000000000000000000000000000000000000000000000000000000000000000'
    let tx = bitcoin.Transaction.fromHex(txHex)

    assert.strictEqual(tx.ins.length, 1)
    let script = tx.ins[0].script
//  bitcoin.script.decompile(script) // returns [] :(

    assert.strictEqual(script[0], 0x03)
    let heightBuffer = script.slice(1, 4)
    let height = bitcoin.script.number.decode(heightBuffer)
    assert.strictEqual(height, 498303)
  })
})
<commit_msg>fix standard issue<commit_after>/* global describe, it */
'use strict'

var assert = require('assert')
var bitcoin = require('../../')

describe('bitcoinjs-lib (blocks)', function () {
  it('can extract a height from a CoinBase transaction', function () {
    // from 00000000000000000097669cdca131f24d40c4cc7d80eaa65967a2d09acf6ce6
    let txHex = '010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff50037f9a07174d696e656420627920416e74506f6f6c685b205a2b1f7bfabe6d6d36afe1910eca9405b66f97750940a656e38e2c0312958190ff8e98fd16761d220400000000000000aa340000d49f0000ffffffff02b07fc366000000001976a9148349212dc27ce3ab4c5b29b85c4dec643d764b1788ac0000000000000000266a24aa21a9ed72d9432948505e3d3062f1307a3f027a5dea846ff85e47159680919c12bf1e400120000000000000000000000000000000000000000000000000000000000000000000000000'
    let tx = bitcoin.Transaction.fromHex(txHex)

    assert.strictEqual(tx.ins.length, 1)
    let script = tx.ins[0].script
//  bitcoin.script.decompile(script) // returns [] :(

    assert.strictEqual(script[0], 0x03)
    let heightBuffer = script.slice(1, 4)
    let height = bitcoin.script.number.decode(heightBuffer)
    assert.strictEqual(height, 498303)
  })
})
<|endoftext|>


<commit_before>import React from 'react';
import _ from 'lodash';

import Show from '../Show';
import {
  FontIcon,
  FlatButton,
  RaisedButton,
  Table,
  TableBody,
  TableRowColumn,
  TableRow,
  TableHeader,
  TableHeaderColumn
} from 'material-ui';
import { colors as Colors } from 'material-ui/styles';
import { BashSnippet } from '../../common';

const EmptyViewCLI = ({
  bashSnippets,
  buttonLabel,
  CLITitle,
  CLIDescription,
  docsUrl,
  description,
  handleClick,
  handleErrorsButtonClick,
  hostingDocsUrl,
  hostingDocsButtonLabel,
  iconClassName,
  iconColor,
  isUploadFinished,
  mainTitle,
  showDocsUrl = true,
  errorResponses,
  urlLabel,
  actionButton = (
    <RaisedButton
      label={buttonLabel}
      primary={true}
      onTouchTap={handleClick}
      data-e2e="zero-state-add-button"
    />
  ),
  ...other
}) => {
  const styles = {
    container: {
      display: 'flex',
      flexDirection: 'column',
      justifyContent: 'space-around',
      alignItems: 'center',
      height: '100%',
      textAlign: 'center',
      padding: '40px 60px'
    },
    mainContainer: {
      width: 640,
      height: 770,
      border: '2px #dedede dashed',
      borderRadius: 5,
      margin: '50px auto 0 auto',
      color: '#000'
    },
    icon: {
      fontSize: 72
    },
    title: {
      marginTop: 40,
      fontSize: 26,
      fontWeight: 400,
      lineHeight: '34px',
      display: 'flex',
      justifyContent: 'center',
      alignItems: 'center'
    },
    description: {
      lineHeight: '26px',
      fontSize: 18
    },
    docsButton: {
      marginTop: 10
    },
    errorIcon: {
      marginRight: 5,
      display: 'inline-flex',
      fontSize: 30
    },
    tableBody: {
      display: 'block',
      height: 250
    },
    tableRow: {
      display: 'flex'
    },
    tableRowColumnLeft: {
      flex: 2,
      textOverflow: 'clip',
      overflow: 'scroll',
      paddingLeft: 0
    },
    tableRowColumnRight: {
      flex: 1,
      color: Colors.red500
    },
    tableHeaderColumnLeft: {
      flex: 2
    },
    tableHeaderColumnRight: {
      flex: 1
    },
    alignCenter: {
      display: 'flex',
      alignItems: 'center',
      flexWrap: 'wrap'
    },
    errorsBackButton: {
      marginTop: 15
    }
  };

  const renderSnippets = (
    _.map(bashSnippets, (item) => (
      <BashSnippet
        description={item.description}
        snippet={item.snippet}
      />
      )
    )
  );

  const renderErrors = (
    _.map(errorResponses, (errorResponse) => {
      const fieldsErrors = errorResponse.errors && (errorResponse.errors.path || errorResponse.errors.file);

      errorResponse.message = errorResponse.message[0].toUpperCase() + errorResponse.message.slice(1);
      const error = fieldsErrors || errorResponse.message;

      return (
        <TableRow style={styles.tableRow}>
          <TableRowColumn style={{ ...styles.tableRowColumnLeft, ...styles.alignCenter }}>
            {errorResponse.file.path}
          </TableRowColumn>
          <TableRowColumn style={{ ...styles.tableRowColumnRight, ...styles.alignCenter }}>
            {error}
          </TableRowColumn>
        </TableRow>
      );
    })
  );

  const renderErrorsView = (

        <FontIcon
          className="synicon-alert-circle-outline"
          color={Colors.red500}
          style={styles.errorIcon}
        />
        Errors

        The following {errorResponses.length} files had problems while uploading.

        <TableHeader
          displaySelectAll={false}
          adjustForCheckbox={false}
        >
          <TableRow style={styles.tableRow}>
            <TableHeaderColumn
              style={{ ...styles.tableHeaderColumnLeft, ...styles.alignCenter }}
            >
              Path
            </TableHeaderColumn>
            <TableHeaderColumn
              style={{ ...styles.tableHeaderColumnRight, ...styles.alignCenter }}
            >
              Error
            </TableHeaderColumn>
          </TableRow>
        </TableHeader>
        <TableBody
          displayRowCheckbox={false}
          style={styles.tableBody}
        >
          {renderErrors}
        </TableBody>

      <FlatButton
        label="Back"
        primary={true}
        style={styles.errorsBackButton}
        onTouchTap={handleErrorsButtonClick}
        disabled={!isUploadFinished}
      />

  );

  const renderCLIUsage = (

        {CLITitle}

        {CLIDescription}

          Syncano CLI.

      {renderSnippets}
      <FlatButton
        label={hostingDocsButtonLabel}
        primary={true}
        href={hostingDocsUrl}
        target="_blank"
        style={styles.docsButton}
      />

  );

  return (

        <FontIcon
          className={iconClassName}
          color={iconColor}
          style={styles.icon}
        />

          {mainTitle}

          {description}

        <Show if={showDocsUrl}>

            Read our

              {` ${urlLabel} docs `}

            to learn more.

        </Show>
        {actionButton}
        {!errorResponses.length ? renderCLIUsage : renderErrorsView}

  );
};

export default EmptyViewCLI;
<commit_msg>[DASH-2284] Change button label<commit_after>import React from 'react';
import _ from 'lodash';

import Show from '../Show';
import {
  FontIcon,
  FlatButton,
  RaisedButton,
  Table,
  TableBody,
  TableRowColumn,
  TableRow,
  TableHeader,
  TableHeaderColumn
} from 'material-ui';
import { colors as Colors } from 'material-ui/styles';
import { BashSnippet } from '../../common';

const EmptyViewCLI = ({
  bashSnippets,
  buttonLabel,
  CLITitle,
  CLIDescription,
  docsUrl,
  description,
  handleClick,
  handleErrorsButtonClick,
  hostingDocsUrl,
  hostingDocsButtonLabel,
  iconClassName,
  iconColor,
  isUploadFinished,
  mainTitle,
  showDocsUrl = true,
  errorResponses,
  urlLabel,
  actionButton = (
    <RaisedButton
      label={buttonLabel}
      primary={true}
      onTouchTap={handleClick}
      data-e2e="zero-state-add-button"
    />
  ),
  ...other
}) => {
  const styles = {
    container: {
      display: 'flex',
      flexDirection: 'column',
      justifyContent: 'space-around',
      alignItems: 'center',
      height: '100%',
      textAlign: 'center',
      padding: '40px 60px'
    },
    mainContainer: {
      width: 640,
      height: 770,
      border: '2px #dedede dashed',
      borderRadius: 5,
      margin: '50px auto 0 auto',
      color: '#000'
    },
    icon: {
      fontSize: 72
    },
    title: {
      marginTop: 40,
      fontSize: 26,
      fontWeight: 400,
      lineHeight: '34px',
      display: 'flex',
      justifyContent: 'center',
      alignItems: 'center'
    },
    description: {
      lineHeight: '26px',
      fontSize: 18
    },
    docsButton: {
      marginTop: 10
    },
    errorIcon: {
      marginRight: 5,
      display: 'inline-flex',
      fontSize: 30
    },
    tableBody: {
      display: 'block',
      height: 250
    },
    tableRow: {
      display: 'flex'
    },
    tableRowColumnLeft: {
      flex: 2,
      textOverflow: 'clip',
      overflow: 'scroll',
      paddingLeft: 0
    },
    tableRowColumnRight: {
      flex: 1,
      color: Colors.red500
    },
    tableHeaderColumnLeft: {
      flex: 2
    },
    tableHeaderColumnRight: {
      flex: 1
    },
    alignCenter: {
      display: 'flex',
      alignItems: 'center',
      flexWrap: 'wrap'
    },
    errorsBackButton: {
      marginTop: 15
    }
  };

  const renderSnippets = (
    _.map(bashSnippets, (item) => (
      <BashSnippet
        description={item.description}
        snippet={item.snippet}
      />
      )
    )
  );

  const renderErrors = (
    _.map(errorResponses, (errorResponse) => {
      const fieldsErrors = errorResponse.errors && (errorResponse.errors.path || errorResponse.errors.file);

      errorResponse.message = errorResponse.message[0].toUpperCase() + errorResponse.message.slice(1);
      const error = fieldsErrors || errorResponse.message;

      return (
        <TableRow style={styles.tableRow}>
          <TableRowColumn style={{ ...styles.tableRowColumnLeft, ...styles.alignCenter }}>
            {errorResponse.file.path}
          </TableRowColumn>
          <TableRowColumn style={{ ...styles.tableRowColumnRight, ...styles.alignCenter }}>
            {error}
          </TableRowColumn>
        </TableRow>
      );
    })
  );

  const renderErrorsView = (

        <FontIcon
          className="synicon-alert-circle-outline"
          color={Colors.red500}
          style={styles.errorIcon}
        />
        Errors

        The following {errorResponses.length} files had problems while uploading.

        <TableHeader
          displaySelectAll={false}
          adjustForCheckbox={false}
        >
          <TableRow style={styles.tableRow}>
            <TableHeaderColumn
              style={{ ...styles.tableHeaderColumnLeft, ...styles.alignCenter }}
            >
              Path
            </TableHeaderColumn>
            <TableHeaderColumn
              style={{ ...styles.tableHeaderColumnRight, ...styles.alignCenter }}
            >
              Error
            </TableHeaderColumn>
          </TableRow>
        </TableHeader>
        <TableBody
          displayRowCheckbox={false}
          style={styles.tableBody}
        >
          {renderErrors}
        </TableBody>

      <FlatButton
        label="Close"
        primary={true}
        style={styles.errorsBackButton}
        onTouchTap={handleErrorsButtonClick}
        disabled={!isUploadFinished}
      />

  );

  const renderCLIUsage = (

        {CLITitle}

        {CLIDescription}

          Syncano CLI.

      {renderSnippets}
      <FlatButton
        label={hostingDocsButtonLabel}
        primary={true}
        href={hostingDocsUrl}
        target="_blank"
        style={styles.docsButton}
      />

  );

  return (

        <FontIcon
          className={iconClassName}
          color={iconColor}
          style={styles.icon}
        />

          {mainTitle}

          {description}

        <Show if={showDocsUrl}>

            Read our

              {` ${urlLabel} docs `}

            to learn more.

        </Show>
        {actionButton}
        {!errorResponses.length ? renderCLIUsage : renderErrorsView}

  );
};

export default EmptyViewCLI;
<|endoftext|>


<commit_before>var test = require('tape')
const {handleMessages} = require('././utils')
const canvasApi = require('../../canvasApi')
const randomstring = require('randomstring')

test.only('should enroll an assistant in an existing course in canvas', t => {
  t.plan(1)
  let canvasCourse
  const message = {
    'kthid': 'u2kub9j5',
    'ugClass': 'group',
    'deleted': false,
    'ug1Name': 'edu.courses.SF.SF1625.20171.1.assistants',
    'name_en': 'Teacher assistants for SF1625 Spring 17 1',
    'name_sv': 'Lärarassistenter på SF1625 VT17 1',
    'member': ['u1znmoik']}

  const courseCode = 'A' + randomstring.generate(5)

  const course = {
    'name': 'Emil testar',
    'course_code': courseCode,
    'sis_course_id': `${courseCode}HT161`,
    'start_at': '2016-08-29T09:15:03.346Z'
  }

  // First create a fresch course in canvas
  canvasApi.createCourse({course}, 14) // Courses that starts with an 'A' is handled by this account
  .then(res => {
    canvasCourse = res
    console.log('canvasCourse', canvasCourse)
  })
  .then(() => handleMessages(message))
  .then(([{resp}]) => canvasApi.pollUntilSisComplete(resp.id))
  .then(()=> canvasApi.getEnrollments(canvasCourse.id))
  .then(enrollments => t.equal(enrollments, ['u1znmoik']))
})
<commit_msg>using a message for the same course as just created<commit_after>var test = require('tape')
const {handleMessages} = require('././utils')
const canvasApi = require('../../canvasApi')
const randomstring = require('randomstring')

test.only('should enroll an assistant in an existing course in canvas', t => {
  t.plan(1)
  let canvasCourse

  const courseCode = 'A' + randomstring.generate(5)

  const message = {
    'kthid': 'u2kub9j5',
    'ugClass': 'group',
    'deleted': false,
    'ug1Name': `edu.courses.SF.${courseCode}.20171.1.assistants`,
    'name_en': 'Teacher assistants for SF1625 Spring 17 1',
    'name_sv': 'Lärarassistenter på SF1625 VT17 1',
    'member': ['u1znmoik']}

  const course = {
    'name': 'Emil testar',
    'course_code': courseCode,
    'sis_course_id': `${courseCode}VT171`,
    'start_at': '2016-08-29T09:15:03.346Z'
  }

  // First create a fresch course in canvas
  canvasApi.createCourse({course}, 14) // Courses that starts with an 'A' is handled by this account
  .then(res => {
    canvasCourse = res
    console.log('canvasCourse', canvasCourse)
  })
  .then(() => handleMessages(message))
  .then(([{resp}]) => canvasApi.pollUntilSisComplete(resp.id))
  .then(()=> canvasApi.getEnrollments(canvasCourse.id))
  .then(enrollments => t.equal(enrollments, ['u1znmoik']))
})
<|endoftext|>


<commit_before>var Checker = require('jscs/lib/checker');
var assert = require('assert');

describe('rules/require-dictionary-words', function() {
    var checker;
    beforeEach(function() {
        checker = new Checker();
        checker.registerDefaultRules();
        checker.configure({ plugins: ['./lib/index.js'] });
    });

    describe('true', function() {
        beforeEach(function() {
            checker.configure({ requireDictionaryWords: true });
        });

        it('should report non-words', function() {
            assert(checker.checkString('asdf = 1;').getErrorCount() === 1);
            assert(checker.checkString('var asdf = 1;').getErrorCount() === 1);
            assert(checker.checkString('let asdf = 1;').getErrorCount() === 1);
            assert(checker.checkString('const asdf = 1;').getErrorCount() === 1);
            assert(checker.checkString('function asdf(jkl) {var asdf = 1;}').getErrorCount() === 3);
            assert(checker.checkString('var asdf = function asdf() {};').getErrorCount() === 2);
            assert(checker.checkString('for(asdf = 0; asdf<1; asdf++){asdf;}').getErrorCount() === 1);
            assert(checker.checkString('object["jkl"] = 1;').getErrorCount() === 1);
            assert(checker.checkString('object.jkl = 1;').getErrorCount() === 1);
            assert(checker.checkString('object = {jkl: 1};').getErrorCount() === 1);
            assert(checker.checkString('object = {"jkl": 1};').getErrorCount() === 1);
            assert(checker.checkString('asdf: void 0;').getErrorCount() === 1);

            assert(checker.checkString('JKL = 1;').getErrorCount() === 1);
        });

        it('should report multiple non-words', function() {
            assert(checker.checkString('asdfAsdf = 1;').getErrorCount() === 2);
            assert(checker.checkString('asdfASDF = 1;').getErrorCount() === 2);
            assert(checker.checkString('asdfASDFAsdf = 1;').getErrorCount() === 3);
            assert(checker.checkString('asdf_asdf = 1;').getErrorCount() === 2);
        });

        it('should ignore numbers and symbols', function() {
            assert(checker.checkString('$asdfAsdf = 1;').getErrorCount() === 2);
            assert(checker.checkString('asdf$Asdf = 1;').getErrorCount() === 2);
            assert(checker.checkString('asdfAsdf$ = 1;').getErrorCount() === 2);
            assert(checker.checkString('asdf9Asdf = 1;').getErrorCount() === 2);
            assert(checker.checkString('asdfAsdf9 = 1;').getErrorCount() === 2);
        });

        it('should not report non-"instantiation" usages', function() {
            assert(checker.checkString('asdf').isEmpty());
            assert(checker.checkString('asdf.jkl').isEmpty());
            assert(checker.checkString('asdf(jkl)').isEmpty());
            assert(checker.checkString('asdf.jkl(jkl)').isEmpty());
            assert(checker.checkString('value = asdf').isEmpty());
            assert(checker.checkString('var value = asdf').isEmpty());
            assert(checker.checkString('object.property = asdf').isEmpty());
            assert(checker.checkString('if(asdf){}').isEmpty());
            assert(checker.checkString('object[jkl] = 1;').isEmpty());
        });

        it('should not report real words', function() {
            assert(checker.checkString('good = 1;').isEmpty());
        });

        it('should not report multiple real words', function() {
            assert(checker.checkString('goodGood = 1;').isEmpty());
        });
    });

    describe('esnext', function() {
        beforeEach(function() {
            checker.configure({ requireDictionaryWords: true, esnext: true });
        });

        it('should report non-words in es6', function() {
            assert(checker.checkString('object = {asdf, jkl() {}, [0 + 1]: 2};').getErrorCount() === 2);
            assert(checker.checkString('class Asdf { jkl() {} }').getErrorCount() === 2);
        });

        it('should not report real words in es6', function() {
            assert(checker.checkString('object = {good, good() {}, [0 + 1]: 2};').isEmpty());
            assert(checker.checkString('class Good { good() {} }').isEmpty());
        });
    });

    describe('allowWords', function() {
        beforeEach(function() {
            checker.configure({
                requireDictionaryWords: {
                    allowWords: ['asdf', 'jkl']
                }
            });
        });

        it('should not report included words', function() {
            assert(checker.checkString('asdf = 1;').isEmpty());
            assert(checker.checkString('object.jkl = 1;').isEmpty());
            assert(checker.checkString('asdfAsdf = 1;').isEmpty());
            assert(checker.checkString('object.jklJkl = 1;').isEmpty());
        });
    });

    describe('allowNames', function() {
        beforeEach(function() {
            checker.configure({
                requireDictionaryWords: {
                    allowNames: ['asdf', 'jkl']
                }
            });
        });

        it('should report names used as substrings', function() {
            assert(checker.checkString('asdfAsdf = 1;').getErrorCount() === 2);
            assert(checker.checkString('object.jklJkl = 1;').getErrorCount() === 2);
        });

        it('should not report included names', function() {
            assert(checker.checkString('asdf = 1;').isEmpty());
            assert(checker.checkString('object.jkl = 1;').isEmpty());
        });
    });

    describe('allowWordsInProperties', function() {
        beforeEach(function() {
            checker.configure({
                requireDictionaryWords: {
                    allowWordsInProperties: ['asdf', 'jkl']
                }
            });
        });

        it('should report non-words', function() {
            assert(checker.checkString('asdf = 1;').getErrorCount() === 1);
            assert(checker.checkString('asdfAsdf = 1;').getErrorCount() === 2);
        });

        it('should not report included words', function() {
            assert(checker.checkString('object.jkl = 1;').isEmpty());
            assert(checker.checkString('object.jklJkl = 1;').isEmpty());
        });
    });

    describe('allowNamesAsProperties', function() {
        beforeEach(function() {
            checker.configure({
                requireDictionaryWords: {
                    allowNamesAsProperties: ['asdf', 'jkl']
                }
            });
        });

        it('should report names used as substrings', function() {
            assert(checker.checkString('object.jklJkl = 1;').getErrorCount() === 2);
        });

        it('should report non-names', function() {
            assert(checker.checkString('asdf = 1;').getErrorCount() === 1);
            assert(checker.checkString('asdfAsdf = 1;').getErrorCount() === 2);
        });

        it('should not report included names', function() {
            assert(checker.checkString('object.jkl = 1;').isEmpty());
        });
    });

    describe('excludeWords', function() {
        beforeEach(function() {
            checker.configure({
                requireDictionaryWords: {
                    excludeWords: ['good']
                }
            });
        });

        it('should report excluded words', function() {
            assert(checker.checkString('good = 1;').getErrorCount() === 1);
            assert(checker.checkString('object.good = 1;').getErrorCount() === 1);
        });
    });

    describe('dictionaries', function() {
        describe('english', function() {
            beforeEach(function() {
                checker.configure({
                    requireDictionaryWords: {
                        dictionaries: ['english']
                    }
                });
            });

            it('should report non-words', function() {
                assert(checker.checkString('color = 1;').getErrorCount() === 1);
            });
        });

        describe('english, american', function() {
            beforeEach(function() {
                checker.configure({
                    requireDictionaryWords: {
                        dictionaries: ['english', 'american']
                    }
                });
            });

            it('should not report real words', function() {
                assert(checker.checkString('color = 1;').isEmpty());
            });
        });

        describe('missing dictionary', function() {
            it('should throw an informative error', function() {
                var missingLanguage = 'elvish';
                assert.throws(function() {
                    checker.configure({
                        requireDictionaryWords: {
                            dictionaries: [missingLanguage]
                        }
                    });
                }, new RegExp('wordlist-' + missingLanguage));
            });
        });
    });
});
<commit_msg>Tests: Update requireDictionaryWords spec wordings<commit_after>var Checker = require('jscs/lib/checker');
var assert = require('assert');

describe('rules/require-dictionary-words', function() {
    var checker;
    beforeEach(function() {
        checker = new Checker();
        checker.registerDefaultRules();
        checker.configure({ plugins: ['./lib/index.js'] });
    });

    describe('true', function() {
        beforeEach(function() {
            checker.configure({ requireDictionaryWords: true });
        });

        it('should report non-words', function() {
            assert(checker.checkString('asdf = 1;').getErrorCount() === 1);
            assert(checker.checkString('var asdf = 1;').getErrorCount() === 1);
            assert(checker.checkString('let asdf = 1;').getErrorCount() === 1);
            assert(checker.checkString('const asdf = 1;').getErrorCount() === 1);
            assert(checker.checkString('function asdf(jkl) {var asdf = 1;}').getErrorCount() === 3);
            assert(checker.checkString('var asdf = function asdf() {};').getErrorCount() === 2);
            assert(checker.checkString('for(asdf = 0; asdf<1; asdf++){asdf;}').getErrorCount() === 1);
            assert(checker.checkString('object["jkl"] = 1;').getErrorCount() === 1);
            assert(checker.checkString('object.jkl = 1;').getErrorCount() === 1);
            assert(checker.checkString('object = {jkl: 1};').getErrorCount() === 1);
            assert(checker.checkString('object = {"jkl": 1};').getErrorCount() === 1);
            assert(checker.checkString('asdf: void 0;').getErrorCount() === 1);

            assert(checker.checkString('JKL = 1;').getErrorCount() === 1);
        });

        it('should report multiple non-words', function() {
            assert(checker.checkString('asdfAsdf = 1;').getErrorCount() === 2);
            assert(checker.checkString('asdfASDF = 1;').getErrorCount() === 2);
            assert(checker.checkString('asdfASDFAsdf = 1;').getErrorCount() === 3);
            assert(checker.checkString('asdf_asdf = 1;').getErrorCount() === 2);
        });

        it('should ignore numbers and symbols', function() {
            assert(checker.checkString('$asdfAsdf = 1;').getErrorCount() === 2);
            assert(checker.checkString('asdf$Asdf = 1;').getErrorCount() === 2);
            assert(checker.checkString('asdfAsdf$ = 1;').getErrorCount() === 2);
            assert(checker.checkString('asdf9Asdf = 1;').getErrorCount() === 2);
            assert(checker.checkString('asdfAsdf9 = 1;').getErrorCount() === 2);
        });

        it('should not report non-"instantiation" usages', function() {
            assert(checker.checkString('asdf').isEmpty());
            assert(checker.checkString('asdf.jkl').isEmpty());
            assert(checker.checkString('asdf(jkl)').isEmpty());
            assert(checker.checkString('asdf.jkl(jkl)').isEmpty());
            assert(checker.checkString('value = asdf').isEmpty());
            assert(checker.checkString('var value = asdf').isEmpty());
            assert(checker.checkString('object.property = asdf').isEmpty());
            assert(checker.checkString('if(asdf){}').isEmpty());
            assert(checker.checkString('object[jkl] = 1;').isEmpty());
        });

        it('should not report defined words', function() {
            assert(checker.checkString('good = 1;').isEmpty());
        });

        it('should not report multiple defined words', function() {
            assert(checker.checkString('goodGood = 1;').isEmpty());
        });
    });

    describe('esnext', function() {
        beforeEach(function() {
            checker.configure({ requireDictionaryWords: true, esnext: true });
        });

        it('should report non-words in es6', function() {
            assert(checker.checkString('object = {asdf, jkl() {}, [0 + 1]: 2};').getErrorCount() === 2);
            assert(checker.checkString('class Asdf { jkl() {} }').getErrorCount() === 2);
        });

        it('should not report defined words in es6', function() {
            assert(checker.checkString('object = {good, good() {}, [0 + 1]: 2};').isEmpty());
            assert(checker.checkString('class Good { good() {} }').isEmpty());
        });
    });

    describe('allowWords', function() {
        beforeEach(function() {
            checker.configure({
                requireDictionaryWords: {
                    allowWords: ['asdf', 'jkl']
                }
            });
        });

        it('should not report allowed words', function() {
            assert(checker.checkString('asdf = 1;').isEmpty());
            assert(checker.checkString('object.jkl = 1;').isEmpty());
            assert(checker.checkString('asdfAsdf = 1;').isEmpty());
            assert(checker.checkString('object.jklJkl = 1;').isEmpty());
        });
    });

    describe('allowNames', function() {
        beforeEach(function() {
            checker.configure({
                requireDictionaryWords: {
                    allowNames: ['asdf', 'jkl']
                }
            });
        });

        it('should report names used as parts of names', function() {
            assert(checker.checkString('asdfAsdf = 1;').getErrorCount() === 2);
            assert(checker.checkString('object.jklJkl = 1;').getErrorCount() === 2);
        });

        it('should not report allowed names', function() {
            assert(checker.checkString('asdf = 1;').isEmpty());
            assert(checker.checkString('object.jkl = 1;').isEmpty());
        });
    });

    describe('allowWordsInProperties', function() {
        beforeEach(function() {
            checker.configure({
                requireDictionaryWords: {
                    allowWordsInProperties: ['asdf', 'jkl']
                }
            });
        });

        it('should report non-words in identifiers', function() {
            assert(checker.checkString('asdf = 1;').getErrorCount() === 1);
            assert(checker.checkString('asdfAsdf = 1;').getErrorCount() === 2);
        });

        it('should not report allowed words in properties', function() {
            assert(checker.checkString('object.jkl = 1;').isEmpty());
            assert(checker.checkString('object.jklJkl = 1;').isEmpty());
        });
    });

    describe('allowNamesAsProperties', function() {
        beforeEach(function() {
            checker.configure({
                requireDictionaryWords: {
                    allowNamesAsProperties: ['asdf', 'jkl']
                }
            });
        });

        it('should report non-names and identifiers', function() {
            assert(checker.checkString('asdf = 1;').getErrorCount() === 1);
            assert(checker.checkString('asdfAsdf = 1;').getErrorCount() === 2);
            assert(checker.checkString('object.jklJkl = 1;').getErrorCount() === 2);
        });

        it('should not report allowed names as properties', function() {
            assert(checker.checkString('object.jkl = 1;').isEmpty());
        });
    });

    describe('excludeWords', function() {
        beforeEach(function() {
            checker.configure({
                requireDictionaryWords: {
                    excludeWords: ['good']
                }
            });
        });

        it('should report excluded words', function() {
            assert(checker.checkString('good = 1;').getErrorCount() === 1);
            assert(checker.checkString('object.good = 1;').getErrorCount() === 1);
        });
    });

    describe('dictionaries', function() {
        describe('english', function() {
            beforeEach(function() {
                checker.configure({
                    requireDictionaryWords: {
                        dictionaries: ['english']
                    }
                });
            });

            it('should report non-words', function() {
                assert(checker.checkString('color = 1;').getErrorCount() === 1);
            });
        });

        describe('english, american', function() {
            beforeEach(function() {
                checker.configure({
                    requireDictionaryWords: {
                        dictionaries: ['english', 'american']
                    }
                });
            });

            it('should not report defined words', function() {
                assert(checker.checkString('color = 1;').isEmpty());
            });
        });

        describe('missing dictionary', function() {
            it('should throw an informative error', function() {
                var missingLanguage = 'elvish';
                assert.throws(function() {
                    checker.configure({
                        requireDictionaryWords: {
                            dictionaries: [missingLanguage]
                        }
                    });
                }, new RegExp('wordlist-' + missingLanguage));
            });
        });
    });
});
<|endoftext|>


<commit_before>var colors = require('colors'),
		start = new Date().getTime(),
		pad = "   ",
		items = {},
		util = require('util')

//
// This is a single item (Or cell or whatever you call it) in the status display
//
var Item = function(options) {
	this.name = options.name
	this.label = (options.label) ? options.label : options.name
	this.count = 0
	options.count && (this.count = options.count)
	options.max && (this.max = options.max)
	options.color && (this.color = colors[options.color])
	this.type = (options.type) ? options.type : "count"
	this.precision = (options.precision != undefined) ? options.precision : 2
}

//
// Repeats a string, using it for the status bar instead of loops
//
String.prototype.repeat = function( len ) {return new Array(len + 1).join(this)}

//
// Render the status bar row
// Loops through all items, then loops through the different types for each item
// If stamp is true, it will console.log it instead of doing an stdout
//
var render = function(stamp){
	var out = ""
  for (var i in items) {

    var c = items[i],
  		nums = (c.color ? c.color(c.label) : c.label) + ": ",
  		types = c.type

    if( Object.prototype.toString.call( types ) !== '[object Array]' )
    	types = [c.type]

		for (var a = 0; a < types.length; a++) {
			if(a > 0)
				nums += pad
	    switch(types[a]) {
	    	case "percentage":
	    		if(!c.max) break;
	    		nums += (100 * c.count/c.max).toFixed(c.precision) + " %"
	    		break;
	    	case "time":
	    		nums += nicetime(new Date().getTime() - start)
	    		break;
	    	case "bar":
	    		if(!c.max) break;
	    		var bar_len = 10
	    		var done = Math.round(bar_len * c.count/c.max)
	    		nums += "[" + ("▒").repeat(done) + ("-").repeat(bar_len - done) + "]"
	    		break;
	    	default:
	    		nums += c.count + (c.max ? "/" + c.max : "")
	    		break;
	    }
	  }
    out += pad + nums + pad + "|"
  }
  if(out === "") return
  if(stamp) {
  	process.stdout.write("\u001B[2K")
  	console.log("Status @ " + nicetime(new Date().getTime() - start) + "|" + out + "\r")
  } else {
  	process.stdout.write("\u001B[2K  Status: |" +  out + "\r")
  }
}

//
// Currently just changes the milliseconds to either a number of seconds or number of minutes
//
var nicetime = function(ms){
	var seconds = ms / 1000
	var minutes = seconds / 60
	return (minutes < 2) ? seconds + "s " : minutes + " mins "
}

process.on('exit', function() {
  render(true)
});

//
// add a new item to the status bar
//
exports.addItem = function(name, options){
	options.name = name
	items[name] = new Item(options)
}

//
// Update the count on an item, then re-render
//
exports.updateCount = function(item, amount) {
	item = items[item]
	item.count += (amount != undefined) ? amount : 1
	if(item.max != undefined) item.count = Math.min(item.count, item.max)
	render()
}

exports.updateMax = function(item, amount) {
	item = items[item]
	item.max = amount
}

var clear_line = function(){ process.stdout.write("\u001B[2K") }

var log = function() {
	clear_line()
	console.log.apply(this,arguments)
	render()
}
var info = function() {
	clear_line()
	console.info.apply(this,arguments)
	render()
}
var warn = function() {
	clear_line()
	console.warn.apply(this,arguments)
	render()
}
var error = function() {
	clear_line()
	console.error.apply(this,arguments)
	render()
}
exports.clear = "\u001B[2K"

exports.console = function(){
	return {
		'log':log,
		'info':info,
		'error':error,
		'warn':warn
	}
}

var auto_stamp = false
exports.startAutoStamp = function(rate){
	if(!rate) rate = 10000
	exports.killAutoStamp()
	auto_stamp = setInterval(exports.stamp, rate)
}

exports.killAutoStamp = function(){
	if(auto_stamp) {
		clearInterval(auto_stamp)
	}
}

//
// Stamps the current status to the console
//
exports.stamp = function() {
	render(true)
}<commit_msg>Status does not start now until told to, or until autoStamp is initiated<commit_after>var colors = require('colors'),
		start = new Date().getTime(),
		pad = "   ",
		items = {},
		util = require('util'),
		running = false

//
// This is a single item (Or cell or whatever you call it) in the status display
//
var Item = function(options) {
	this.name = options.name
	this.label = (options.label) ? options.label : options.name
	this.count = 0
	options.count && (this.count = options.count)
	options.max && (this.max = options.max)
	options.color && (this.color = colors[options.color])
	this.type = (options.type) ? options.type : "count"
	this.precision = (options.precision != undefined) ? options.precision : 2
}

//
// Repeats a string, using it for the status bar instead of loops
//
String.prototype.repeat = function( len ) {return new Array(len + 1).join(this)}

//
// Render the status bar row
// Loops through all items, then loops through the different types for each item
// If stamp is true, it will console.log it instead of doing an stdout
//
var render = function(stamp){
	if(!running) return
	var out = ""
  for (var i in items) {

    var c = items[i],
  		nums = (c.color ? c.color(c.label) : c.label) + ": ",
  		types = c.type

    if( Object.prototype.toString.call( types ) !== '[object Array]' )
    	types = [c.type]

		for (var a = 0; a < types.length; a++) {
			if(a > 0)
				nums += pad
	    switch(types[a]) {
	    	case "percentage":
	    		if(!c.max) break;
	    		nums += (100 * c.count/c.max).toFixed(c.precision) + " %"
	    		break;
	    	case "time":
	    		nums += nicetime(new Date().getTime() - start)
	    		break;
	    	case "bar":
	    		if(!c.max) break;
	    		var bar_len = 10
	    		var done = Math.round(bar_len * c.count/c.max)
	    		nums += "[" + ("▒").repeat(done) + ("-").repeat(bar_len - done) + "]"
	    		break;
	    	default:
	    		nums += c.count + (c.max ? "/" + c.max : "")
	    		break;
	    }
	  }
    out += pad + nums + pad + "|"
  }
  if(out === "") return
  if(stamp) {
  	process.stdout.write("\u001B[2K")
  	console.log("Status @ " + nicetime(new Date().getTime() - start) + "|" + out + "\r")
  } else {
  	process.stdout.write("\u001B[2K  Status: |" +  out + "\r")
  }
}

//
// Currently just changes the milliseconds to either a number of seconds or number of minutes
//
var nicetime = function(ms,round){
	var seconds = (ms / 1000).toFixed(3)
	var minutes = (seconds / 60).toFixed(3)
	var time = (minutes < 2) ? seconds : minutes
	if(round) time = Math.round(time)
	return time + (minutes < 2 ?  "s " : "m ")
}

process.on('exit', function() {
  render(true)
});

//
// add a new item to the status bar
//
exports.addItem = function(name, options){
	options.name = name
	items[name] = new Item(options)
}

//
// Update the count on an item, then re-render
//
exports.updateCount = function(item, amount) {
	item = items[item]
	item.count += (amount != undefined) ? amount : 1
	if(item.max != undefined) item.count = Math.min(item.count, item.max)
	render()
}

exports.updateMax = function(item, amount) {
	item = items[item]
	item.max = amount
}

var clear_line = function(){ process.stdout.write("\u001B[2K") }

var log = function() {
	clear_line()
	console.log.apply(this,arguments)
	render()
}
var info = function() {
	clear_line()
	console.info.apply(this,arguments)
	render()
}
var warn = function() {
	clear_line()
	console.warn.apply(this,arguments)
	render()
}
var error = function() {
	clear_line()
	console.error.apply(this,arguments)
	render()
}
exports.clear = "\u001B[2K"

exports.console = function(){
	return {
		'log':log,
		'info':info,
		'error':error,
		'warn':warn
	}
}

var auto_stamp = false
exports.startAutoStamp = function(rate){
	running = true
	if(!rate) rate = 10000
	exports.killAutoStamp()
	auto_stamp = setInterval(exports.stamp, rate)
}

exports.killAutoStamp = function(){
	if(auto_stamp) {
		clearInterval(auto_stamp)
	}
}

exports.start = function(){
	running = true
}

//
// Stamps the current status to the console
//
exports.stamp = function() {
	render(true)
}<|endoftext|>


<commit_before>/* global describe, it */

var assert = require('assert')
var async = require('async')
var bigi = require('bigi')
var bitcoin = require('../../')
var blockchain = new (require('cb-blockr'))('bitcoin')
var crypto = require('crypto')

describe('bitcoinjs-lib (crypto)', function () {
  it('can generate a single-key stealth address', function () {
    var receiver = bitcoin.ECPair.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss')

    // XXX: ephemeral, must be random (and secret to sender) to preserve privacy
    var sender = bitcoin.ECPair.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct')

    var G = bitcoin.ECPair.curve.G
    var d = receiver.d // secret (receiver only)
    var Q = receiver.Q // shared

    var e = sender.d // secret (sender only)
    var P = sender.Q // shared

    // derived shared secret
    var eQ = Q.multiply(e) // sender
    var dP = P.multiply(d) // receiver
    assert.deepEqual(eQ.getEncoded(), dP.getEncoded())

    var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
    var cG = G.multiply(c)

    // derived public key
    var QprimeS = Q.add(cG)
    var QprimeR = G.multiply(d.add(c))
    assert.deepEqual(QprimeR.getEncoded(), QprimeS.getEncoded())

    // derived shared-secret address
    var address = new bitcoin.ECPair(null, QprimeS).getAddress()

    assert.strictEqual(address, '1EwCNJNZM5q58YPPTnjR1H5BvYRNeyZi47')
  })

  // TODO
  it.skip('can generate a dual-key stealth address', function () {})

  it("can recover a parent private key from the parent's public key and a derived non-hardened child private key", function () {
    function recoverParent (master, child) {
      assert(!master.keyPair.d, 'You already have the parent private key')
      assert(child.keyPair.d, 'Missing child private key')

      var curve = bitcoin.ECPair.curve
      var QP = master.keyPair.Q
      var serQP = master.keyPair.getPublicKeyBuffer()

      var d1 = child.keyPair.d
      var d2
      var indexBuffer = new Buffer(4)

      // search index space until we find it
      for (var i = 0; i < bitcoin.HDNode.HIGHEST_BIT; ++i) {
        indexBuffer.writeUInt32BE(i, 0)

        // calculate I
        var data = Buffer.concat([serQP, indexBuffer])
        var I = crypto.createHmac('sha512', master.chainCode).update(data).digest()
        var IL = I.slice(0, 32)
        var pIL = bigi.fromBuffer(IL)

        // See hdnode.js:273 to understand
        d2 = d1.subtract(pIL).mod(curve.n)

        var Qp = new bitcoin.ECPair(d2).Q
        if (Qp.equals(QP)) break
      }

      var node = new bitcoin.HDNode(new bitcoin.ECPair(d2), master.chainCode, master.network)
      node.depth = master.depth
      node.index = master.index
      node.masterFingerprint = master.masterFingerprint
      return node
    }

    var seed = crypto.randomBytes(32)
    var master = bitcoin.HDNode.fromSeedBuffer(seed)
    var child = master.derive(6) // m/6

    // now for the recovery
    var neuteredMaster = master.neutered()
    var recovered = recoverParent(neuteredMaster, child)
    assert.strictEqual(recovered.toBase58(), master.toBase58())
  })

  it('can recover a private key from duplicate R values', function () {
    var inputs = [
      {
        txId: 'f4c16475f2a6e9c602e4a287f9db3040e319eb9ece74761a4b84bc820fbeef50',
        vout: 0
      },
      {
        txId: 'f4c16475f2a6e9c602e4a287f9db3040e319eb9ece74761a4b84bc820fbeef50',
        vout: 1
      }
    ]

    var txIds = inputs.map(function (x) {
      return x.txId
    })

    // first retrieve the relevant transactions
    blockchain.transactions.get(txIds, function (err, results) {
      assert.ifError(err)

      var transactions = {}
      results.forEach(function (tx) {
        transactions[tx.txId] = bitcoin.Transaction.fromHex(tx.txHex)
      })

      var tasks = []

      // now we need to collect/transform a bit of data from the selected inputs
      inputs.forEach(function (input) {
        var transaction = transactions[input.txId]
        var script = transaction.ins[input.vout].script
        assert(bitcoin.scripts.isPubKeyHashInput(script), 'Expected pubKeyHash script')

        var prevOutTxId = bitcoin.bufferutils.reverse(transaction.ins[input.vout].hash).toString('hex')
        var prevVout = transaction.ins[input.vout].index

        tasks.push(function (callback) {
          blockchain.transactions.get(prevOutTxId, function (err, result) {
            if (err) return callback(err)

            var prevOut = bitcoin.Transaction.fromHex(result.txHex)
            var prevOutScript = prevOut.outs[prevVout].script

            var scriptSignature = bitcoin.ECSignature.parseScriptSignature(script.chunks[0])
            var publicKey = bitcoin.ECPair.fromPublicKeyBuffer(script.chunks[1])

            var m = transaction.hashForSignature(input.vout, prevOutScript, scriptSignature.hashType)
            assert(publicKey.verify(m, scriptSignature.signature), 'Invalid m')

            // store the required information
            input.signature = scriptSignature.signature
            input.z = bigi.fromBuffer(m)

            return callback()
          })
        })
      })

      // finally, run the tasks, then on to the math
      async.parallel(tasks, function (err) {
        if (err) throw err

        var n = bitcoin.ECPair.curve.n

        for (var i = 0; i < inputs.length; ++i) {
          for (var j = i + 1; j < inputs.length; ++j) {
            var inputA = inputs[i]
            var inputB = inputs[j]

            // enforce matching r values
            assert.strictEqual(inputA.signature.r.toString(), inputB.signature.r.toString())
            var r = inputA.signature.r
            var rInv = r.modInverse(n)

            var s1 = inputA.signature.s
            var s2 = inputB.signature.s
            var z1 = inputA.z
            var z2 = inputB.z

            var zz = z1.subtract(z2).mod(n)
            var ss = s1.subtract(s2).mod(n)

            // k = (z1 - z2) / (s1 - s2)
            // d1 = (s1 * k - z1) / r
            // d2 = (s2 * k - z2) / r
            var k = zz.multiply(ss.modInverse(n)).mod(n)
            var d1 = ((s1.multiply(k).mod(n)).subtract(z1).mod(n)).multiply(rInv).mod(n)
            var d2 = ((s2.multiply(k).mod(n)).subtract(z2).mod(n)).multiply(rInv).mod(n)

            // enforce matching private keys
            assert.strictEqual(d1.toString(), d2.toString())
          }
        }
      })
    })
  })
})
<commit_msg>integration: wait for duplicate R value recovery to finish<commit_after>/* global describe, it */

var assert = require('assert')
var async = require('async')
var bigi = require('bigi')
var bitcoin = require('../../')
var blockchain = new (require('cb-blockr'))('bitcoin')
var crypto = require('crypto')

describe('bitcoinjs-lib (crypto)', function () {
  it('can generate a single-key stealth address', function () {
    var receiver = bitcoin.ECPair.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss')

    // XXX: ephemeral, must be random (and secret to sender) to preserve privacy
    var sender = bitcoin.ECPair.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct')

    var G = bitcoin.ECPair.curve.G
    var d = receiver.d // secret (receiver only)
    var Q = receiver.Q // shared

    var e = sender.d // secret (sender only)
    var P = sender.Q // shared

    // derived shared secret
    var eQ = Q.multiply(e) // sender
    var dP = P.multiply(d) // receiver
    assert.deepEqual(eQ.getEncoded(), dP.getEncoded())

    var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
    var cG = G.multiply(c)

    // derived public key
    var QprimeS = Q.add(cG)
    var QprimeR = G.multiply(d.add(c))
    assert.deepEqual(QprimeR.getEncoded(), QprimeS.getEncoded())

    // derived shared-secret address
    var address = new bitcoin.ECPair(null, QprimeS).getAddress()

    assert.strictEqual(address, '1EwCNJNZM5q58YPPTnjR1H5BvYRNeyZi47')
  })

  // TODO
  it.skip('can generate a dual-key stealth address', function () {})

  it("can recover a parent private key from the parent's public key and a derived non-hardened child private key", function () {
    function recoverParent (master, child) {
      assert(!master.keyPair.d, 'You already have the parent private key')
      assert(child.keyPair.d, 'Missing child private key')

      var curve = bitcoin.ECPair.curve
      var QP = master.keyPair.Q
      var serQP = master.keyPair.getPublicKeyBuffer()

      var d1 = child.keyPair.d
      var d2
      var indexBuffer = new Buffer(4)

      // search index space until we find it
      for (var i = 0; i < bitcoin.HDNode.HIGHEST_BIT; ++i) {
        indexBuffer.writeUInt32BE(i, 0)

        // calculate I
        var data = Buffer.concat([serQP, indexBuffer])
        var I = crypto.createHmac('sha512', master.chainCode).update(data).digest()
        var IL = I.slice(0, 32)
        var pIL = bigi.fromBuffer(IL)

        // See hdnode.js:273 to understand
        d2 = d1.subtract(pIL).mod(curve.n)

        var Qp = new bitcoin.ECPair(d2).Q
        if (Qp.equals(QP)) break
      }

      var node = new bitcoin.HDNode(new bitcoin.ECPair(d2), master.chainCode, master.network)
      node.depth = master.depth
      node.index = master.index
      node.masterFingerprint = master.masterFingerprint
      return node
    }

    var seed = crypto.randomBytes(32)
    var master = bitcoin.HDNode.fromSeedBuffer(seed)
    var child = master.derive(6) // m/6

    // now for the recovery
    var neuteredMaster = master.neutered()
    var recovered = recoverParent(neuteredMaster, child)
    assert.strictEqual(recovered.toBase58(), master.toBase58())
  })

  it('can recover a private key from duplicate R values', function (done) {
    var inputs = [
      {
        txId: 'f4c16475f2a6e9c602e4a287f9db3040e319eb9ece74761a4b84bc820fbeef50',
        vout: 0
      },
      {
        txId: 'f4c16475f2a6e9c602e4a287f9db3040e319eb9ece74761a4b84bc820fbeef50',
        vout: 1
      }
    ]

    var txIds = inputs.map(function (x) { return x.txId })

    // first retrieve the relevant transactions
    blockchain.transactions.get(txIds, function (err, results) {
      assert.ifError(err)

      var transactions = {}
      results.forEach(function (tx) {
        transactions[tx.txId] = bitcoin.Transaction.fromHex(tx.txHex)
      })

      var tasks = []

      // now we need to collect/transform a bit of data from the selected inputs
      inputs.forEach(function (input) {
        var transaction = transactions[input.txId]
        var script = transaction.ins[input.vout].script
        assert(bitcoin.scripts.isPubKeyHashInput(script), 'Expected pubKeyHash script')

        var prevOutTxId = bitcoin.bufferutils.reverse(transaction.ins[input.vout].hash).toString('hex')
        var prevVout = transaction.ins[input.vout].index

        tasks.push(function (callback) {
          blockchain.transactions.get(prevOutTxId, function (err, result) {
            if (err) return callback(err)

            var prevOut = bitcoin.Transaction.fromHex(result.txHex)
            var prevOutScript = prevOut.outs[prevVout].script

            var scriptSignature = bitcoin.ECSignature.parseScriptSignature(script.chunks[0])
            var publicKey = bitcoin.ECPair.fromPublicKeyBuffer(script.chunks[1])

            var m = transaction.hashForSignature(input.vout, prevOutScript, scriptSignature.hashType)
            assert(publicKey.verify(m, scriptSignature.signature), 'Invalid m')

            // store the required information
            input.signature = scriptSignature.signature
            input.z = bigi.fromBuffer(m)

            return callback()
          })
        })
      })

      // finally, run the tasks, then on to the math
      async.parallel(tasks, function (err) {
        if (err) throw err

        var n = bitcoin.ECPair.curve.n

        for (var i = 0; i < inputs.length; ++i) {
          for (var j = i + 1; j < inputs.length; ++j) {
            var inputA = inputs[i]
            var inputB = inputs[j]

            // enforce matching r values
            assert.strictEqual(inputA.signature.r.toString(), inputB.signature.r.toString())
            var r = inputA.signature.r
            var rInv = r.modInverse(n)

            var s1 = inputA.signature.s
            var s2 = inputB.signature.s
            var z1 = inputA.z
            var z2 = inputB.z

            var zz = z1.subtract(z2).mod(n)
            var ss = s1.subtract(s2).mod(n)

            // k = (z1 - z2) / (s1 - s2)
            // d1 = (s1 * k - z1) / r
            // d2 = (s2 * k - z2) / r
            var k = zz.multiply(ss.modInverse(n)).mod(n)
            var d1 = ((s1.multiply(k).mod(n)).subtract(z1).mod(n)).multiply(rInv).mod(n)
            var d2 = ((s2.multiply(k).mod(n)).subtract(z2).mod(n)).multiply(rInv).mod(n)

            // enforce matching private keys
            assert.strictEqual(d1.toString(), d2.toString())
          }
        }

        done()
      })
    })
  })
})
<|endoftext|>