<commit_before>/**
 * Copyright 2020 The Google Earth Engine Community Authors
 *
 * 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 Earth Engine Developer's Guide examples
 *   from 'Import and Export data' section
 */

// [START earthengine__import_export01__export_image]
// Load a landsat image and select three bands.
var landsat = ee.Image('LANDSAT/LC08/C01/T1_TOA/LC08_123032_20140515')
  .select(['B4', 'B3', 'B2']);

// Create a geometry representing an export region.
var geometry = ee.Geometry.Rectangle([116.2621, 39.8412, 116.4849, 40.01236]);

// Export the image, specifying scale and region.
Export.image.toDrive({
  image: landsat,
  description: 'imageToDriveExample',
  scale: 30,
  region: geometry
});
// [END earthengine__import_export01__export_image]

// [START earthengine__import_export01__export_cogeo]
// Export a cloud-optimized GeoTIFF.
Export.image.toDrive({
  image: landsat,
  description: 'imageToCOGeoTiffExample',
  scale: 30,
  region: geometry,
  fileFormat: 'GeoTIFF',
  formatOptions: {
    cloudOptimized: true
  }
});
// [END earthengine__import_export01__export_cogeo]

// [START earthengine__import_export01__image_to_cloud]
// Export the image to Cloud Storage.
Export.image.toCloudStorage({
  image: landsat,
  description: 'imageToCloudExample',
  bucket: 'your-bucket-name',
  fileNamePrefix: 'exampleExport',
  scale: 30,
  region: geometry
});
// [END earthengine__import_export01__image_to_cloud]

// [START earthengine__import_export01__image_to_asset]
// Get band 4 from the Landsat image, copy it.
var band4 = landsat.select('B4').rename('b4_mean')
  .addBands(landsat.select('B4').rename('b4_sample'))
  .addBands(landsat.select('B4').rename('b4_max'));

// Export the image to an Earth Engine asset.
Export.image.toAsset({
  image: band4,
  description: 'imageToAssetExample',
  assetId: 'exampleExport',
  scale: 30,
  region: geometry,
  pyramidingPolicy: {
    'b4_mean': 'mean',
    'b4_sample': 'sample',
    'b4_max': 'max'
  }
});
// [END earthengine__import_export01__image_to_asset]

Map.addLayer(landsat, {bands: ['B4', 'B3', 'B2'], max: 0.4, gamma: 1.2});

// [START earthengine__import_export01__export_vectors]
// Make a collection of points.
var features = ee.FeatureCollection([
  ee.Feature(ee.Geometry.Point(30.41, 59.933), {name: 'Voronoi'}),
  ee.Feature(ee.Geometry.Point(-73.96, 40.781), {name: 'Thiessen'}),
  ee.Feature(ee.Geometry.Point(6.4806, 50.8012), {name: 'Dirichlet'})
]);

// Export the FeatureCollection to a KML file.
Export.table.toDrive({
  collection: features,
  description:'vectorsToDriveExample',
  fileFormat: 'KML'
});
// [END earthengine__import_export01__export_vectors]

// [START earthengine__import_export01__vectors_to_cloud]
// Export a KML file to Cloud Storage.
Export.table.toCloudStorage({
  collection: features,
  description:'vectorsToCloudStorageExample',
  bucket: 'your-bucket-name',
  fileNamePrefix: 'exampleTableExport',
  fileFormat: 'KML'
});
// [END earthengine__import_export01__vectors_to_cloud]

// [START earthengine__import_export01__export_table_asset]
// Export an ee.FeatureCollection as an Earth Engine asset.
Export.table.toAsset({
  collection: features,
  description:'exportToTableAssetExample',
  assetId: 'exampleAssetId',
});
// [END earthengine__import_export01__export_table_asset]

// [START earthengine__import_export01__export_table]
// Load a Landsat TOA image.
var image = ee.Image('LANDSAT/LC08/T1_TOA/LC08_044034_20140318');

// Create an arbitrary rectangle.
var region = ee.Geometry.Rectangle(-122.2806, 37.1209, -122.0554, 37.2413);

// Get a dictionary of means in the region.
var means = image.reduceRegion({
  reducer: ee.Reducer.mean(),
  geometry: region,
  scale: 30
});

// Make a feature without geometry and set the properties to the dictionary of means.
var feature = ee.Feature(null, means);

// Wrap the Feature in a FeatureCollection for export.
var featureCollection = ee.FeatureCollection([feature]);

// Export the FeatureCollection.
Export.table.toDrive({
  collection: featureCollection,
  description: 'exportTableExample',
  fileFormat: 'CSV'
});
// [END earthengine__import_export01__export_table]

// [START earthengine__import_export01__export_map]
// Load the global Accessibility to Cities image.
var accessibility = ee.Image('Oxford/MAP/accessibility_to_cities_2015_v1_0');

// Color palette for visualizing accessibility data.
var accessibilityPalette = ['f2fef8', 'defce1', 'c9f3bc', 'cbeca7', 'd6e793',
  'e2d87b', 'd4a561', 'c46c49', 'ab3a38', '922f4b', '7d285d', '672069',
  '3a1453', '1b0c3c', '050526', '00030f', '000000'];

// Apply the color palette to the log of travel time.
var accessibilityVis = {min: 0, max: 10, palette: accessibilityPalette};
var logAccessibility =
    accessibility.where(accessibility.gt(0), accessibility.log());
var accessibilityRgb = logAccessibility.visualize(accessibilityVis);

// Composite onto a solid-color background to fill in the oceans.
var background = ee.Image(0).visualize({palette: ['11101e']});
var accessibilityBlended = background.blend(accessibilityRgb).updateMask(1);

// Check the visualization.
Map.addLayer(accessibilityBlended, {}, 'accessibilityBlended');

// Define an export region.
var exportRegion = ee.Geometry.Rectangle([34, -3, 40, 1]);
Map.centerObject(exportRegion);
Map.addLayer(exportRegion, {}, 'exportRegion');

// Export the visualization image as map tiles.
Export.map.toCloudStorage({
  // All tiles that intersect the region get exported in their entirety.
  // Clip the image to prevent low resolution tiles from appearing outside
  // of the region.
  image: accessibilityBlended.clip(exportRegion),
  description: 'mapToCloudExample',
  bucket: 'your-bucket-name',
  maxZoom: 13,
  region: exportRegion
});
// [END earthengine__import_export01__export_map]
<commit_msg>Internal change<commit_after>/**
 * Copyright 2020 The Google Earth Engine Community Authors
 *
 * 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 Earth Engine Developer's Guide examples
 *   from 'Import and Export data' section
 */

// [START earthengine__import_export01__export_setup]
// Load a landsat image and select three bands.
var landsat = ee.Image('LANDSAT/LC08/C01/T1_TOA/LC08_123032_20140515')
  .select(['B4', 'B3', 'B2']);

// Create a geometry representing an export region.
var geometry = ee.Geometry.Rectangle([116.2621, 39.8412, 116.4849, 40.01236]);
// [END earthengine__import_export01__export_setup]

// [START earthengine__import_export01__export_projection]
// Retrieve the projection information from a band of the original image.
// Call getInfo() on the projection to request a client-side object containing
// the crs and transform information needed for the client-side Export function.
var projection = landsat.select('B2').projection().getInfo();
// [END earthengine__import_export01__export_projection]

// [START earthengine__import_export01__export_image]
// Export the image, specifying the CRS, transform, and region.
Export.image.toDrive({
  image: landsat,
  description: 'imageToDriveExample_transform',
  crs: projection.crs,
  crsTransform: projection.transform,
  region: geometry
});
// [END earthengine__import_export01__export_image]

// [START earthengine__import_export01__export_cogeo]
// Export a cloud-optimized GeoTIFF.
Export.image.toDrive({
  image: landsat,
  description: 'imageToCOGeoTiffExample',
  crs: projection.crs,
  crsTransform: projection.transform,
  region: geometry,
  fileFormat: 'GeoTIFF',
  formatOptions: {
    cloudOptimized: true
  }
});
// [END earthengine__import_export01__export_cogeo]

// [START earthengine__import_export01__image_to_cloud]
// Export the image to Cloud Storage.
Export.image.toCloudStorage({
  image: landsat,
  description: 'imageToCloudExample',
  bucket: 'your-bucket-name',
  fileNamePrefix: 'exampleExport',
  crs: projection.crs,
  crsTransform: projection.transform,
  region: geometry
});
// [END earthengine__import_export01__image_to_cloud]

// [START earthengine__import_export01__image_to_asset]
// Get band 4 from the Landsat image, copy it.
var band4 = landsat.select('B4').rename('b4_mean')
  .addBands(landsat.select('B4').rename('b4_sample'))
  .addBands(landsat.select('B4').rename('b4_max'));

// Export the image to an Earth Engine asset.
Export.image.toAsset({
  image: band4,
  description: 'imageToAssetExample',
  assetId: 'exampleExport',
  crs: projection.crs,
  crsTransform: projection.transform,
  region: geometry,
  pyramidingPolicy: {
    'b4_mean': 'mean',
    'b4_sample': 'sample',
    'b4_max': 'max'
  }
});
// [END earthengine__import_export01__image_to_asset]

Map.addLayer(landsat, {bands: ['B4', 'B3', 'B2'], max: 0.4, gamma: 1.2});

// [START earthengine__import_export01__export_vectors]
// Make a collection of points.
var features = ee.FeatureCollection([
  ee.Feature(ee.Geometry.Point(30.41, 59.933), {name: 'Voronoi'}),
  ee.Feature(ee.Geometry.Point(-73.96, 40.781), {name: 'Thiessen'}),
  ee.Feature(ee.Geometry.Point(6.4806, 50.8012), {name: 'Dirichlet'})
]);

// Export the FeatureCollection to a KML file.
Export.table.toDrive({
  collection: features,
  description:'vectorsToDriveExample',
  fileFormat: 'KML'
});
// [END earthengine__import_export01__export_vectors]

// [START earthengine__import_export01__vectors_to_cloud]
// Export a KML file to Cloud Storage.
Export.table.toCloudStorage({
  collection: features,
  description:'vectorsToCloudStorageExample',
  bucket: 'your-bucket-name',
  fileNamePrefix: 'exampleTableExport',
  fileFormat: 'KML'
});
// [END earthengine__import_export01__vectors_to_cloud]

// [START earthengine__import_export01__export_table_asset]
// Export an ee.FeatureCollection as an Earth Engine asset.
Export.table.toAsset({
  collection: features,
  description:'exportToTableAssetExample',
  assetId: 'exampleAssetId',
});
// [END earthengine__import_export01__export_table_asset]

// [START earthengine__import_export01__export_table]
// Load a Landsat TOA image.
var image = ee.Image('LANDSAT/LC08/T1_TOA/LC08_044034_20140318');

// Create an arbitrary rectangle.
var region = ee.Geometry.Rectangle(-122.2806, 37.1209, -122.0554, 37.2413);

// Get a dictionary of means in the region.
var means = image.reduceRegion({
  reducer: ee.Reducer.mean(),
  geometry: region,
  crs: projection.crs,
  crsTransform: projection.transform,
});

// Make a feature without geometry and set the properties to the dictionary of means.
var feature = ee.Feature(null, means);

// Wrap the Feature in a FeatureCollection for export.
var featureCollection = ee.FeatureCollection([feature]);

// Export the FeatureCollection.
Export.table.toDrive({
  collection: featureCollection,
  description: 'exportTableExample',
  fileFormat: 'CSV'
});
// [END earthengine__import_export01__export_table]

// [START earthengine__import_export01__export_map]
// Load the global Accessibility to Cities image.
var accessibility = ee.Image('Oxford/MAP/accessibility_to_cities_2015_v1_0');

// Color palette for visualizing accessibility data.
var accessibilityPalette = ['f2fef8', 'defce1', 'c9f3bc', 'cbeca7', 'd6e793',
  'e2d87b', 'd4a561', 'c46c49', 'ab3a38', '922f4b', '7d285d', '672069',
  '3a1453', '1b0c3c', '050526', '00030f', '000000'];

// Apply the color palette to the log of travel time.
var accessibilityVis = {min: 0, max: 10, palette: accessibilityPalette};
var logAccessibility =
    accessibility.where(accessibility.gt(0), accessibility.log());
var accessibilityRgb = logAccessibility.visualize(accessibilityVis);

// Composite onto a solid-color background to fill in the oceans.
var background = ee.Image(0).visualize({palette: ['11101e']});
var accessibilityBlended = background.blend(accessibilityRgb).updateMask(1);

// Check the visualization.
Map.addLayer(accessibilityBlended, {}, 'accessibilityBlended');

// Define an export region.
var exportRegion = ee.Geometry.Rectangle([34, -3, 40, 1]);
Map.centerObject(exportRegion);
Map.addLayer(exportRegion, {}, 'exportRegion');

// Export the visualization image as map tiles.
Export.map.toCloudStorage({
  // All tiles that intersect the region get exported in their entirety.
  // Clip the image to prevent low resolution tiles from appearing outside
  // of the region.
  image: accessibilityBlended.clip(exportRegion),
  description: 'mapToCloudExample',
  bucket: 'your-bucket-name',
  maxZoom: 13,
  region: exportRegion
});
// [END earthengine__import_export01__export_map]
<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc directive
 * @name timelinerApp.directive:projectListTimeline
 * @description
 * # projectListTimeline
 */
angular.module('timelinerApp')
  .directive('projectListTimeline', function ($window, $sanitize, $timeout, _, UsersService, ProjectsService) {
    var timelineOptions = {
      groupOrder: 'position',
      zoomMax: 1.578e+11, // 5 years
      zoomMin: 2.63e+9, // 1 month
      selectable: false
    };

    function determineFull(containerWidth, elementWidth, elementsCount, factor) {
      if ( factor < 2 ) {
        throw new Error('Factor is required to be greater or equal to two, instead a value of ' + factor.toString() + ' was provided!');
      }

      if ( elementsCount === 1 ) {
        return 1;
      } else if ( ( elementsCount * elementWidth ) <= containerWidth ) {
        return elementsCount;
      } else {
        var leftWidth = containerWidth - ( ( elementsCount + ( factor - 1 ) ) * ( elementWidth / factor ) );

        if ( leftWidth >= elementWidth / factor  * ( factor - 1 ) ) {
          var additionalFullElements = Math.floor( ( leftWidth / ( elementWidth / factor * ( factor - 1 ) ) ) );

          return additionalFullElements + 1;
        }
      }

      return 1;
    }

    function findAndApply(element) {
      var factor = 10;
      var elements = angular.element(element[0].querySelectorAll('.tl-timeline-project'));

      if ( elements && elements.length > 0 ) {
        _(elements).each(function(singleProjectElement) {
          var imageElements = angular.element(singleProjectElement.querySelectorAll('img.tl-timeline-participant'));
          if ( imageElements && imageElements.length > 1 ) {
            var containerWidth = singleProjectElement.clientWidth;
            //var imageElementWidth = imageElements[0].clientWidth;
            // TODO It does not count for margins
            var imageElementWidth = imageElements[0].offsetWidth;
            // This accounts for contained nested element margins
            var fullCount = determineFull(containerWidth - 10, imageElementWidth + 2, imageElements.length, factor);
            _(imageElements).each(function(imageElement, index) {
              imageElement.style.position = 'relative';
              imageElement.style.zIndex = imageElements.length - index;
              if ( index >= fullCount ) {
                imageElement.style.left = '-' + ( imageElementWidth * ( index + 1 - fullCount ) / factor * ( factor - 1 ) ) + 'px';
              } else {
                imageElement.style.left = '0px';
              }
            });
          }
        });
      }
    }

    function buildItemContent(project) {
      return '
' +
        '
' +
        _(project.participants).map(function(participant) {
          return '';
        }).join('') +
        '
' +
      '
';
    }

    return {
      restrict: 'E',
      scope: {
        data: '='
      },
      link: function postLink(scope, element) {
        var maxZindex = 2;
        var timeline = null;

        // TODO Add handling for updates
        // Full redraw on update does not seems to be reasonable
        scope.$watchCollection('data', function() {
          if ( scope.data === null ) {
            return;
          }

          if ( timeline !== null ) {
            timeline.destroy();
          }

          timeline = new $window.vis.Timeline(element[0]);
          timeline.setOptions(timelineOptions);

          var groups = new $window.vis.DataSet([]);
          var items = new $window.vis.DataSet([]);

          angular.forEach(scope.data, function(project) {
            if ( !ProjectsService.isShownOnTimeline(project) ) {
              return;
            }

            if ( maxZindex < project.participants.length ) {
              maxZindex = project.participants.length;
            }

            groups.add({
              className: 'tl-timeline-project-group',
              content: project.title, // XXX Need to generate some
              id: project._id,
              title: project.title
            });
            items.add({
              className: 'tl-timeline-project',
              content: buildItemContent(project),
              end: project.end ? project.end : timeline.getWindow().end,
              group: project._id,
              id: project._id,
              start: project.start,
              title: project.title,
              type: 'range',
              editable: false,
              hasEnd: project.end ? true : false
            });
          });

          timeline.setData({
            groups: groups,
            items: items
          });

          var findAndApplyTimeout;

          timeline.on('rangechanged', function(data) {
            timeline.once('changed', function() {
              if ( findAndApplyTimeout ) {
                $timeout.cancel(findAndApplyTimeout);
                findAndApplyTimeout = null;
              }
              findAndApplyTimeout = $timeout(function() {
                findAndApply(element);
              }, 50);
            });

            angular.element(element[0].querySelector('.vis-current-time'))[0].style.zIndex = maxZindex + 1;

            var ids = items.getIds({
              filter: function(item) {
                return item.hasEnd === false;
              }
            });
            if ( ids.length > 0 ) {
              angular.forEach(ids, function(id) {
                items.update({ id: id, end: data.end });
              });
              timeline.redraw();
            }
          });
        });

        element.on('$destroy', function() {
          if ( timeline !== null ) {
            timeline.destroy();
          }
        });
      }
    };
  });
<commit_msg>Fixes learning-layers/timeliner#85, better width calculation.<commit_after>'use strict';

/**
 * @ngdoc directive
 * @name timelinerApp.directive:projectListTimeline
 * @description
 * # projectListTimeline
 */
angular.module('timelinerApp')
  .directive('projectListTimeline', function ($window, $sanitize, $timeout, _, UsersService, ProjectsService) {
    var timelineOptions = {
      groupOrder: 'position',
      zoomMax: 1.578e+11, // 5 years
      zoomMin: 2.63e+9, // 1 month
      selectable: false
    };

    function getContainerWidth(containerElement, timeline) {
      if ( containerElement.offsetLeft < 0 ) {
        if ( containerElement.clientWidth + containerElement.offsetLeft > 0 ) {
          return containerElement.clientWidth + containerElement.offsetLeft;
        }
        return 0;
      } else {
        var centerContainerWidth = timeline.dom.centerContainer.clientWidth;
        if ( centerContainerWidth - containerElement.offsetLeft < containerElement.clientWidth ) {
          if ( centerContainerWidth - containerElement.offsetLeft > 0 ) {
            return centerContainerWidth - containerElement.offsetLeft;
          }
          return 0;
        }
        return containerElement.clientWidth;
      }
    }

    function determineFull(containerWidth, elementWidth, elementsCount, factor) {
      if ( factor < 2 ) {
        throw new Error('Factor is required to be greater or equal to two, instead a value of ' + factor.toString() + ' was provided!');
      }

      if ( elementsCount === 1 ) {
        return 1;
      } else if ( ( elementsCount * elementWidth ) <= containerWidth ) {
        return elementsCount;
      } else {
        var leftWidth = containerWidth - ( ( elementsCount + ( factor - 1 ) ) * ( elementWidth / factor ) );

        if ( leftWidth >= elementWidth / factor  * ( factor - 1 ) ) {
          var additionalFullElements = Math.floor( ( leftWidth / ( elementWidth / factor * ( factor - 1 ) ) ) );

          return additionalFullElements + 1;
        }
      }

      return 1;
    }

    function findAndApply(element, timeline) {
      var factor = 10;
      var elements = angular.element(element[0].querySelectorAll('.tl-timeline-project'));

      if ( elements && elements.length > 0 ) {
        _(elements).each(function(singleProjectElement) {
          var imageElements = angular.element(singleProjectElement.querySelectorAll('img.tl-timeline-participant'));
          if ( imageElements && imageElements.length > 1 ) {
            var containerWidth = getContainerWidth(singleProjectElement, timeline);
            var imageElementWidth = imageElements[0].offsetWidth;
            // This accounts for contained nested element margins
            var fullCount = determineFull(containerWidth - 10, imageElementWidth + 2, imageElements.length, factor);
            _(imageElements).each(function(imageElement, index) {
              imageElement.style.position = 'relative';
              imageElement.style.zIndex = imageElements.length - index;
              if ( index >= fullCount ) {
                imageElement.style.left = '-' + ( imageElementWidth * ( index + 1 - fullCount ) / factor * ( factor - 1 ) ) + 'px';
              } else {
                imageElement.style.left = '0px';
              }
            });
          }
        });
      }
    }

    function buildItemContent(project) {
      return '
' +
        '
' +
        _(project.participants).map(function(participant) {
          return '';
        }).join('') +
        '
' +
      '
';
    }

    return {
      restrict: 'E',
      scope: {
        data: '='
      },
      link: function postLink(scope, element) {
        var maxZindex = 2;
        var timeline = null;

        // TODO Add handling for updates
        // Full redraw on update does not seems to be reasonable
        scope.$watchCollection('data', function() {
          if ( scope.data === null ) {
            return;
          }

          if ( timeline !== null ) {
            timeline.destroy();
          }

          timeline = new $window.vis.Timeline(element[0]);
          timeline.setOptions(timelineOptions);

          var groups = new $window.vis.DataSet([]);
          var items = new $window.vis.DataSet([]);

          angular.forEach(scope.data, function(project) {
            if ( !ProjectsService.isShownOnTimeline(project) ) {
              return;
            }

            if ( maxZindex < project.participants.length ) {
              maxZindex = project.participants.length;
            }

            groups.add({
              className: 'tl-timeline-project-group',
              content: project.title, // XXX Need to generate some
              id: project._id,
              title: project.title
            });
            items.add({
              className: 'tl-timeline-project',
              content: buildItemContent(project),
              end: project.end ? project.end : timeline.getWindow().end,
              group: project._id,
              id: project._id,
              start: project.start,
              title: project.title,
              type: 'range',
              editable: false,
              hasEnd: project.end ? true : false
            });
          });

          timeline.setData({
            groups: groups,
            items: items
          });

          var findAndApplyTimeout;

          timeline.on('rangechanged', function(data) {
            timeline.once('changed', function() {
              if ( findAndApplyTimeout ) {
                $timeout.cancel(findAndApplyTimeout);
                findAndApplyTimeout = null;
              }
              findAndApplyTimeout = $timeout(function() {
                findAndApply(element, timeline);
              }, 50);
            });

            angular.element(element[0].querySelector('.vis-current-time'))[0].style.zIndex = maxZindex + 1;

            var ids = items.getIds({
              filter: function(item) {
                return item.hasEnd === false;
              }
            });
            if ( ids.length > 0 ) {
              angular.forEach(ids, function(id) {
                items.update({ id: id, end: data.end });
              });
              timeline.redraw();
            }
          });
        });

        element.on('$destroy', function() {
          if ( timeline !== null ) {
            timeline.destroy();
          }
        });
      }
    };
  });
<|endoftext|>


<commit_before>define([ "HeroCard", "Trait" ], function(HeroCard, Trait)
{
    "use strict";
    QUnit.module("HeroCard");

    QUnit.test("HeroCard properties Aragorn (Core)", function(assert)
    {
        var cardKey = HeroCard.ARAGORN_CORE;
        var properties = HeroCard.properties[cardKey];
        assert.equal(properties.name, "Aragorn");
        assert.equal(properties.value, "aragornCore");
    });

    QUnit.test("keys and values", function(assert)
    {
        // Setup.

        // Run.
        var result = HeroCard.values();
        var ownPropertyNames = Object.getOwnPropertyNames(HeroCard);

        // Verify.
        ownPropertyNames.forEach(function(key)
        {
            var key2 = HeroCard[key];

            if (key !== "properties" && typeof key2 === "string")
            {
                assert.ok(HeroCard.properties[key2], "Missing value for key = " + key);
            }
        });

        result.forEach(function(value)
        {
            var p = ownPropertyNames.filter(function(key)
            {
                return HeroCard[key] === value;
            });

            assert.equal(p.length, 1, "Missing key for value = " + value);
        });
    });

    QUnit.test("traits", function(assert)
    {
        HeroCard.values().forEach(function(cardKey)
        {
            var card = HeroCard.properties[cardKey];
            card.traitKeys.forEach(function(traitKey)
            {
                assert.ok(traitKey, "Missing traitKey for cardKey = " + cardKey);
            });
        });
    });

    QUnit.test("HeroCard.values()", function(assert)
    {
        // Run.
        var result = HeroCard.values();

        // Verify.
        assert.ok(result);
        var length = 71;
        assert.equal(result.length, length);
        assert.equal(result[0], HeroCard.AMARTHIUL);
        assert.equal(result[length - 1], HeroCard.TREEBEARD);
    });
});
<commit_msg>Added player cards from The Road Darkens saga expansion.<commit_after><|endoftext|>


<commit_before>import dns from 'native-dns'
import fetch from 'node-fetch'
import fs from 'fs'
import ip from 'ip'
//import readline from 'readline'

/*function parseHostsRecords ( url, cb ) {
  fetch( url )
    .then( res => {})
    .then( body => {
      if ( body ) {
        body
          .split('\n')
          .forEach(
            ( line ) => {
              if ( !line.startsWith( '#' ) ) {
                var host = line.split( /\s+/ ),
                    domain = ''

                if ( host.length < 2 )
                  domain = host[0]
                else
                  domain = host[1]

                global.zeroDns.dns.cache
                .set( domain, { hit: 0 } )
              }
            }
          )
          cb()
      }
    })
}
*/

function proxyDnsRequest ( ipType, question, response ) {
  const resolver = global.zeroDns.dns.resolver[ ipType ][ Math.round( Math.random() ) ]

  return new Promise(
    ( resolve, reject ) => {
      dns
        .Request({
          question: question,
          server: {
            address: resolver,
            'port': 53,
            'type': 'udp'
          },
          timeout: 1000
        })
        .on( 'timeout', () => reject( `>> DNS: Recursive question '${question.name}' went in timeout with resolver '${resolver}:53'` ) )
        .on( 'message',
          (err, msg) => {
            msg.answer
              .forEach( answer => response.answer.push( answer ) )
          }
        )
        .on( 'end', resolve )
        .send()
    }
  )
}

function answerDnsRequest ( req, res ) {
  let promises = []

  if ( !( req.address.address in global.zeroDns.http.stats.clients ) ) {
    global.zeroDns.http.stats.clients[ req.address.address ] = {
      'ads': 0,
      'generic': 0
    }
  }

  req.question.forEach( function ( question ) {
    var adDomain = global.zeroDns.dns.cache.get( question.name )

    if ( adDomain ) {
      res
      .answer
      .push(
        dns.A({
          name: question.name,
          address: ip.address( 'private', 'ipv4' ),
          ttl: 600
        })
      )

      res
      .answer
      .push(
        dns.AAAA({
          name: question.name,
          address: ip.address( 'private', 'ipv6' ),
          ttl: 600
        })
      )

      global.zeroDns.http.stats.clients[ req.address.address ].ads++

      global.zeroDns.dns.cache.set( question.name, { hit: ++adDomain.hit } )
    } else {
      global.zeroDns.http.stats.clients[ req.address.address ].generic++

      promises.push(
        proxyDnsRequest( req.address.family.toLowerCase(), question, res )
      )
    }
  })

  Promise
    .all( promises )
    .then( () => res.send() )
    .catch( err => console.log( err ) )
}

export default () => {
  var udp4Server = dns.createServer( { dgram_type: { type: 'udp4', reuseAddr: true } } ),
      udp6Server = dns.createServer( { dgram_type: { type: 'udp6', reuseAddr: true } } ),
      tcpServer  = dns.createTCPServer()
      /*urls = [],
      lineReader = readline.createInterface({
        input: fs.createReadStream('ads.list')
      })*/

  return Promise
    .resolve()
    .then(
      () => {
        return Promise.resolve()
        /*return new Promise (
          ( resolve, reject ) => {
            lineReader
              .on( 'line', function (line) {
                if ( line.startsWith( 'http' ) ) urls.push( line )
              })
              .on( 'close', function (){
                async.map( urls, parseHostsRecords, function ( err ) {
                  if ( err )
                    reject( err )
                  else
                    resolve()
                })
              })
          }
        )*/
      }
    )
    .then(
      () => {
        return new Promise (
          ( resolve, reject ) => {
            tcpServer
              .on( 'socketError', ( e ) => reject( `[DNS] TCP: ${e.message}` ) )
              .on( 'request', answerDnsRequest )
              .on( 'listening', () => {
                console.log( `>> DNS: Listening on [::]:53/tcp` )
                resolve()
              })
              .serve( global.zeroDns.dns.port )
          }
        )
      }
    )
    .then(
      () => {
        return new Promise (
          ( resolve, reject ) => {
            udp4Server
              .on( 'socketError', ( e ) => reject( `[DNS] UDP4: ${e.message}` ) )
              .on( 'request', answerDnsRequest )
              .on( 'listening', () => {
                console.log( `>> DNS: Listening on 0.0.0.0:53/udp` )
                resolve()
              })
              .serve( global.zeroDns.dns.port )
          }
        )
      }
    )
    .then(
      () => {
        return new Promise (
          ( resolve, reject ) => {
            udp6Server
              .on( 'socketError', ( e ) => reject( `[DNS] UDP6: ${e.message}` ) )
              .on( 'request', answerDnsRequest )
              .on( 'listening', () => {
                console.log( `>> DNS: Listening on [::]:53/udp` )
                resolve()
              })
              .serve( global.zeroDns.dns.port )
          }
        )
      }
    )
}<commit_msg>Make it more ES6 compliant<commit_after>import dns from 'native-dns'
import fetch from 'node-fetch'
import fs from 'fs'
import ip from 'ip'
//import readline from 'readline'

/*function parseHostsRecords ( url, cb ) {
  fetch( url )
    .then( res => {})
    .then( body => {
      if ( body ) {
        body
          .split('\n')
          .forEach(
            ( line ) => {
              if ( !line.startsWith( '#' ) ) {
                var host = line.split( /\s+/ ),
                    domain = ''

                if ( host.length < 2 )
                  domain = host[0]
                else
                  domain = host[1]

                global.zeroDns.dns.cache
                .set( domain, { hit: 0 } )
              }
            }
          )
          cb()
      }
    })
}
*/

function proxyDnsRequest ( ipType, question, response ) {
  const resolver = global.zeroDns.dns.resolver[ ipType ][ Math.round( Math.random() ) ]

  return new Promise(
    ( resolve, reject ) => {
      dns
        .Request({
          question: question,
          server: {
            address: resolver,
            'port': 53,
            'type': 'udp'
          },
          timeout: 1000
        })
        .on( 'timeout', () => reject( `>> DNS: Recursive question '${question.name}' went in timeout with resolver '${resolver}:53'` ) )
        .on( 'message',
          (err, msg) => {
            msg.answer
              .forEach( answer => response.answer.push( answer ) )
          }
        )
        .on( 'end', resolve )
        .send()
    }
  )
}

function answerDnsRequest ( req, res ) {
  let promises = []

  if ( !( req.address.address in global.zeroDns.http.stats.clients ) ) {
    global.zeroDns.http.stats.clients[ req.address.address ] = {
      'ads': 0,
      'generic': 0
    }
  }

  req.question.forEach( function ( question ) {
    const adDomain = global.zeroDns.dns.cache.get( question.name )

    if ( adDomain ) {
      res
      .answer
      .push(
        dns.A({
          name: question.name,
          address: ip.address( 'private', 'ipv4' ),
          ttl: 600
        })
      )

      res
      .answer
      .push(
        dns.AAAA({
          name: question.name,
          address: ip.address( 'private', 'ipv6' ),
          ttl: 600
        })
      )

      global.zeroDns.http.stats.clients[ req.address.address ].ads++

      global.zeroDns.dns.cache.set( question.name, { hit: ++adDomain.hit } )
    } else {
      global.zeroDns.http.stats.clients[ req.address.address ].generic++

      promises.push(
        proxyDnsRequest( req.address.family.toLowerCase(), question, res )
      )
    }
  })

  Promise
    .all( promises )
    .then( () => res.send() )
    .catch( err => console.log( err ) )
}

export default () => {
  const udp4Server = dns.createServer( { dgram_type: { type: 'udp4', reuseAddr: true } } ),
        udp6Server = dns.createServer( { dgram_type: { type: 'udp6', reuseAddr: true } } ),
        tcpServer  = dns.createTCPServer()
      /*urls = [],
      lineReader = readline.createInterface({
        input: fs.createReadStream('ads.list')
      })*/

  return Promise
    .resolve()
    .then(
      () => {
        return Promise.resolve()
        /*return new Promise (
          ( resolve, reject ) => {
            lineReader
              .on( 'line', function (line) {
                if ( line.startsWith( 'http' ) ) urls.push( line )
              })
              .on( 'close', function (){
                async.map( urls, parseHostsRecords, function ( err ) {
                  if ( err )
                    reject( err )
                  else
                    resolve()
                })
              })
          }
        )*/
      }
    )
    .then(
      () => {
        return new Promise (
          ( resolve, reject ) => {
            tcpServer
              .on( 'socketError', ( e ) => reject( `[DNS] TCP: ${e.message}` ) )
              .on( 'request', answerDnsRequest )
              .on( 'listening', () => {
                console.log( `>> DNS: Listening on [::]:53/tcp` )
                resolve()
              })
              .serve( global.zeroDns.dns.port )
          }
        )
      }
    )
    .then(
      () => {
        return new Promise (
          ( resolve, reject ) => {
            udp4Server
              .on( 'socketError', ( e ) => reject( `[DNS] UDP4: ${e.message}` ) )
              .on( 'request', answerDnsRequest )
              .on( 'listening', () => {
                console.log( `>> DNS: Listening on 0.0.0.0:53/udp` )
                resolve()
              })
              .serve( global.zeroDns.dns.port )
          }
        )
      }
    )
    .then(
      () => {
        return new Promise (
          ( resolve, reject ) => {
            udp6Server
              .on( 'socketError', ( e ) => reject( `[DNS] UDP6: ${e.message}` ) )
              .on( 'request', answerDnsRequest )
              .on( 'listening', () => {
                console.log( `>> DNS: Listening on [::]:53/udp` )
                resolve()
              })
              .serve( global.zeroDns.dns.port )
          }
        )
      }
    )
}<|endoftext|>


<commit_before>/*
 * Copyright (c) Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License.
 */

const express = require("express");
const msal = require('@azure/msal-node');

/**
 * Command line arguments can be used to configure:
 * - The port the application runs on
 * - The cache file location
 * - The authentication scenario/configuration file name
 */
const argv = require("../cliArgs");

const SERVER_PORT = argv.p || 3000;
const cacheLocation = argv.c || "./data/cache.json";
const cachePlugin = require('../cachePlugin')(cacheLocation);

/**
 * The scenario string is the name of a .json file which contains the MSAL client configuration
 * For an example of what a configuration file should look like, check out the customConfig.json file in the
 * /config directory.
 *
 * You can create your own configuration file and replace the path inside the "config" require statement below
 * with the path to your custom configuraiton.
 */
const scenario = argv.s || "customConfig";
const config = require(`./config/${scenario}.json`);

// Sample Application Code
const getTokenAuthCode = function (scenarioConfig, clientApplication, port) {
    // Set the port that the express server will listen on
    const serverPort = port || SERVER_PORT;
    // Create Express App and Routes
    const app = express();

    const requestConfig = scenarioConfig.request;

    app.get("/", (req, res) => {
        const { authCodeUrlParameters } = requestConfig;

        if (req.query) {
            // Check for the state parameter
            if(req.query.state) authCodeUrlParameters.state = req.query.state;

            // Check for the prompt parameter
            if (req.query.prompt) authCodeUrlParameters.prompt = req.query.prompt;

            // Check for the loginHint parameter
            if (req.query.loginHint) authCodeUrlParameters.loginHint = req.query.loginHint;

            // Check for the domainHint parameter
            if (req.query.domainHint) authCodeUrlParameters.domainHint = req.query.domainHint;
        }

        /**
         * MSAL Usage
         * The code below demonstrates the correct usage pattern of the ClientApplicaiton.getAuthCodeUrl API.
         *
         * Authorization Code Grant: First Leg
         *
         * In this code block, the application uses MSAL to obtain an authorization code request URL. Once the URL is
         * returned by MSAL, the express application is redirected to said request URL, concluding the first leg of the
         * Authorization Code Grant flow.
         */
        clientApplication.getAuthCodeUrl(authCodeUrlParameters).then((authCodeUrl) => {
            res.redirect(authCodeUrl);
        }).catch((error) => console.log(JSON.stringify(error)));
    });

    app.get("/redirect", (req, res) => {
        const tokenRequest = { ...requestConfig.tokenRequest, code: req.query.code };
        /**
         * MSAL Usage
         * The code below demonstrates the correct usage pattern of the ClientApplicaiton.acquireTokenByCode API.
         *
         * Authorization Code Grant: Second Leg
         *
         * In this code block, the application uses MSAL to obtain an Access Token from the configured authentication service.
         * The response contains an `accessToken` property. Said property contains a string representing an encoded Json Web Token
         * which can be added to the `Authorization` header in a protected resource request to demonstrate authorization.
         */

        clientApplication.acquireTokenByCode(tokenRequest).then((response) => {
            console.log("Successfully acquired token using Authorization Code.");
            res.sendStatus(200);
        }).catch((error) => {
            console.log(error);
            res.status(500).send(error);
        });
    });

    return app.listen(serverPort, () => console.log(`Msal Node Auth Code Sample app listening on port ${serverPort}!`));
}

/**
 * The code below checks if the script is being executed manually or in automation.
 * If the script was executed manually, it will initialize a PublicClientApplication object
 * and execute the sample application.
 */
 if(argv.$0 === "index.js") {
    const loggerOptions = {
        loggerCallback(loglevel, message, containsPii) {
            console.log(message);
        },
            piiLoggingEnabled: false,
        logLevel: msal.LogLevel.Verbose,
    }

    // Build MSAL ClientApplication Configuration object
    const clientConfig = {
        auth: config.authOptions,
        cache: {
            cachePlugin
        },
        // Uncomment the code below to enable the MSAL logger
        /*
         *   system: {
         *    loggerOptions: loggerOptions
         *   }
         */
    };

    // Create an MSAL PublicClientApplication object
    const publicClientApplication = new msal.PublicClientApplication(clientConfig);

    // Execute sample application with the configured MSAL PublicClientApplication
    return getTokenAuthCode(config, publicClientApplication, null);
 }

// The application code is exported so it can be executed in automation environments
 module.exports = getTokenAuthCode;<commit_msg>Revert node sample change<commit_after>/*
 * Copyright (c) Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License.
 */

const express = require("express");
const msal = require('@azure/msal-node');

/**
 * Command line arguments can be used to configure:
 * - The port the application runs on
 * - The cache file location
 * - The authentication scenario/configuration file name
 */
const argv = require("../cliArgs");

const SERVER_PORT = argv.p || 3000;
const cacheLocation = argv.c || "./data/cache.json";
const cachePlugin = require('../cachePlugin')(cacheLocation);

/**
 * The scenario string is the name of a .json file which contains the MSAL client configuration
 * For an example of what a configuration file should look like, check out the customConfig.json file in the
 * /config directory.
 *
 * You can create your own configuration file and replace the path inside the "config" require statement below
 * with the path to your custom configuraiton.
 */
const scenario = argv.s || "customConfig";
const config = require(`./config/${scenario}.json`);

// Sample Application Code
const getTokenAuthCode = function (scenarioConfig, clientApplication, port) {
    // Set the port that the express server will listen on
    const serverPort = port || SERVER_PORT;
    // Create Express App and Routes
    const app = express();

    const requestConfig = scenarioConfig.request;

    app.get("/", (req, res) => {
        const { authCodeUrlParameters } = requestConfig;

        if (req.query) {
            // Check for the state parameter
            if(req.query.state) authCodeUrlParameters.state = req.query.state;

            // Check for the prompt parameter
            if (req.query.prompt) authCodeUrlParameters.prompt = req.query.prompt;

            // Check for the loginHint parameter
            if (req.query.loginHint) authCodeUrlParameters.loginHint = req.query.loginHint;

            // Check for the domainHint parameter
            if (req.query.domainHint) authCodeUrlParameters.domainHint = req.query.domainHint;
        }

        /**
         * MSAL Usage
         * The code below demonstrates the correct usage pattern of the ClientApplicaiton.getAuthCodeUrl API.
         *
         * Authorization Code Grant: First Leg
         *
         * In this code block, the application uses MSAL to obtain an authorization code request URL. Once the URL is
         * returned by MSAL, the express application is redirected to said request URL, concluding the first leg of the
         * Authorization Code Grant flow.
         */
        clientApplication.getAuthCodeUrl(authCodeUrlParameters).then((authCodeUrl) => {
            res.redirect(authCodeUrl);
        }).catch((error) => console.log(JSON.stringify(error)));
    });

    app.get("/redirect", (req, res) => {
        const tokenRequest = { ...requestConfig.tokenRequest, code: req.query.code };
        /**
         * MSAL Usage
         * The code below demonstrates the correct usage pattern of the ClientApplicaiton.acquireTokenByCode API.
         *
         * Authorization Code Grant: Second Leg
         *
         * In this code block, the application uses MSAL to obtain an Access Token from the configured authentication service.
         * The response contains an `accessToken` property. Said property contains a string representing an encoded Json Web Token
         * which can be added to the `Authorization` header in a protected resource request to demonstrate authorization.
         */

        clientApplication.acquireTokenByCode(tokenRequest).then((response) => {
            console.log("Successfully acquired token using Authorization Code.");
            res.sendStatus(200);
        }).catch((error) => {
            console.log(error);
            res.status(500).send(error);
        });
    });

    return app.listen(serverPort, () => console.log(`Msal Node Auth Code Sample app listening on port ${serverPort}!`));
}

/**
 * The code below checks if the script is being executed manually or in automation.
 * If the script was executed manually, it will initialize a PublicClientApplication object
 * and execute the sample application.
 */
 if(argv.$0 === "index.js") {
    const loggerOptions = {
        loggerCallback(loglevel, message, containsPii) {
            console.log(message);
        },
            piiLoggingEnabled: false,
        logLevel: msal.LogLevel.Verbose,
    }

    // Build MSAL ClientApplication Configuration object
    const clientConfig = {
        auth: config.authOptions,
        cache: {
            cachePlugin
        },
        // Uncomment the code below to enable the MSAL logger
        /*
         *   system: {
         *    loggerOptions: loggerOptions
         *   }
         */
    };

    // Create an MSAL PublicClientApplication object
    const publicClientApplication = new msal.PublicClientApplication(clientConfig);

    // Execute sample application with the configured MSAL PublicClientApplication
    return getTokenAuthCode(config, publicClientApplication, null);
 }

// The application code is exported so it can be executed in automation environments
 module.exports = getTokenAuthCode;<|endoftext|>


<commit_before>(function() {
  'use strict';
  var module = angular.module('fim.base');
  module.factory('GoodsDetailsProvider', function(nxt, $q, IndexedEntityProvider) {

    function GoodsDetailsProvider(api, $scope, paramSection) {
      this.init(api, $scope, paramSection);
      this.paramSection = paramSection;
    }
    angular.extend(GoodsDetailsProvider.prototype, IndexedEntityProvider.prototype, {

      uniqueKey: function(good) {
        return good.goods;
      },
      sortFunction: function(a, b) {
        return a.index - b.index;
      },

      getData: function() {
        var deferred = $q.defer();
        var args = {
          requestType: 'getDGSGood',
          goods: this.paramSection
        }
        this.api.engine.socket().callAPIFunction(args).then(deferred.resolve, deferred.reject);
        return deferred.promise;
      },

      dataIterator: function(data) {
        var goods = data;
        var index = this.entities.length > 0 ? this.entities[this.entities.length - 1].index : 0;
        return new Iterator([goods]);
      }
    });
    return GoodsDetailsProvider;
  });
})();<commit_msg>goods details provider edited<commit_after>(function() {
  'use strict';
  var module = angular.module('fim.base');
  module.factory('GoodsDetailsProvider', function(nxt, $q) {

    function GoodsDetailsProvider(api, $scope, paramSection) {
      this.paramSection = paramSection;
      this.api = api;
      this.$scope = $scope;
      this.isLoading = true;
      this.entities = [];
    }
    GoodsDetailsProvider.prototype = {
      reload: function() {
        var deferred = $q.defer();
        var self = this;
        this.$scope.$evalAsync(function() {
          self.isLoading = true;
          self.getData().then(deferred.resolve, deferred.reject);
        });
        return deferred.promise;
      },

      getData: function() {
        var deferred = $q.defer();
        var self = this;
        var args = {
          requestType: 'getDGSGood',
          goods: this.paramSection
        }
        this.api.engine.socket().callAPIFunction(args).then(function(data) {
            self.$scope.$evalAsync(function() {
              self.isLoading = false;
              var goodsDetails = data || [];
              self.entities.push(goodsDetails);
              deferred.resolve();
            });
          },
          function() {
            self.$scope.$evalAsync(function() {
              self.isLoading = false;
              deferred.reject();
            });
          }
        );
        return deferred.promise;
      }
    };
    return GoodsDetailsProvider;
  });
})();<|endoftext|>


<commit_before>/* global jsPDF, canvg */
/** @license
 * Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * ====================================================================
 */

/**
* jsPDF SVG plugin
*
* @name svg
* @module
*/
(function (jsPDFAPI) {
    'use strict'

    /**
    * Parses SVG XML and converts only some of the SVG elements into
    * PDF elements.
    *
    * Supports:
    * paths
    *
    * @name addSvg
    * @public
	* @function
    * @param {string} SVG-Data as Text
    * @param {number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
    * @param {number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
    * @param {number} width of SVG (in units declared at inception of PDF document)
    * @param {number} height of SVG (in units declared at inception of PDF document)
    * @returns {Object} jsPDF-instance
	*/
    jsPDFAPI.addSvg = function (svgtext, x, y, w, h) {
        // 'this' is _jsPDF object returned when jsPDF is inited (new jsPDF())

        if (x === undefined || y === undefined) {
            throw new Error("addSVG needs values for 'x' and 'y'");
        }

        function InjectCSS(cssbody, document) {
            var styletag = document.createElement('style');
            styletag.type = 'text/css';
            if (styletag.styleSheet) {
                // ie
                styletag.styleSheet.cssText = cssbody;
            } else {
                // others
                styletag.appendChild(document.createTextNode(cssbody));
            }
            document.getElementsByTagName("head")[0].appendChild(styletag);
        }

        function createWorkerNode(document) {

            var frameID = 'childframe' // Date.now().toString() + '_' + (Math.random() * 100).toString()
                , frame = document.createElement('iframe');

            InjectCSS(
                '.jsPDF_sillysvg_iframe {display:none;position:absolute;}'
                , document
            );

            frame.name = frameID;
            frame.setAttribute("width", 0);
            frame.setAttribute("height", 0);
            frame.setAttribute("frameborder", "0");
            frame.setAttribute("scrolling", "no");
            frame.setAttribute("seamless", "seamless");
            frame.setAttribute("class", "jsPDF_sillysvg_iframe");

            document.body.appendChild(frame);

            return frame;
        }

        function attachSVGToWorkerNode(svgtext, frame) {
            var framedoc = (frame.contentWindow || frame.contentDocument).document;
            framedoc.write(svgtext);
            framedoc.close();
            return framedoc.getElementsByTagName('svg')[0];
        }

        function convertPathToPDFLinesArgs(path) {
            'use strict'
            // we will use 'lines' method call. it needs:
            // - starting coordinate pair
            // - array of arrays of vector shifts (2-len for line, 6 len for bezier)
            // - scale array [horizontal, vertical] ratios
            // - style (stroke, fill, both)

            var x = parseFloat(path[1])
                , y = parseFloat(path[2])
                , vectors = []
                , position = 3
                , len = path.length;

            while (position < len) {
                if (path[position] === 'c') {
                    vectors.push([
                        parseFloat(path[position + 1])
                        , parseFloat(path[position + 2])
                        , parseFloat(path[position + 3])
                        , parseFloat(path[position + 4])
                        , parseFloat(path[position + 5])
                        , parseFloat(path[position + 6])
                    ]);
                    position += 7;
                } else if (path[position] === 'l') {
                    vectors.push([
                        parseFloat(path[position + 1])
                        , parseFloat(path[position + 2])
                    ]);
                    position += 3;
                } else {
                    position += 1;
                }
            }
            return [x, y, vectors];
        }

        var workernode = createWorkerNode(document)
            , svgnode = attachSVGToWorkerNode(svgtext, workernode)
            , scale = [1, 1]
            , svgw = parseFloat(svgnode.getAttribute('width'))
            , svgh = parseFloat(svgnode.getAttribute('height'));

        if (svgw && svgh) {
            // setting both w and h makes image stretch to size.
            // this may distort the image, but fits your demanded size
            if (w && h) {
                scale = [w / svgw, h / svgh];
            }
            // if only one is set, that value is set as max and SVG
            // is scaled proportionately.
            else if (w) {
                scale = [w / svgw, w / svgw];
            } else if (h) {
                scale = [h / svgh, h / svgh];
            }
        }

        var i, l, tmp
            , linesargs
            , items = svgnode.childNodes;
        for (i = 0, l = items.length; i < l; i++) {
            tmp = items[i];
            if (tmp.tagName && tmp.tagName.toUpperCase() === 'PATH') {
                linesargs = convertPathToPDFLinesArgs(tmp.getAttribute("d").split(' '));
                // path start x coordinate
                linesargs[0] = linesargs[0] * scale[0] + x; // where x is upper left X of image
                // path start y coordinate
                linesargs[1] = linesargs[1] * scale[1] + y; // where y is upper left Y of image
                // the rest of lines are vectors. these will adjust with scale value auto.
                this.lines.call(
                    this
                    , linesargs[2] // lines
                    , linesargs[0] // starting x
                    , linesargs[1] // starting y
                    , scale
                );
            }
        }

        // clean up
        // workernode.parentNode.removeChild(workernode)

        return this;
    };

    //fallback
    jsPDFAPI.addSVG = jsPDFAPI.addSvg;

    /**
    * Parses SVG XML and saves it as image into the PDF.
    *
    * Depends on canvas-element and canvg
    *
    * @name addSvgAsImage
    * @public
    * @function
    * @param {string} SVG-Data as Text
    * @param {number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
    * @param {number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
    * @param {number} width of SVG-Image (in units declared at inception of PDF document)
    * @param {number} height of SVG-Image (in units declared at inception of PDF document)
    * @param {string} alias of SVG-Image (if used multiple times)
    * @param {string} compression of the generated JPEG, can have the values 'NONE', 'FAST', 'MEDIUM' and 'SLOW'
    * @param {number} rotation of the image in degrees (0-359)
    *
    * @returns jsPDF jsPDF-instance
    */
    jsPDFAPI.addSvgAsImage = function (svg, x, y, w, h, alias, compression, rotation) {

        if (isNaN(x) || isNaN(y)) {
            console.error('jsPDF.addSvgAsImage: Invalid coordinates', arguments);
            throw new Error('Invalid coordinates passed to jsPDF.addSvgAsImage');
        }

        if (isNaN(w) || isNaN(h)) {
            console.error('jsPDF.addSvgAsImage: Invalid measurements', arguments);
            throw new Error('Invalid measurements (width and/or height) passed to jsPDF.addSvgAsImage');
        }

        var canvas = document.createElement('canvas');
        canvas.width = w;
        canvas.height = h;
        var ctx = canvas.getContext('2d');
        ctx.fillStyle = '#fff';  /// set white fill style
        ctx.fillRect(0, 0, canvas.width, canvas.height);

        //load a svg snippet in the canvas with id = 'drawingArea'
        canvg(canvas, svg, {
            ignoreMouse: true,
            ignoreAnimation: true,
            ignoreDimensions: true,
            ignoreClear: true
        });

        this.addImage(canvas.toDataURL("image/jpeg", 1.0), x, y, w, h, compression, rotation);
        return this;
    };

})(jsPDF.API);
<commit_msg>Improved parsing of SVG coordinate pairs (#2431)<commit_after>/* global jsPDF, canvg */
/** @license
 * Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * ====================================================================
 */

/**
* jsPDF SVG plugin
*
* @name svg
* @module
*/
(function (jsPDFAPI) {
    'use strict'

    /**
    * Parses SVG XML and converts only some of the SVG elements into
    * PDF elements.
    *
    * Supports:
    * paths
    *
    * @name addSvg
    * @public
	* @function
    * @param {string} SVG-Data as Text
    * @param {number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
    * @param {number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
    * @param {number} width of SVG (in units declared at inception of PDF document)
    * @param {number} height of SVG (in units declared at inception of PDF document)
    * @returns {Object} jsPDF-instance
	*/
    jsPDFAPI.addSvg = function (svgtext, x, y, w, h) {
        // 'this' is _jsPDF object returned when jsPDF is inited (new jsPDF())

        if (x === undefined || y === undefined) {
            throw new Error("addSVG needs values for 'x' and 'y'");
        }

        function InjectCSS(cssbody, document) {
            var styletag = document.createElement('style');
            styletag.type = 'text/css';
            if (styletag.styleSheet) {
                // ie
                styletag.styleSheet.cssText = cssbody;
            } else {
                // others
                styletag.appendChild(document.createTextNode(cssbody));
            }
            document.getElementsByTagName("head")[0].appendChild(styletag);
        }

        function createWorkerNode(document) {

            var frameID = 'childframe' // Date.now().toString() + '_' + (Math.random() * 100).toString()
                , frame = document.createElement('iframe');

            InjectCSS(
                '.jsPDF_sillysvg_iframe {display:none;position:absolute;}'
                , document
            );

            frame.name = frameID;
            frame.setAttribute("width", 0);
            frame.setAttribute("height", 0);
            frame.setAttribute("frameborder", "0");
            frame.setAttribute("scrolling", "no");
            frame.setAttribute("seamless", "seamless");
            frame.setAttribute("class", "jsPDF_sillysvg_iframe");

            document.body.appendChild(frame);

            return frame;
        }

        function attachSVGToWorkerNode(svgtext, frame) {
            var framedoc = (frame.contentWindow || frame.contentDocument).document;
            framedoc.write(svgtext);
            framedoc.close();
            return framedoc.getElementsByTagName('svg')[0];
        }

        function convertPathToPDFLinesArgs(path) {
            'use strict'
            // we will use 'lines' method call. it needs:
            // - starting coordinate pair
            // - array of arrays of vector shifts (2-len for line, 6 len for bezier)
            // - scale array [horizontal, vertical] ratios
            // - style (stroke, fill, both)

            var x = parseFloat(path[1])
                , y = parseFloat(path[2])
                , vectors = []
                , position = 3
                , len = path.length;

            while (position < len) {
                if (path[position] === 'c') {
                    vectors.push([
                        parseFloat(path[position + 1])
                        , parseFloat(path[position + 2])
                        , parseFloat(path[position + 3])
                        , parseFloat(path[position + 4])
                        , parseFloat(path[position + 5])
                        , parseFloat(path[position + 6])
                    ]);
                    position += 7;
                } else if (path[position] === 'l') {
                    vectors.push([
                        parseFloat(path[position + 1])
                        , parseFloat(path[position + 2])
                    ]);
                    position += 3;
                } else {
                    position += 1;
                }
            }
            return [x, y, vectors];
        }

        var workernode = createWorkerNode(document)
            , svgnode = attachSVGToWorkerNode(svgtext, workernode)
            , scale = [1, 1]
            , svgw = parseFloat(svgnode.getAttribute('width'))
            , svgh = parseFloat(svgnode.getAttribute('height'));

        if (svgw && svgh) {
            // setting both w and h makes image stretch to size.
            // this may distort the image, but fits your demanded size
            if (w && h) {
                scale = [w / svgw, h / svgh];
            }
            // if only one is set, that value is set as max and SVG
            // is scaled proportionately.
            else if (w) {
                scale = [w / svgw, w / svgw];
            } else if (h) {
                scale = [h / svgh, h / svgh];
            }
        }

        var i, l, tmp
            , linesargs
            , items = svgnode.childNodes;
        for (i = 0, l = items.length; i < l; i++) {
            tmp = items[i];
            if (tmp.tagName && tmp.tagName.toUpperCase() === 'PATH') {
                linesargs = convertPathToPDFLinesArgs(tmp.getAttribute("d").split(tmp.getAttribute("d").indexOf(',') === -1 ? ' ' : ','));

                // path start x coordinate
                linesargs[0] = linesargs[0] * scale[0] + x; // where x is upper left X of image
                // path start y coordinate
                linesargs[1] = linesargs[1] * scale[1] + y; // where y is upper left Y of image
                // the rest of lines are vectors. these will adjust with scale value auto.
                this.lines.call(
                    this
                    , linesargs[2] // lines
                    , linesargs[0] // starting x
                    , linesargs[1] // starting y
                    , scale
                );
            }
        }

        // clean up
        // workernode.parentNode.removeChild(workernode)

        return this;
    };

    //fallback
    jsPDFAPI.addSVG = jsPDFAPI.addSvg;

    /**
    * Parses SVG XML and saves it as image into the PDF.
    *
    * Depends on canvas-element and canvg
    *
    * @name addSvgAsImage
    * @public
    * @function
    * @param {string} SVG-Data as Text
    * @param {number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
    * @param {number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
    * @param {number} width of SVG-Image (in units declared at inception of PDF document)
    * @param {number} height of SVG-Image (in units declared at inception of PDF document)
    * @param {string} alias of SVG-Image (if used multiple times)
    * @param {string} compression of the generated JPEG, can have the values 'NONE', 'FAST', 'MEDIUM' and 'SLOW'
    * @param {number} rotation of the image in degrees (0-359)
    *
    * @returns jsPDF jsPDF-instance
    */
    jsPDFAPI.addSvgAsImage = function (svg, x, y, w, h, alias, compression, rotation) {

        if (isNaN(x) || isNaN(y)) {
            console.error('jsPDF.addSvgAsImage: Invalid coordinates', arguments);
            throw new Error('Invalid coordinates passed to jsPDF.addSvgAsImage');
        }

        if (isNaN(w) || isNaN(h)) {
            console.error('jsPDF.addSvgAsImage: Invalid measurements', arguments);
            throw new Error('Invalid measurements (width and/or height) passed to jsPDF.addSvgAsImage');
        }

        var canvas = document.createElement('canvas');
        canvas.width = w;
        canvas.height = h;
        var ctx = canvas.getContext('2d');
        ctx.fillStyle = '#fff';  /// set white fill style
        ctx.fillRect(0, 0, canvas.width, canvas.height);

        //load a svg snippet in the canvas with id = 'drawingArea'
        canvg(canvas, svg, {
            ignoreMouse: true,
            ignoreAnimation: true,
            ignoreDimensions: true,
            ignoreClear: true
        });

        this.addImage(canvas.toDataURL("image/jpeg", 1.0), x, y, w, h, compression, rotation);
        return this;
    };

})(jsPDF.API);
<|endoftext|>


<commit_before>var _          = require('_'),
    overload   = require('overload'),
    O          = overload.O,

    _SUPPORTS  = require('../supports'),
    _NODE_TYPE = require('../nodeType'),

    _utils     = require('../utils'),
    _div       = require('../div');

var _outerHtml = function() {
    return this.length ? this[0].outerHTML : null;
};

var _text = {
    get: (_div.textContent !== undefined) ?
        function(elem) { return elem.textContent; } :
            function(elem) { return elem.innerText; } ,
    set: (_div.textContent !== undefined) ?
        function(elem, str) { elem.textContent = str; } :
            function(elem, str) { elem.innerText = str; }
};

var _valHooks = {
    option: {
        get: function(elem) {
            var val = elem.getAttribute('value');
            return _.exists(val) ? val : _text.get(elem);
        }
    },

    select: {
        get: function(elem) {
            var value, option,
                options = elem.options,
                index   = elem.selectedIndex,
                one     = elem.type === 'select-one' || index < 0,
                values  = one ? null : [],
                max     = one ? index + 1 : options.length,
                idx     = index < 0 ? max : (one ? index : 0);

            // Loop through all the selected options
            for (; idx < max; idx++) {
                option = options[idx];

                // oldIE doesn't update selected after form reset (#2551)
                if ((option.selected || idx === index) &&
                        // Don't return options that are disabled or in a disabled optgroup
                        (_SUPPORTS.optDisabled ? !option.disabled : option.getAttribute('disabled') === null) &&
                        (!option.parentNode.disabled || !_utils.isNodeName(option.parentNode, 'optgroup'))) {

                    // Get the specific value for the option
                    value = _valHooks.option.get(option);

                    // We don't need an array for one selects
                    if (one) {
                        return value;
                    }

                    // Multi-Selects return an array
                    values.push(value);
                }
            }

            return values;
        },

        set: function(elem, value) {
            var optionSet, option,
                options = elem.options,
                values  = jQuery.makeArray(value),
                idx     = options.length;

            while (idx--) {
                option = options[idx];

                if (jQuery.inArray(jQuery.valHooks.option.get(option), values) >= 0) {
                    option.selected = optionSet = true;
                } else {
                    option.selected = false;
                }
            }

            // Force browsers to behave consistently when non-matching value is set
            if (!optionSet) {
                elem.selectedIndex = -1;
            }
        }
    }

};

// Radios and checkboxes getter/setter
_.each(['radio', 'checkbox'], function(type) {
    _valHooks[type] = {
        set: function(elem, value) {
            if (_.isArray(value)) {
                return (elem.checked = jQuery.inArray(jQuery(elem).val(), value) >= 0);
            }
        }
    };

    if (!_SUPPORTS.checkOn) {
        _valHooks[type].get = function(elem) {
            // Support: Webkit - '' is returned instead of 'on' if a value isn't specified
            return elem.getAttribute('value') === null ? 'on' : elem.value;
        };
    }
});

var _getVal = function(elem) {
    if (!elem || (elem.nodeType !== _NODE_TYPE.ELEMENT)) { return; }

    var hook = _valHooks[elem.type] || _valHooks[_utils.normalNodeName(elem)];
    if (hook && hook.get) {
        return hook.get(elem);
    }

    var val = elem.value;
    return _.isString(val) ? _utils.normalizeNewlines(val) : val;

};

var _setVal = function(elem, value) {
    if (elem.nodeType !== _NODE_TYPE.ELEMENT) { return; }

    var hook = _valHooks[elem.type] || _valHooks[_utils.normalNodeName(elem)];
    if (hook && hook.set) {
        hook.set(elem, value);
    } else {
        elem.setAttribute('value', value);
    }
};

module.exports = {
    fn: {
        // TODO: Overload and determine api
        // TODO: unit tests
        outerHtml: _outerHtml,
        outerHTML: _outerHtml,

        html: overload()
            .args(String)
            .use(function(html) {
                return _.each(this, function(elem) {
                    elem.innerHTML = html;
                });
            })

            .args(Function)
            .use(function(iterator) {
                return _.each(this, function(elem, idx) {
                    elem.innerHTML = iterator.call(elem, idx, elem.innerHTML);
                });
            })

            .fallback(function() {
                var first = this[0];
                return (!first) ? undefined : first.innerHTML;
            })
            .expose(),

        // TODO: Add handling of (and unit tests for) \r\n in IE
        val: overload()
            .args(O.any(String, Number))
            .use(function(value) {
                value = '' + value;
                return _.each(this, function(elem) {
                    _setVal(elem, value);
                });
            })

            .args(Function)
            .use(function(iterator) {
                return _.each(this, function(elem, idx) {
                    if (elem.nodeType !== _NODE_TYPE.ELEMENT) { return; }

                    var value = iterator.call(elem, idx, _getVal(elem));
                    var hook = _valHooks[elem.type] || _valHooks[_utils.normalNodeName(elem)];

                    if (hook && hook.set) {
                        hook.set(elem, value);
                    } else {
                        elem.setAttribute('value', value);
                    }
                });
            })

            .args(Array)
            .use(function(arr) {
                var dom = this,
                    len = this.length;
                _.each(arr, function(val, idx) {
                    if (idx >= len) { return false; }
                    _setVal(dom[idx], '' + val);
                });
                return this;
            })

            .fallback(function() {
                return _getVal(this[0]);
            })

            .expose(),

        text: overload()
            .args(String)
            .use(function(str) {
                return _.each(this, function(elem) {
                    _text.set(elem, str);
                });
            })

            .args(Function)
            .use(function(iterator) {
                return _.each(this, function(elem, idx) {
                    _text.set(elem, iterator.call(elem, idx, _text.get(elem)));
                });
            })

            .fallback(function() {
                var str = '';
                _.each(this, function(elem) {
                    str += _text.get(elem);
                });

                return str;
            })
            .expose()
    }
};
<commit_msg>Fixed failing tests<commit_after>var _          = require('_'),
    overload   = require('overload'),
    O          = overload.O,

    _SUPPORTS  = require('../supports'),
    _NODE_TYPE = require('../nodeType'),

    _utils     = require('../utils'),
    _div       = require('../div');

var _outerHtml = function() {
    return this.length ? this[0].outerHTML : null;
};

var _text = {
    get: (_div.textContent !== undefined) ?
        function(elem) { return elem.textContent; } :
            function(elem) { return elem.innerText; } ,
    set: (_div.textContent !== undefined) ?
        function(elem, str) { elem.textContent = str; } :
            function(elem, str) { elem.innerText = str; }
};

var _valHooks = {
    option: {
        get: function(elem) {
            var val = elem.getAttribute('value');
            return _.exists(val) ? val : _text.get(elem);
        }
    },

    select: {
        get: function(elem) {
            var value, option,
                options = elem.options,
                index   = elem.selectedIndex,
                one     = elem.type === 'select-one' || index < 0,
                values  = one ? null : [],
                max     = one ? index + 1 : options.length,
                idx     = index < 0 ? max : (one ? index : 0);

            // Loop through all the selected options
            for (; idx < max; idx++) {
                option = options[idx];

                // oldIE doesn't update selected after form reset (#2551)
                if ((option.selected || idx === index) &&
                        // Don't return options that are disabled or in a disabled optgroup
                        (_SUPPORTS.optDisabled ? !option.disabled : option.getAttribute('disabled') === null) &&
                        (!option.parentNode.disabled || !_utils.isNodeName(option.parentNode, 'optgroup'))) {

                    // Get the specific value for the option
                    value = _valHooks.option.get(option);

                    // We don't need an array for one selects
                    if (one) {
                        return value;
                    }

                    // Multi-Selects return an array
                    values.push(value);
                }
            }

            return values;
        },

        set: function(elem, value) {
            var optionSet, option,
                options = elem.options,
                values  = jQuery.makeArray(value),
                idx     = options.length;

            while (idx--) {
                option = options[idx];

                if (jQuery.inArray(jQuery.valHooks.option.get(option), values) >= 0) {
                    option.selected = optionSet = true;
                } else {
                    option.selected = false;
                }
            }

            // Force browsers to behave consistently when non-matching value is set
            if (!optionSet) {
                elem.selectedIndex = -1;
            }
        }
    }

};

// Radios and checkboxes getter/setter
_.each(['radio', 'checkbox'], function(type) {
    _valHooks[type] = {
        set: function(elem, value) {
            if (_.isArray(value)) {
                return (elem.checked = jQuery.inArray(jQuery(elem).val(), value) >= 0);
            }
        }
    };

    if (!_SUPPORTS.checkOn) {
        _valHooks[type].get = function(elem) {
            // Support: Webkit - '' is returned instead of 'on' if a value isn't specified
            return elem.getAttribute('value') === null ? 'on' : elem.value;
        };
    }
});

var _getVal = function(elem) {
    if (!elem || (elem.nodeType !== _NODE_TYPE.ELEMENT)) { return; }

    var hook = _valHooks[elem.type] || _valHooks[_utils.normalNodeName(elem)];
    if (hook && hook.get) {
        return hook.get(elem);
    }

    var val = elem.value;
    return _.isString(val) ? _utils.normalizeNewlines(val) : val;

};

var _setVal = function(elem, value) {
    if (elem.nodeType !== _NODE_TYPE.ELEMENT) { return; }

    var hook = _valHooks[elem.type] || _valHooks[_utils.normalNodeName(elem)];
    if (hook && hook.set) {
        hook.set(elem, value);
    } else {
        elem.setAttribute('value', value);
    }
};

module.exports = {
    fn: {
        // TODO: Overload and determine api
        // TODO: unit tests
        outerHtml: _outerHtml,
        outerHTML: _outerHtml,

        html: overload()
            .args(String)
            .use(function(html) {
                return _.each(this, function(elem) {
                    elem.innerHTML = html;
                });
            })

            .args(Function)
            .use(function(iterator) {
                return _.each(this, function(elem, idx) {
                    elem.innerHTML = iterator.call(elem, idx, elem.innerHTML);
                });
            })

            .fallback(function() {
                var first = this[0];
                return (!first) ? undefined : first.innerHTML;
            })
            .expose(),

        // TODO: Add handling of (and unit tests for) \r\n in IE
        val: overload()
            .args()
            .use(function() {
                return _getVal(this[0]);
            })

            .args(Function)
            .use(function(iterator) {
                return _.each(this, function(elem, idx) {
                    if (elem.nodeType !== _NODE_TYPE.ELEMENT) { return; }

                    var value = iterator.call(elem, idx, _getVal(elem));
                    var hook = _valHooks[elem.type] || _valHooks[_utils.normalNodeName(elem)];

                    if (hook && hook.set) {
                        hook.set(elem, value);
                    } else {
                        elem.setAttribute('value', value);
                    }
                });
            })

            .args(Array)
            .use(function(arr) {
                var dom = this,
                    len = this.length;
                _.each(arr, function(val, idx) {
                    if (idx >= len) { return false; }
                    _setVal(dom[idx], '' + val);
                });
                return this;
            })

            .args(O.any(null, undefined))
            .use(function(value) {
                return _.each(this, function(elem) {
                    _setVal(elem, '');
                });
            })

            .fallback(function(value) {
                value = '' + value;
                return _.each(this, function(elem) {
                    _setVal(elem, value);
                });
            })

            .expose(),

        text: overload()
            .args(String)
            .use(function(str) {
                return _.each(this, function(elem) {
                    _text.set(elem, str);
                });
            })

            .args(Function)
            .use(function(iterator) {
                return _.each(this, function(elem, idx) {
                    _text.set(elem, iterator.call(elem, idx, _text.get(elem)));
                });
            })

            .fallback(function() {
                var str = '';
                _.each(this, function(elem) {
                    str += _text.get(elem);
                });

                return str;
            })
            .expose()
    }
};
<|endoftext|>


<commit_before>// @flow
import styles from './ReadMore.less';

import React, { PureComponent } from 'react';
import classnames from 'classnames';

import themeVars from '../private/themeVars';
import Text from '../Text/Text';
import TextLink from '../TextLink/TextLink';

const { rowHeight, standardTypeRowSpan, interactionTypeRowSpan } = themeVars;
const buttonHeight = rowHeight * interactionTypeRowSpan;

const getMaxHeight = (maxLines?: number, maxRows?: number) => {
  if (maxLines) {
    return maxLines * rowHeight * standardTypeRowSpan;
  }

  if (maxRows) {
    return maxRows * rowHeight;
  }

  return 0;
};

type Props = {|
  children: React$Element<*>,
  maxLines?: number,
  maxRows?: number,
  moreLabel: string,
  lessLabel: string,
  backgroundComponentName: 'card' | 'body' | 'gray-lightest',
  onShowMore?: Function
|};
type State = {|
  showMore: boolean,
  tooLong: boolean,
  mounted: boolean
|};
class ReadMore extends PureComponent<Props, State> {
  static defaultProps = {
    moreLabel: 'More',
    lessLabel: 'Less',
    backgroundComponentName: 'card'
  };

  constructor(props: Props) {
    super(props);

    this.contentRef = null;

    this.state = {
      showMore: false,
      tooLong: false,
      mounted: false
    };
  }

  componentDidMount() {
    this.update();
  }

  componentDidUpdate() {
    this.update();
  }

  contentRef: ?HTMLDivElement;

  update = () => {
    const { maxLines, maxRows } = this.props;

    if (this.contentRef) {
      const { scrollHeight } = this.contentRef;

      const tooLong =
        scrollHeight > getMaxHeight(maxLines, maxRows) + buttonHeight;

      this.setState({ tooLong, mounted: true }); // eslint-disable-line
    }
  };

  setTextRef = (element: ?HTMLDivElement) => {
    this.contentRef = element;
  };

  handleShowMore = () => {
    const { onShowMore } = this.props;

    this.setState(
      {
        showMore: !this.state.showMore
      },
      () => {
        if (onShowMore) {
          onShowMore(this.state.showMore);
        }
      }
    );
  };

  render() {
    const {
      children,
      maxLines,
      maxRows,
      moreLabel,
      lessLabel,
      backgroundComponentName
    } = this.props;
    const { tooLong, showMore, mounted } = this.state;

    const truncate = mounted ? !showMore && tooLong : true;
    const showFade = truncate && mounted;
    const fadeColor = styles[backgroundComponentName];
    const showMoreLessButton = tooLong && mounted;

    const contentStyle = truncate ? {
      maxHeight: getMaxHeight(maxLines, maxRows),
      overflow: 'hidden'
    } : {};

    return (

{children}

          {showFade ? (

          ) : null}

        {showMoreLessButton && (
          <Text
            strong
            chevron={showMore ? 'up' : 'down'}
            className={styles.showMore}
            component={TextLink}
            onClick={this.handleShowMore}>
            {showMore ? lessLabel : moreLabel}
          </Text>
        )}

    );
  }
}

export default ReadMore;
<commit_msg>feat(ReadMore): Add ability to access state of more button visiblity (#599)<commit_after>// @flow
import styles from './ReadMore.less';

import React, { PureComponent } from 'react';
import classnames from 'classnames';

import themeVars from '../private/themeVars';
import Text from '../Text/Text';
import TextLink from '../TextLink/TextLink';

const { rowHeight, standardTypeRowSpan, interactionTypeRowSpan } = themeVars;
const buttonHeight = rowHeight * interactionTypeRowSpan;

const getMaxHeight = (maxLines?: number, maxRows?: number) => {
  if (maxLines) {
    return maxLines * rowHeight * standardTypeRowSpan;
  }

  if (maxRows) {
    return maxRows * rowHeight;
  }

  return 0;
};

type Props = {|
  children: React$Element<*>,
  maxLines?: number,
  maxRows?: number,
  moreLabel: string,
  lessLabel: string,
  backgroundComponentName: 'card' | 'body' | 'gray-lightest',
  onShowMore?: Function,
  onMoreButtonVisibilityChange?: Function
|};
type State = {|
  showMore: boolean,
  tooLong: boolean,
  mounted: boolean
|};
class ReadMore extends PureComponent<Props, State> {
  static defaultProps = {
    moreLabel: 'More',
    lessLabel: 'Less',
    backgroundComponentName: 'card'
  };

  constructor(props: Props) {
    super(props);

    this.contentRef = null;

    this.state = {
      showMore: false,
      tooLong: false,
      mounted: false
    };
  }

  componentDidMount() {
    this.update();
  }

  componentDidUpdate() {
    this.update();
  }

  contentRef: ?HTMLDivElement;

  update = () => {
    const { maxLines, maxRows, onMoreButtonVisibilityChange } = this.props;

    if (this.contentRef) {
      const { scrollHeight } = this.contentRef;

      const tooLong =
        scrollHeight > getMaxHeight(maxLines, maxRows) + buttonHeight;

      this.setState({ tooLong, mounted: true }); // eslint-disable-line

      if (onMoreButtonVisibilityChange && tooLong !== this.state.tooLong) {
        onMoreButtonVisibilityChange(tooLong);
      }
    }
  };

  setTextRef = (element: ?HTMLDivElement) => {
    this.contentRef = element;
  };

  handleShowMore = () => {
    const { onShowMore } = this.props;

    this.setState(
      {
        showMore: !this.state.showMore
      },
      () => {
        if (onShowMore) {
          onShowMore(this.state.showMore);
        }
      }
    );
  };

  render() {
    const {
      children,
      maxLines,
      maxRows,
      moreLabel,
      lessLabel,
      backgroundComponentName
    } = this.props;
    const { tooLong, showMore, mounted } = this.state;

    const truncate = mounted ? !showMore && tooLong : true;
    const showFade = truncate && mounted;
    const fadeColor = styles[backgroundComponentName];
    const showMoreLessButton = tooLong && mounted;

    const contentStyle = truncate ? {
      maxHeight: getMaxHeight(maxLines, maxRows),
      overflow: 'hidden'
    } : {};

    return (

{children}

          {showFade ? (

          ) : null}

        {showMoreLessButton && (
          <Text
            strong
            chevron={showMore ? 'up' : 'down'}
            className={styles.showMore}
            component={TextLink}
            onClick={this.handleShowMore}>
            {showMore ? lessLabel : moreLabel}
          </Text>
        )}

    );
  }
}

export default ReadMore;
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';

const { ipcRenderer, shell } = require('electron');

const showdown = require('showdown');

class ReleaseInfo extends Component {
  constructor() {
    super();
    this.state = {
      markdown: null,
    };
  }
  componentWillMount() {
    fetch('https://raw.githubusercontent.com/tahnik/devRantron/update-md/UPDATE.md')
      .then((res) => {
        res.text().then((latestRelease) => {
          console.log(latestRelease);
          const converter = new showdown.Converter();
          const html = converter.makeHtml(latestRelease);
          this.setState({ markdown: html });
        });
      });
  }
  static handleUpdate() {
    let plat = '';

    if (/^win/.test(process.platform)) { plat = 'windows'; }
    if (/^dar/.test(process.platform)) { plat = 'osx'; }
    if (/^lin/.test(process.platform)) { plat = 'linux'; }

    if (plat === 'windows') {
      ipcRenderer.send('updateNow', true);
    } else {
      shell.openExternal('https://devrantron.firebaseapp.com/');
    }
  }
  render() {
    const { close } = this.props;
    return (

            {
              this.state.markdown === '' ?

Fetching release note
 :

            }

              <button onClick={() => ReleaseInfo.handleUpdate()}>Update</button>
              <button onClick={() => close()}>Not Now</button>

              * On Windows: Update will be installed after you click update
              * On MacOS and Linux: Clicking update will take you to our website.
                You have to download the latest update from there.

    );
  }
}

ReleaseInfo.propTypes = {
  close: PropTypes.func.isRequired,
};

export default ReleaseInfo;
<commit_msg>Removed console log<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';

const { ipcRenderer, shell } = require('electron');

const showdown = require('showdown');

class ReleaseInfo extends Component {
  constructor() {
    super();
    this.state = {
      markdown: null,
    };
  }
  componentWillMount() {
    fetch('https://raw.githubusercontent.com/tahnik/devRantron/update-md/UPDATE.md')
      .then((res) => {
        res.text().then((latestRelease) => {
          const converter = new showdown.Converter();
          const html = converter.makeHtml(latestRelease);
          this.setState({ markdown: html });
        });
      });
  }
  static handleUpdate() {
    let plat = '';

    if (/^win/.test(process.platform)) { plat = 'windows'; }
    if (/^dar/.test(process.platform)) { plat = 'osx'; }
    if (/^lin/.test(process.platform)) { plat = 'linux'; }

    if (plat === 'windows') {
      ipcRenderer.send('updateNow', true);
    } else {
      shell.openExternal('https://devrantron.firebaseapp.com/');
    }
  }
  render() {
    const { close } = this.props;
    return (

            {
              this.state.markdown === '' ?

Fetching release note
 :

            }

              <button onClick={() => ReleaseInfo.handleUpdate()}>Update</button>
              <button onClick={() => close()}>Not Now</button>

              * On Windows: Update will be installed after you click update
              * On MacOS and Linux: Clicking update will take you to our website.
                You have to download the latest update from there.

    );
  }
}

ReleaseInfo.propTypes = {
  close: PropTypes.func.isRequired,
};

export default ReleaseInfo;
<|endoftext|>


<commit_before><commit_msg>Center tool tips<commit_after><|endoftext|>


<commit_before><commit_msg>Related input generator (task #5524)<commit_after><|endoftext|>


<commit_before><commit_msg>Auto-focus the Quick Plot popup window. Thus if we're doing a quick plot again, and the popup window is already open (but not topmost), it will be brought to the front.<commit_after><|endoftext|>


<commit_before><commit_msg>gaming<commit_after><|endoftext|>


<commit_before>'use strict';   // dont touch
var plugin = []; // dont touch
plugin.command = []; // dont touch
plugin.commandName = []; // dont touch
plugin.gamemodeId = []; // dont touch
plugin.gamemode = []; // dont touch
plugin.addToHelp = []; // dont touch

// [General]
plugin.name = ""; // Name of plugin REQUIRED
plugin.author = ""; // author REQUIRED
plugin.description = ''; // Desciprtion
plugin.compatVersion = ''; // compatable with (todo)
plugin.version = ''; // version REQUIRED

// [Extra Commands]
plugin.commandName[0] = ""; // plugin add-on command names
plugin.addToHelp[0] = ""; // help command add-on (adds this string to the help command)
plugin.command[0] = ''; // extra command location

// [Extra Gamemodes]
plugin.gamemodeId[0] = ''; // gamemodeids of extra plugin gamemodes
plugin.gamemode[0] = ''; // gamemode location

// [Configs]
plugin.config = {
// config1: 0,

}
plugin.configfile = 'config.ini'

// [Functions]
plugin.init = function (gameServer) {
  // init, Used to do stuff such as overriding things

};

plugin.onSecond = function (gameServer) {

  // called every second
};

module.exports = plugin; // dont touch
<commit_msg>Update index.js<commit_after>'use strict';   // dont touch
var plugin = []; // dont touch
plugin.command = []; // dont touch
plugin.commandName = []; // dont touch
plugin.gamemodeId = []; // dont touch
plugin.gamemode = []; // dont touch
plugin.addToHelp = []; // dont touch

// [General]
plugin.name = ""; // Name of plugin REQUIRED
plugin.author = ""; // author REQUIRED
plugin.description = ''; // Desciprtion
plugin.compatVersion = ''; // compatable with (todo)
plugin.version = ''; // version REQUIRED

// [Extra Commands]
plugin.commandName[0] = ""; // plugin add-on command names
plugin.addToHelp[0] = ""; // help command add-on (adds this string to the help command)
plugin.command[0] = ''; // extra command location

// [Extra Gamemodes]
plugin.gamemodeId[0] = ''; // gamemodeids of extra plugin gamemodes
plugin.gamemode[0] = ''; // gamemode location

// [Configs]
plugin.config = {
// config1: 0,

}
plugin.configfile = 'config.ini'

// [Functions]
plugin.init = function (gameServer, config) {
  this.config = config;

  // init, Used to do stuff such as overriding things

};

plugin.onSecond = function (gameServer) {

  // called every second
};

module.exports = plugin; // dont touch
<|endoftext|>


<commit_before>'use strict';   // dont touch
var plugin = []; // dont touch
plugin.command = []; // dont touch
plugin.commandName = []; // dont touch
plugin.gamemodeId = []; // dont touch
plugin.gamemode = []; // dont touch
plugin.addToHelp = []; // dont touch

// [General]
plugin.name = ""; // Name of plugin
plugin.author = ""; // author
plugin.description = ''; // Desciprtion
plugin.compatVersion = ''; // compatable with (todo)
plugin.version = ''; // version

// [Extra Commands]
plugin.commandName[0] = ""; // plugin add-on command names
plugin.addToHelp[0] = ""; // help command add-on (adds this string to the help command)
plugin.command[0] = ''; // extra command location

// [Extra Gamemodes]
plugin.gamemodeId[0] = ''; // gamemodeids of extra plugin gamemodes
plugin.gamemode[0] = ''; // gamemode location

// [Functions]
plugin.init = function (gameServer) {
  // init, Used to do stuff such as overriding things

};

plugin.onSecond = function (gameServer) {

  // called every second
};

module.exports = plugin; // dont touch
<commit_msg>Update index.js<commit_after>'use strict';   // dont touch
var plugin = []; // dont touch
plugin.command = []; // dont touch
plugin.commandName = []; // dont touch
plugin.gamemodeId = []; // dont touch
plugin.gamemode = []; // dont touch
plugin.addToHelp = []; // dont touch

// [General]
plugin.name = ""; // Name of plugin REQUIRED
plugin.author = ""; // author REQUIRED
plugin.description = ''; // Desciprtion
plugin.compatVersion = ''; // compatable with (todo)
plugin.version = ''; // version REQUIRED

// [Extra Commands]
plugin.commandName[0] = ""; // plugin add-on command names
plugin.addToHelp[0] = ""; // help command add-on (adds this string to the help command)
plugin.command[0] = ''; // extra command location

// [Extra Gamemodes]
plugin.gamemodeId[0] = ''; // gamemodeids of extra plugin gamemodes
plugin.gamemode[0] = ''; // gamemode location

// [Functions]
plugin.init = function (gameServer) {
  // init, Used to do stuff such as overriding things

};

plugin.onSecond = function (gameServer) {

  // called every second
};

module.exports = plugin; // dont touch
<|endoftext|>