<commit_before>/**
 * @author mflux / http://minmax.design
 * Based on @mattdesl three-orbit-viewer
 */

import emitter from 'mitt';

import * as THREE from './lib/three';
import installVREffect from './lib/VREffect';
import installVRControls from './lib/VRControls';
import installVRController from './lib/VRController';
import stats from './lib/stats';
import { tempVector } from './utils/three';
import settings from './settings';
import InstancedItem from './instanced-item';
import feature from './utils/feature';
import windowSize from './utils/windowSize';
import audio from './audio';
import postprocessing from './postprocessing';
import Room from './room';
import { backgroundColor } from './theme/colors';
import updateCull from './cull';

const orthographicDistance = 4;
// TODO: remove me:
// const times = [0];
// document.addEventListener('keydown', (event) => {
//   if (event.shiftKey) {
//     times.push(audio.time);
//   }
//   if (event.metaKey) {
//     console.log(times);
//   }
// });

const cameras = (function () {
  const { aspectRatio } = windowSize;
  const perspective = new THREE.PerspectiveCamera(70, aspectRatio, 0.1, 1000);
  perspective.lookAt(tempVector(0, 0, 1));
  perspective.position.y = settings.holeHeight;

  const orthographic = new THREE.OrthographicCamera(
    -orthographicDistance * aspectRatio,
    orthographicDistance * aspectRatio,
    orthographicDistance,
    -orthographicDistance,
    -100,
    1000,
  );
  orthographic.position.set(0.06, 0.08, 0.08);
  orthographic.lookAt(tempVector());

  return { default: perspective, orthographic };
}());

const cameraWorldPos = new THREE.Vector3();

let lastZoom = 4;
let lastAspectRatio;
const zoomCamera = (zoom) => {
  const newZoom = sineInOut(zoom);
  const { aspectRatio } = windowSize;
  if (newZoom === lastZoom && lastAspectRatio === aspectRatio) return;
  const distance = orthographicDistance + (feature.isMobile ? newZoom : newZoom * 3);
  const camera = cameras.orthographic;
  camera.left = -distance * aspectRatio;
  camera.right = distance * aspectRatio;
  camera.top = distance;
  camera.bottom = -distance;
  camera.updateProjectionMatrix();
  lastZoom = newZoom;
};

let renderer;
let vrEffect;
let controls;
let renderPostProcessing;
let resizePostProcessing;
let clock;

const sineInOut = t => -0.5 * (Math.cos(Math.PI * t) - 1);
const fog = new THREE.Fog(backgroundColor, 10, 200);

const createScene = () => {
  const _scene = new THREE.Scene();
  const light = new THREE.DirectionalLight(0xffffff);
  light.position.set(-1.42, 1.86, 0.74).normalize();

  const ambientLight = new THREE.AmbientLight(0x444444, 0.7);
  const hemisphereLight = new THREE.HemisphereLight(0x606060, 0x404040);

  _scene.add(hemisphereLight, light, ambientLight);
  _scene.fog = fog;
  return _scene;
};

const scene = createScene();

const onResize = ({ width, height, aspectRatio }) => {
  const { orthographic } = cameras;
  Object.assign(
    orthographic,
    {
      left: -orthographicDistance * aspectRatio,
      right: orthographicDistance * aspectRatio,
    },
  );

  vrEffect.setSize(width, height);

  renderer.domElement.style.width = `${width}px`;
  renderer.domElement.style.height = `${height}px`;

  resizePostProcessing(width, height);

  Object
    .values(cameras)
    .forEach((camera) => {
      camera.aspect = aspectRatio;
      camera.updateProjectionMatrix();
    });
};

const viewer = Object.assign(emitter(), {
  camera: cameras.orthographic,
  cameras,
  cameraWorldPos,
  createScene,
  scene,
  renderScene: scene,
  controllers: [{}, {}],
  controls,
  renderer,
  fog,
  stopAnimating: () => {
    viewer.animating = false;
  },
  startAnimating: () => {
    viewer.animating = true;
    viewer.animate();
  },
  animate: (timestamp, staticTime) => {
    updateCull();
    const dt = clock.getDelta();
    if (viewer.animating) {
      vrEffect.requestAnimationFrame(viewer.animate);
    }

    THREE.VRController.update();

    if (feature.isIODaydream) {
      viewer.daydreamController.update();
    }

    controls.update();
    audio.tick(staticTime);
    Room.clear();
    viewer.emit('tick', dt);

    cameraWorldPos.setFromMatrixPosition(viewer.camera.matrixWorld);

    zoomCamera(
      audio.progress > 21
        ? Math.min(2, audio.progress - 21) * 0.5
        : 0
    );

    if (staticTime !== undefined) return;

    if (!vrEffect.isPresenting && viewer.camera === cameras.default) {
      renderPostProcessing();
    } else {
      vrEffect.render(viewer.renderScene, viewer.camera);
    }

    if (vrEffect.isPresenting && feature.hasExternalDisplay) {
      renderer.render(viewer.renderScene, viewer.camera);
    }

    viewer.emit('render', dt);
    if (settings.stats) stats(renderer);
  },
  prepare: () => {
    clock = new THREE.Clock();
    clock.start();
    installVREffect(THREE);
    installVRControls(THREE);
    installVRController(THREE);
    viewer.renderer = renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setClearColor(backgroundColor);
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, settings.maxPixelRatio));
    renderer.setSize(windowSize.width, windowSize.height);
    renderer.sortObjects = false;

    const containerEl = document.createElement('div');
    containerEl.className = 'viewer';
    containerEl.appendChild(renderer.domElement);
    document.body.appendChild(containerEl);

    viewer.vrEffect = vrEffect = new THREE.VREffect(renderer);
    viewer.controls = controls = new THREE.VRControls(cameras.default);
    controls.standing = true;

    window.addEventListener('vrdisplaypresentchange', () => {
      viewer.emit('vr-present-change', vrEffect.isPresenting);
      if (!vrEffect.isPresenting) viewer.switchCamera('orthographic');
    }, false);

    const { render, resize } = postprocessing({
      renderer,
      camera: cameras.default,
      scene,
    });
    renderPostProcessing = render;
    resizePostProcessing = resize;
    windowSize.on('resize', onResize, false);
  },

  exitPresent() {
    if (!vrEffect.isPresenting) return;
    vrEffect.exitPresent();
    viewer.switchCamera('orthographic');
  },

  enterPresent() {
    if (vrEffect.isPresenting) return;
    vrEffect.requestPresent();
    setTimeout(() => {
      viewer.switchCamera('default');
      scene.add(viewer.camera);
    }, 10); // Delay switching 10ms to avoid flashing POV before overlay is displayed
  },

  toggleVR: async () => {
    if (vrEffect.isPresenting) {
      viewer.exitPresent();
    } else {
      viewer.enterPresent();
    }
  },

  switchCamera: (name) => {
    if (name === 'orthographic') {
      InstancedItem.switch(name);
      viewer.renderScene.fog = null;
    } else {
      InstancedItem.switch('perspective');
      viewer.renderScene.fog = viewer.fog;
    }
    viewer.camera = cameras[name];
  },
  vrEffect,
});

export default viewer;
<commit_msg>only update vrcontroller with 6dof<commit_after>/**
 * @author mflux / http://minmax.design
 * Based on @mattdesl three-orbit-viewer
 */

import emitter from 'mitt';

import * as THREE from './lib/three';
import installVREffect from './lib/VREffect';
import installVRControls from './lib/VRControls';
import installVRController from './lib/VRController';
import stats from './lib/stats';
import { tempVector } from './utils/three';
import settings from './settings';
import InstancedItem from './instanced-item';
import feature from './utils/feature';
import windowSize from './utils/windowSize';
import audio from './audio';
import postprocessing from './postprocessing';
import Room from './room';
import { backgroundColor } from './theme/colors';
import updateCull from './cull';

const orthographicDistance = 4;
// TODO: remove me:
// const times = [0];
// document.addEventListener('keydown', (event) => {
//   if (event.shiftKey) {
//     times.push(audio.time);
//   }
//   if (event.metaKey) {
//     console.log(times);
//   }
// });

const cameras = (function () {
  const { aspectRatio } = windowSize;
  const perspective = new THREE.PerspectiveCamera(70, aspectRatio, 0.1, 1000);
  perspective.lookAt(tempVector(0, 0, 1));
  perspective.position.y = settings.holeHeight;

  const orthographic = new THREE.OrthographicCamera(
    -orthographicDistance * aspectRatio,
    orthographicDistance * aspectRatio,
    orthographicDistance,
    -orthographicDistance,
    -100,
    1000,
  );
  orthographic.position.set(0.06, 0.08, 0.08);
  orthographic.lookAt(tempVector());

  return { default: perspective, orthographic };
}());

const cameraWorldPos = new THREE.Vector3();

let lastZoom = 4;
let lastAspectRatio;
const zoomCamera = (zoom) => {
  const newZoom = sineInOut(zoom);
  const { aspectRatio } = windowSize;
  if (newZoom === lastZoom && lastAspectRatio === aspectRatio) return;
  const distance = orthographicDistance + (feature.isMobile ? newZoom : newZoom * 3);
  const camera = cameras.orthographic;
  camera.left = -distance * aspectRatio;
  camera.right = distance * aspectRatio;
  camera.top = distance;
  camera.bottom = -distance;
  camera.updateProjectionMatrix();
  lastZoom = newZoom;
};

let renderer;
let vrEffect;
let controls;
let renderPostProcessing;
let resizePostProcessing;
let clock;

const sineInOut = t => -0.5 * (Math.cos(Math.PI * t) - 1);
const fog = new THREE.Fog(backgroundColor, 10, 200);

const createScene = () => {
  const _scene = new THREE.Scene();
  const light = new THREE.DirectionalLight(0xffffff);
  light.position.set(-1.42, 1.86, 0.74).normalize();

  const ambientLight = new THREE.AmbientLight(0x444444, 0.7);
  const hemisphereLight = new THREE.HemisphereLight(0x606060, 0x404040);

  _scene.add(hemisphereLight, light, ambientLight);
  _scene.fog = fog;
  return _scene;
};

const scene = createScene();

const onResize = ({ width, height, aspectRatio }) => {
  const { orthographic } = cameras;
  Object.assign(
    orthographic,
    {
      left: -orthographicDistance * aspectRatio,
      right: orthographicDistance * aspectRatio,
    },
  );

  vrEffect.setSize(width, height);

  renderer.domElement.style.width = `${width}px`;
  renderer.domElement.style.height = `${height}px`;

  resizePostProcessing(width, height);

  Object
    .values(cameras)
    .forEach((camera) => {
      camera.aspect = aspectRatio;
      camera.updateProjectionMatrix();
    });
};

const viewer = Object.assign(emitter(), {
  camera: cameras.orthographic,
  cameras,
  cameraWorldPos,
  createScene,
  scene,
  renderScene: scene,
  controllers: [{}, {}],
  controls,
  renderer,
  fog,
  stopAnimating: () => {
    viewer.animating = false;
  },
  startAnimating: () => {
    viewer.animating = true;
    viewer.animate();
  },
  animate: (timestamp, staticTime) => {
    updateCull();
    const dt = clock.getDelta();
    if (viewer.animating) {
      vrEffect.requestAnimationFrame(viewer.animate);
    }

    if (feature.has6DOF) {
      VRController.update();
    }

    if (feature.isIODaydream) {
      viewer.daydreamController.update();
    }

    controls.update();
    audio.tick(staticTime);
    Room.clear();
    viewer.emit('tick', dt);

    cameraWorldPos.setFromMatrixPosition(viewer.camera.matrixWorld);

    zoomCamera(
      audio.progress > 21
        ? Math.min(2, audio.progress - 21) * 0.5
        : 0
    );

    if (staticTime !== undefined) return;

    if (!vrEffect.isPresenting && viewer.camera === cameras.default) {
      renderPostProcessing();
    } else {
      vrEffect.render(viewer.renderScene, viewer.camera);
    }

    if (vrEffect.isPresenting && feature.hasExternalDisplay) {
      renderer.render(viewer.renderScene, viewer.camera);
    }

    viewer.emit('render', dt);
    if (settings.stats) stats(renderer);
  },
  prepare: () => {
    clock = new THREE.Clock();
    clock.start();
    installVREffect(THREE);
    installVRControls(THREE);
    installVRController(THREE);
    viewer.renderer = renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setClearColor(backgroundColor);
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, settings.maxPixelRatio));
    renderer.setSize(windowSize.width, windowSize.height);
    renderer.sortObjects = false;

    const containerEl = document.createElement('div');
    containerEl.className = 'viewer';
    containerEl.appendChild(renderer.domElement);
    document.body.appendChild(containerEl);

    viewer.vrEffect = vrEffect = new THREE.VREffect(renderer);
    viewer.controls = controls = new THREE.VRControls(cameras.default);
    controls.standing = true;

    window.addEventListener('vrdisplaypresentchange', () => {
      viewer.emit('vr-present-change', vrEffect.isPresenting);
      if (!vrEffect.isPresenting) viewer.switchCamera('orthographic');
    }, false);

    const { render, resize } = postprocessing({
      renderer,
      camera: cameras.default,
      scene,
    });
    renderPostProcessing = render;
    resizePostProcessing = resize;
    windowSize.on('resize', onResize, false);
  },

  exitPresent() {
    if (!vrEffect.isPresenting) return;
    vrEffect.exitPresent();
    viewer.switchCamera('orthographic');
  },

  enterPresent() {
    if (vrEffect.isPresenting) return;
    vrEffect.requestPresent();
    setTimeout(() => {
      viewer.switchCamera('default');
      scene.add(viewer.camera);
    }, 10); // Delay switching 10ms to avoid flashing POV before overlay is displayed
  },

  toggleVR: async () => {
    if (vrEffect.isPresenting) {
      viewer.exitPresent();
    } else {
      viewer.enterPresent();
    }
  },

  switchCamera: (name) => {
    if (name === 'orthographic') {
      InstancedItem.switch(name);
      viewer.renderScene.fog = null;
    } else {
      InstancedItem.switch('perspective');
      viewer.renderScene.fog = viewer.fog;
    }
    viewer.camera = cameras[name];
  },
  vrEffect,
});

export default viewer;
<|endoftext|>


<commit_before>(function () {
  'use strict';

  /**
   * @param {String} hash
   * @returns {Object}
   */
  const parseHash = (hash) => {
    let parse = {};
    hash.substr((hash.indexOf('#') === 0) ? 1 : 0).split('&').forEach((segment) => {
      const delimiterIndex = segment.indexOf('=');
      if (delimiterIndex > 0) {
        // Key-value pair.
        parse[decodeURIComponent(segment.substring(0, delimiterIndex))] =
          decodeURIComponent(segment.substring(delimiterIndex + 1));
      } else if (delimiterIndex === -1) {
        // Flag.
        parse[decodeURIComponent(segment)] = true;
      } else {
        // Invalid.
      }
    });
    return parse;
  };

  /**
   * @param {Object} map
   * @returns {String}
   */
  const buildHash = (map) => {
    let segments = [];
    map.forEach((value, key) => {
      segments.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
    });
    return segments.join('&');
  };

  /**
   * @param {*} value
   * @returns {Boolean}
   */
  const isValidConfigValue = (value) => {
    return typeof value === 'string' && value.length > 0 && !isNaN(value);
  };

  /**
   * @param {String} configString
   * @returns {Object}
   */
  const parseLayerConfig = (configString) => {
    const layerConfigs = {};
    if (configString.length > 0) {
      configString.split('|').forEach((segment) => {
        const delimiterIndex = segment.indexOf(':');
        if (delimiterIndex > 0) {
          const layerId = segment.substring(0, delimiterIndex),
                layerProps = segment.substring(delimiterIndex + 1).split(',').map((value) => value.trim());
          layerConfigs[layerId] = {
            zIndex: isValidConfigValue(layerProps[0]) ? Number(layerProps[0]) : 0,
            visible: isValidConfigValue(layerProps[1]) ? Boolean(Number(layerProps[1])) : true,
            opacity: isValidConfigValue(layerProps[2]) ? Number(layerProps[2]) : 1
          };
        }
      });
    }
    return layerConfigs;
  };

  /**
   * @param {Object} layerConfigs
   * @returns {String}
   */
  const buildLayerConfigString = (layerConfigs) => {
    const segments = [];
    for (let layerId of Object.keys(layerConfigs)) {
      const layerConfig = layerConfigs[layerId];
      segments.push(`${layerId}:${layerConfig.zIndex},${layerConfig.visible},${layerConfig.opacity}`);
    }
    return segments.join('|');
  };

  /**
   * @param {String} extentString
   * @returns {Array.<Number>}
   */
  const parseExtent = (extentString) => {
    const extentStringSegments = extentString.split(',').map((value) => value.trim()).filter((value) => value.length > 0);
    let extent = null;
    if (extentStringSegments.length === 4) {
      extent = extentStringSegments.map((value) => Number(value));
    }
    return extent;
  };

  /**
   * @param {Array.<Number>} extent
   * @returns {String}
   */
  const buildExtentString = (extent) => {
    const segments = extent.slice(0, 4);
    return (segments.length === 4) ? segments.join(',') : '';
  };

  // @type {Object.<SourceType, LayerType>}
  const layerTypeMapping = {
    "BingMaps": "Tile",
    "CartoDB": "Tile",
    "Cluster": "Vector",
    "ImageCanvas": "Image",
    "ImageMapGuide": "Image",
    //"Image": "Image",
    "ImageStatic": "Image",
    "ImageVector": "Image",
    "ImageWMS": "Image",
    "MapQuest": "Tile",
    "OSM": "Tile",
    "Raster": "Image",
    //"Source", // Abstract
    "Stamen": "Tile",
    "TileArcGISRest": "Tile",
    "TileDebug": "Tile",
    "TileImage": "Tile",
    "TileJSON": "Tile",
    //"Tile", // Abstract
    "TileUTFGrid": "Tile",
    "TileWMS": "Tile",
    "Vector": "Vector",
    "VectorTile": "VectorTile",
    "WMTS": "Tile",
    "XYZ": "Tile",
    "Zoomify": "Tile"
  };

  const LayerListExpandedFlag = 'layer-list--expanded';

  const supportedSourceTypes = Object.keys(layerTypeMapping);

  const $mapContainer = $('#map');
  const $notificationContainer = $('#notifications');

  if ($mapContainer.length === 0 || $notificationContainer.length === 0) {
    throw new ReferenceError('Can not find elements.');
  }

  // Layer List Control.
  const LayerListControl = function (opt_options) {
    const options = opt_options || {};

    const button = document.createElement('button');
    button.className = 'material-icons';
    button.textContent = 'layers';

    const fakeControl = document.createElement('div');
    fakeControl.className = 'layer-list__toggle ol-control';
    fakeControl.appendChild(button);

    const layerListTitle = document.createElement('label');
    layerListTitle.className = 'layer-list__title';
    layerListTitle.textContent = 'Layers';

    const layerListBody = document.createElement('div');
    layerListBody.className = 'layer-list__body';

    const layerListContainer = document.createElement('div');
    layerListContainer.className = 'layer-list__container';
    layerListContainer.appendChild(layerListTitle);
    layerListContainer.appendChild(layerListBody);

    const handleToggleLayerList = function() {
      const viewportElement = this.getMap().getViewport();
      if (viewportElement.classList.contains(LayerListExpandedFlag)) {
        viewportElement.classList.remove(LayerListExpandedFlag);
      } else {
        viewportElement.classList.add(LayerListExpandedFlag);
      }
      //this.getMap().getView().setRotation(0);
    }.bind(this);

    button.addEventListener('click', handleToggleLayerList, false);
    button.addEventListener('touchstart', handleToggleLayerList, false);

    const element = document.createElement('div');
    element.className = 'layer-list ol-unselectable';
    element.appendChild(layerListContainer);
    element.appendChild(fakeControl);

    ol.control.Control.call(this, {
      element: element,
      target: options.target
    });
  };
  ol.inherits(LayerListControl, ol.control.Control);

  // Start map loading.
  const map = new ol.Map({
    target: $mapContainer[0],
    controls: ol.control.defaults().extend([
      new LayerListControl()
    ]),
    view: new ol.View({
      center: [0, 0],
      zoom: 0
    })
  });
  const mainLayerGroup = map.getLayerGroup();
  const mainLayerCollection = mainLayerGroup.getLayers();

  // Runtime data.
  let busy = false,
      loaded = false,
      loadedSourceUrl = null;

  const startWithHash = (hash) => {
    if (busy) {
      console.warn('Hash update while busy!');
      location.reload();
      return;
    }
    busy = true;
    console.info('Hash', hash);
    const parse = parseHash(hash);
    console.info('parse', parse);
    const sourceUrl = (parse.source || '').trim();
    console.info('sourceUrl', sourceUrl);
    const extra = {};
    const configString = (parse.config || '').trim();
    // Config String is optional.
    extra.layerConfigs = parseLayerConfig(configString);
    console.info('extra.layerConfigs', extra.layerConfigs);
    const extentString = (parse.extent || '').trim();
    // Extent String is optional.
    extra.extent = parseExtent(extentString);
    console.info('extra.extent', extra.extent);
    if (loaded && sourceUrl === loadedSourceUrl) {
      // Source Url didn't change.
      console.warn('Updating...');
      // Update layers.
      updateLayers.call(mainLayerCollection, extra);
      //! Update map view extent.
      console.log('Updated');
      busy = false;
    } else {
      console.warn('Loading new...');
      // Some resetting here.
      loaded = false;
      mainLayerCollection.clear();
      $notificationContainer.empty();
      $notificationContainer.append($('<span>').text(hash));
      // Source Url is necessary.
      if (sourceUrl.length === 0) {
        // No source url available.
        console.warn('No source url available.');
        $notificationContainer.append($('<span>').text('No source url available.'));
        return;
      }
      console.log('Downloading source file...');
      $notificationContainer.append($('<span>').text('Downloading source file...'));
      const JSONP_URL = (sourceUrl.indexOf('?') > -1) ? `${sourceUrl}&jsoncallback=?` : `${sourceUrl}?jsoncallback=?`;
      $.getJSON(sourceUrl)
      .fail((jqxhr, textStatus, error) => {
        const err = textStatus + ", " + error;
        console.error(err);
        $notificationContainer.append($('<span>').text(err));
      })
      .done((data, textStatus, jqxhr) => {
        console.info('Downloaded', data);
        $notificationContainer.empty();
        try {
          // Load layers.
          loadLayers.call(mainLayerCollection, data.layers);
          // Update layers.
          updateLayers.call(mainLayerCollection, extra);
          //! Update map view extent.
          loaded = true;
          loadedSourceUrl = sourceUrl;
          console.log('Loaded');
        } catch (err) {
          console.error(err);
          $notificationContainer.append($('<span>').text(err));
        }
        busy = false;
      });
    }
  };

  const loadLayers = function (layerConfigs) {
    if (!Array.isArray(layerConfigs)) {
      throw new TypeError('Expect layers to be an array.');
    }
    if (layerConfigs.length === 0) {
      throw new RangeError('There is no layer to load.');
    }
    // Create layers.
    for (let config of layerConfigs) {
      if (typeof config !== 'object') {
        throw new TypeError('Expect each layer to be an object.');
      }
      if (typeof config.id !== 'string') {
        throw new TypeError('Expect layer ID to be a string.');
      }
      if (typeof config.title !== 'string') {
        throw new TypeError('Expect layer title to be a string.');
      }
      if (typeof config.zIndex !== 'number') {
        throw new TypeError('Expect layer z-index to be a number.');
      }
      if (typeof config.visible !== 'boolean') {
        throw new TypeError('Expect layer visibility to be a boolean.');
      }
      if (typeof config.opacity !== 'number') {
        throw new TypeError('Expect layer opacity to be a number.');
      }
      if (typeof config.extent !== 'undefined') {
        if (!Array.isArray(config.extent)) {
          throw new TypeError('Expect layer extent to be an array.');
        }
        if (config.extent.length !== 4) {
          throw new RangeError('Expect layer extent to be an array of length 4.');
        }
        for (let cell of config.extent) {
          if (typeof cell !== 'number') {
            throw new TypeError('Expect layer extent to contain only numbers.');
          }
        }
      }
      if (typeof config.source !== 'object') {
        throw new TypeError('Expect layer source to be an object.');
      }
      if (typeof config.source.type !== 'string') {
        throw new TypeError('Expect layer source type to be a string.');
      }
      if (typeof config.source.options !== 'object') {
        throw new TypeError('Expect layer source options to be an object.');
      }
      if (supportedSourceTypes.indexOf(config.source.type) === -1) {
        throw new RangeError('Unsupported layer source type.');
      }
      const layerSource = new ol.source[config.source.type](config.source.options);
      console.info('layerSource', layerSource);
      const layerType = layerTypeMapping[config.source.type];
      const layer = new ol.layer[layerType]({
        id: config.id,
        title: config.title,
        source: layerSource,
        opacity: config.opacity,
        visible: config.visible,
        extent: config.extent,
        zIndex: config.zIndex
      });
      console.info('layer', layer);
      this.push(layer);
    }
  };

  const updateLayers = function (extra) {
    this.forEach((layer) => {
      const layerId = layer.get('id');
      if (extra.layerConfigs.hasOwnProperty(layerId)) {
        const extraConfig = extra.layerConfigs[layerId];
        if (extraConfig.hasOwnProperty('zIndex')) {
          layer.setZIndex(extraConfig.zIndex);
        }
        if (extraConfig.hasOwnProperty('visible')) {
          layer.setVisible(extraConfig.visible);
        }
        if (extraConfig.hasOwnProperty('opacity')) {
          layer.setOpacity(extraConfig.opacity);
        }
      }
    });
  };

  $(window).on('load', () => {
    startWithHash(location.hash);
    $(window).on('hashchange', () => {
      // Need to check if Source Url has been changed.
      startWithHash(location.hash);
    });
  });
})();
<commit_msg>Test if map is accessible.<commit_after>(function () {
  'use strict';

  /**
   * @param {String} hash
   * @returns {Object}
   */
  const parseHash = (hash) => {
    let parse = {};
    hash.substr((hash.indexOf('#') === 0) ? 1 : 0).split('&').forEach((segment) => {
      const delimiterIndex = segment.indexOf('=');
      if (delimiterIndex > 0) {
        // Key-value pair.
        parse[decodeURIComponent(segment.substring(0, delimiterIndex))] =
          decodeURIComponent(segment.substring(delimiterIndex + 1));
      } else if (delimiterIndex === -1) {
        // Flag.
        parse[decodeURIComponent(segment)] = true;
      } else {
        // Invalid.
      }
    });
    return parse;
  };

  /**
   * @param {Object} map
   * @returns {String}
   */
  const buildHash = (map) => {
    let segments = [];
    map.forEach((value, key) => {
      segments.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
    });
    return segments.join('&');
  };

  /**
   * @param {*} value
   * @returns {Boolean}
   */
  const isValidConfigValue = (value) => {
    return typeof value === 'string' && value.length > 0 && !isNaN(value);
  };

  /**
   * @param {String} configString
   * @returns {Object}
   */
  const parseLayerConfig = (configString) => {
    const layerConfigs = {};
    if (configString.length > 0) {
      configString.split('|').forEach((segment) => {
        const delimiterIndex = segment.indexOf(':');
        if (delimiterIndex > 0) {
          const layerId = segment.substring(0, delimiterIndex),
                layerProps = segment.substring(delimiterIndex + 1).split(',').map((value) => value.trim());
          layerConfigs[layerId] = {
            zIndex: isValidConfigValue(layerProps[0]) ? Number(layerProps[0]) : 0,
            visible: isValidConfigValue(layerProps[1]) ? Boolean(Number(layerProps[1])) : true,
            opacity: isValidConfigValue(layerProps[2]) ? Number(layerProps[2]) : 1
          };
        }
      });
    }
    return layerConfigs;
  };

  /**
   * @param {Object} layerConfigs
   * @returns {String}
   */
  const buildLayerConfigString = (layerConfigs) => {
    const segments = [];
    for (let layerId of Object.keys(layerConfigs)) {
      const layerConfig = layerConfigs[layerId];
      segments.push(`${layerId}:${layerConfig.zIndex},${layerConfig.visible},${layerConfig.opacity}`);
    }
    return segments.join('|');
  };

  /**
   * @param {String} extentString
   * @returns {Array.<Number>}
   */
  const parseExtent = (extentString) => {
    const extentStringSegments = extentString.split(',').map((value) => value.trim()).filter((value) => value.length > 0);
    let extent = null;
    if (extentStringSegments.length === 4) {
      extent = extentStringSegments.map((value) => Number(value));
    }
    return extent;
  };

  /**
   * @param {Array.<Number>} extent
   * @returns {String}
   */
  const buildExtentString = (extent) => {
    const segments = extent.slice(0, 4);
    return (segments.length === 4) ? segments.join(',') : '';
  };

  // @type {Object.<SourceType, LayerType>}
  const layerTypeMapping = {
    "BingMaps": "Tile",
    "CartoDB": "Tile",
    "Cluster": "Vector",
    "ImageCanvas": "Image",
    "ImageMapGuide": "Image",
    //"Image": "Image",
    "ImageStatic": "Image",
    "ImageVector": "Image",
    "ImageWMS": "Image",
    "MapQuest": "Tile",
    "OSM": "Tile",
    "Raster": "Image",
    //"Source", // Abstract
    "Stamen": "Tile",
    "TileArcGISRest": "Tile",
    "TileDebug": "Tile",
    "TileImage": "Tile",
    "TileJSON": "Tile",
    //"Tile", // Abstract
    "TileUTFGrid": "Tile",
    "TileWMS": "Tile",
    "Vector": "Vector",
    "VectorTile": "VectorTile",
    "WMTS": "Tile",
    "XYZ": "Tile",
    "Zoomify": "Tile"
  };

  const LayerListExpandedFlag = 'layer-list--expanded';

  const supportedSourceTypes = Object.keys(layerTypeMapping);

  const $mapContainer = $('#map');
  const $notificationContainer = $('#notifications');

  if ($mapContainer.length === 0 || $notificationContainer.length === 0) {
    throw new ReferenceError('Can not find elements.');
  }

  // Layer List Control.
  const LayerListControl = function (opt_options) {
    const options = opt_options || {};

    const button = document.createElement('button');
    button.className = 'material-icons';
    button.textContent = 'layers';

    const fakeControl = document.createElement('div');
    fakeControl.className = 'layer-list__toggle ol-control';
    fakeControl.appendChild(button);

    const layerListTitle = document.createElement('label');
    layerListTitle.className = 'layer-list__title';
    layerListTitle.textContent = 'Layers';

    const layerListBody = document.createElement('div');
    layerListBody.className = 'layer-list__body';

    const layerListContainer = document.createElement('div');
    layerListContainer.className = 'layer-list__container';
    layerListContainer.appendChild(layerListTitle);
    layerListContainer.appendChild(layerListBody);

    const mainLayerGroup = this.getMap().getLayerGroup();
    const mainLayerCollection = mainLayerGroup.getLayers();

    const handleToggleLayerList = function() {
      const viewportElement = this.getMap().getViewport();
      if (viewportElement.classList.contains(LayerListExpandedFlag)) {
        viewportElement.classList.remove(LayerListExpandedFlag);
      } else {
        viewportElement.classList.add(LayerListExpandedFlag);
      }
      console.info('mainLayerCollection', mainLayerCollection);
      //this.getMap().getView().setRotation(0);
    }.bind(this);

    button.addEventListener('click', handleToggleLayerList, false);
    button.addEventListener('touchstart', handleToggleLayerList, false);

    const element = document.createElement('div');
    element.className = 'layer-list ol-unselectable';
    element.appendChild(layerListContainer);
    element.appendChild(fakeControl);

    ol.control.Control.call(this, {
      element: element,
      target: options.target
    });
  };
  ol.inherits(LayerListControl, ol.control.Control);

  // Start map loading.
  const map = new ol.Map({
    target: $mapContainer[0],
    controls: ol.control.defaults().extend([
      new LayerListControl()
    ]),
    view: new ol.View({
      center: [0, 0],
      zoom: 0
    })
  });
  const mainLayerGroup = map.getLayerGroup();
  const mainLayerCollection = mainLayerGroup.getLayers();

  // Runtime data.
  let busy = false,
      loaded = false,
      loadedSourceUrl = null;

  const startWithHash = (hash) => {
    if (busy) {
      console.warn('Hash update while busy!');
      location.reload();
      return;
    }
    busy = true;
    console.info('Hash', hash);
    const parse = parseHash(hash);
    console.info('parse', parse);
    const sourceUrl = (parse.source || '').trim();
    console.info('sourceUrl', sourceUrl);
    const extra = {};
    const configString = (parse.config || '').trim();
    // Config String is optional.
    extra.layerConfigs = parseLayerConfig(configString);
    console.info('extra.layerConfigs', extra.layerConfigs);
    const extentString = (parse.extent || '').trim();
    // Extent String is optional.
    extra.extent = parseExtent(extentString);
    console.info('extra.extent', extra.extent);
    if (loaded && sourceUrl === loadedSourceUrl) {
      // Source Url didn't change.
      console.warn('Updating...');
      // Update layers.
      updateLayers.call(mainLayerCollection, extra);
      //! Update map view extent.
      console.log('Updated');
      busy = false;
    } else {
      console.warn('Loading new...');
      // Some resetting here.
      loaded = false;
      mainLayerCollection.clear();
      $notificationContainer.empty();
      $notificationContainer.append($('<span>').text(hash));
      // Source Url is necessary.
      if (sourceUrl.length === 0) {
        // No source url available.
        console.warn('No source url available.');
        $notificationContainer.append($('<span>').text('No source url available.'));
        return;
      }
      console.log('Downloading source file...');
      $notificationContainer.append($('<span>').text('Downloading source file...'));
      const JSONP_URL = (sourceUrl.indexOf('?') > -1) ? `${sourceUrl}&jsoncallback=?` : `${sourceUrl}?jsoncallback=?`;
      $.getJSON(sourceUrl)
      .fail((jqxhr, textStatus, error) => {
        const err = textStatus + ", " + error;
        console.error(err);
        $notificationContainer.append($('<span>').text(err));
      })
      .done((data, textStatus, jqxhr) => {
        console.info('Downloaded', data);
        $notificationContainer.empty();
        try {
          // Load layers.
          loadLayers.call(mainLayerCollection, data.layers);
          // Update layers.
          updateLayers.call(mainLayerCollection, extra);
          //! Update map view extent.
          loaded = true;
          loadedSourceUrl = sourceUrl;
          console.log('Loaded');
        } catch (err) {
          console.error(err);
          $notificationContainer.append($('<span>').text(err));
        }
        busy = false;
      });
    }
  };

  const loadLayers = function (layerConfigs) {
    if (!Array.isArray(layerConfigs)) {
      throw new TypeError('Expect layers to be an array.');
    }
    if (layerConfigs.length === 0) {
      throw new RangeError('There is no layer to load.');
    }
    // Create layers.
    for (let config of layerConfigs) {
      if (typeof config !== 'object') {
        throw new TypeError('Expect each layer to be an object.');
      }
      if (typeof config.id !== 'string') {
        throw new TypeError('Expect layer ID to be a string.');
      }
      if (typeof config.title !== 'string') {
        throw new TypeError('Expect layer title to be a string.');
      }
      if (typeof config.zIndex !== 'number') {
        throw new TypeError('Expect layer z-index to be a number.');
      }
      if (typeof config.visible !== 'boolean') {
        throw new TypeError('Expect layer visibility to be a boolean.');
      }
      if (typeof config.opacity !== 'number') {
        throw new TypeError('Expect layer opacity to be a number.');
      }
      if (typeof config.extent !== 'undefined') {
        if (!Array.isArray(config.extent)) {
          throw new TypeError('Expect layer extent to be an array.');
        }
        if (config.extent.length !== 4) {
          throw new RangeError('Expect layer extent to be an array of length 4.');
        }
        for (let cell of config.extent) {
          if (typeof cell !== 'number') {
            throw new TypeError('Expect layer extent to contain only numbers.');
          }
        }
      }
      if (typeof config.source !== 'object') {
        throw new TypeError('Expect layer source to be an object.');
      }
      if (typeof config.source.type !== 'string') {
        throw new TypeError('Expect layer source type to be a string.');
      }
      if (typeof config.source.options !== 'object') {
        throw new TypeError('Expect layer source options to be an object.');
      }
      if (supportedSourceTypes.indexOf(config.source.type) === -1) {
        throw new RangeError('Unsupported layer source type.');
      }
      const layerSource = new ol.source[config.source.type](config.source.options);
      console.info('layerSource', layerSource);
      const layerType = layerTypeMapping[config.source.type];
      const layer = new ol.layer[layerType]({
        id: config.id,
        title: config.title,
        source: layerSource,
        opacity: config.opacity,
        visible: config.visible,
        extent: config.extent,
        zIndex: config.zIndex
      });
      console.info('layer', layer);
      this.push(layer);
    }
  };

  const updateLayers = function (extra) {
    this.forEach((layer) => {
      const layerId = layer.get('id');
      if (extra.layerConfigs.hasOwnProperty(layerId)) {
        const extraConfig = extra.layerConfigs[layerId];
        if (extraConfig.hasOwnProperty('zIndex')) {
          layer.setZIndex(extraConfig.zIndex);
        }
        if (extraConfig.hasOwnProperty('visible')) {
          layer.setVisible(extraConfig.visible);
        }
        if (extraConfig.hasOwnProperty('opacity')) {
          layer.setOpacity(extraConfig.opacity);
        }
      }
    });
  };

  $(window).on('load', () => {
    startWithHash(location.hash);
    $(window).on('hashchange', () => {
      // Need to check if Source Url has been changed.
      startWithHash(location.hash);
    });
  });
})();
<|endoftext|>


<commit_before>// const prod = true;
const prod = false;

module.exports = {
  wpyExt: '.wpy',
  build: {
    web: {
    }
  },
  eslint: true,
  'autoprefixer': {
    filter: /\.(wxss|css)$/,
    config: {
      browsers: ['last 11 iOS versions']
    }
  },
  compilers: {
    sass: {
      outputStyle: 'expanded'
    },
    babel: {
      sourceMap: true,
      presets: [
        'es2015',
        'stage-1'
      ],
      plugins: [
        'transform-decorators-legacy',
        'transform-export-extensions',
        'syntax-export-extensions'
      ]
    }
  },
  plugins: {
  }
};

if (prod) {
  delete module.exports.compilers.babel.sourcesMap;
  // 压缩sass
  module.exports.compilers['sass'] = {outputStyle: 'compressed'};

  // 压缩js
  module.exports.plugins = {
    uglifyjs: {
      filter: /\.js$/,
      config: {
      }
    },
    imagemin: {
      filter: /\.(jpg|png|jpeg)$/,
      config: {
        jpg: {
          quality: 80
        },
        png: {
          quality: 80
        }
      }
    }
  }
}
<commit_msg>FIX:修订编译模式<commit_after>const prod = process.env.NODE_ENV === 'production';

module.exports = {
  wpyExt: '.wpy',
  build: {
    web: {
    }
  },
  eslint: true,
  'autoprefixer': {
    filter: /\.(wxss|css)$/,
    config: {
      browsers: ['last 11 iOS versions']
    }
  },
  compilers: {
    sass: {
      outputStyle: 'expanded'
    },
    babel: {
      sourceMap: true,
      presets: [
        'es2015',
        'stage-1'
      ],
      plugins: [
        'transform-decorators-legacy',
        'transform-export-extensions',
        'syntax-export-extensions'
      ]
    }
  },
  plugins: {
  }
};

if (prod) {
  delete module.exports.compilers.babel.sourcesMap;
  // 压缩sass
  module.exports.compilers['sass'] = {outputStyle: 'compressed'};

  // 压缩js
  module.exports.plugins = {
    uglifyjs: {
      filter: /\.js$/,
      config: {
      }
    },
    imagemin: {
      filter: /\.(jpg|png|jpeg)$/,
      config: {
        jpg: {
          quality: 80
        },
        png: {
          quality: 80
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>/* istanbul ignore next */
export default {
  batteries: {
    name: 'Store electricity in batteries',
    description: `
      You can give an additional 20% of all households a battery that can store
      19.8 kWh of electricity and can be charged using grid power or solar.
    `
  },
  buildOffshoreTurbines: {
    name: 'Build 250 offshore turbines',
    header: 'Wind',
    description: `
      You can build 250 wind turbines of 3 MWe each. Wind turbines produce
      less electricity per MWe than fossil-fired or nuclear plants do because
      of varying wind conditions. Offshore wind turbines produce at maximum
      capacity ~40% of the time, if there is not too much need for maintenance.
    `
  },
  cheaperOil: {
    name: 'Make oil cheaper',
    header: 'Cheaper oil',
    description: `
      The price of oil is tracked by many and discussed on a daily basis in
      the news. Does it have an impact of the CO2 emissions of our
      energy system?
    `
  },
  closeConventionalCoal: {
    name: 'Close a conventional coal power plant',
    description: `
      You can close a conventional 800 megawatt electric (MWe)
      ultra-supercritical pulverized coal-fired plant. These plants are not
      build anymore in rich countries due to environmental restrictions. The
      Netherlands still possesses 1,200 MW of production capacity from this type
      of power plant.
    `
  },
  closeModernCoal: {
    name: 'Close a modern coal power plant',
    description: `
      You can close a modern 800 megawatt electric (MWe) ultra-supercritical
      pulverized coal-fired plant. Of all types of power plants, coal and
      lignite-fired contribute most to pollution of the environment. This is the
      most common type of modern coal-fired power plant in rich countries, with
      relatively strict regulations for air pollution.
    `
  },
  electricTrucks: {
    name: 'Increase electric trucks with 20%',
    header: '20% electric trucks',
    description: `
      Trucks need to drive longer distances and sometimes have less time to
      stop and recharge than cars. Siemens is testing electric trucks that can
      be charged using a catenary while driving on the highway.
    `
  },
  electricVehicles: {
    name: 'Add one million electric cars',
    header: 'Travel by electric car',
    description: `
      These cars use less than half the energy from ‘well to wheels’ of good
      diesel cars and are even more efficient compared to gasoline engines.
      They are emission free, which is a bonus to the environment in our cities
      and villages!
    `
  },
  fossilCarEfficiency: {
    name: 'Make fossil cars more efficient',
    header: 'Fossil cars more efficient',
    description: `
      New cars become almost 2% more efficient every year. To reduce
      CO2 emissions, it is important that people replace their
      old puffing machines with shiny new ones as technology improves.
    `
  },
  greenGas: {
    name: 'Make 10% of gas green',
    header: '10% green gas',
    description: `
      Green gas is biogas that has been upgraded to natural gas quality and can
      be fed into the gas mains. Biogas is conventionally produced by bacteria
      that digest biological material. In the future, such gas may be produced
      by ‘gasification’ of biomass.
    `
  },
  householdInsulationNew: {
    name: 'Double insulation of new houses',
    header: 'Insulate new houses',
    description: `
      Newly built houses – namely those build after 1990 – already have a higher
      degree of insulation than older homes. In general, they have been built
      with cavity walls containing insulation, insulated glazing, roofs and
      floors. What if we insulate these houses further to their maximum
      potential?
    `
  },
  householdInsulationOld: {
    name: 'Double insulation of existing houses',
    header: 'Insulate existing houses',
    description: `
      The most important insulation measures are roof, wall, floor insulation,
      and insulated glazing. These four account for roughly 75% of the total
      potential savings. What if we can double the average insulation level
      of houses that were built before 1990?
    `
  },
  hybridHeatPumps: {
    name: 'Use hybrid heat pumps',
    description: `
      This heater is a combination of an electric heat pump that draws its heat
      from the outside air and an efficient conventional gas-fired boiler.
      Essentially, the hybrid heat pump offers a way to strongly reduce natural
      gas demand for heating, while buying time for grid management companies to
      reinforce grids.
    `
  },
  ledLightingHouseholds: {
    name: 'Use LED light bulbs',
    description: `
      Replace all the light bulbs in households with LED-lights. A old-fashioned
      incandescent light bulb lasts for 1,000 hours, but LED-lights last for
      50,000 hours! So, less changing as well.
    `
  },
  ledLightingOffices: {
    name: 'Use LED light bulbs in offices',
    description: `
      You can turn 100% of the lights at offices into LED lights. These lights
      also need to be replaced a lot less often that the old fashioned light
      bulbs, so you will also save money!
    `
  },
  lngShips: {
    name: 'Use only LNG ships',
    header: 'LNG ships',
    description: `
      Compared to diesel ships an LNG ship has a 50% advantage in its emissions
      of sulfur particles, and a 60% advantage in particulate matter. Because of
      methane slip at the ship's engine, the CO2 difference is very
      small.
    `
  },
  lngTrucks: {
    name: 'Use only LNG trucks',
    header: 'LNG trucks',
    description: `
      You can replace diesel trucks with electric trucks, but you may also
      want to replace part of the fleet with liquified natural gas (LNG).
      This fuel emits about 30% less CO2 per km.
    `
  },
  refineryEfficiency: {
    name: 'Make refineries 1% per year more efficient',
    header: 'More efficient refineries',
    description: `
      Refineries use a lot of energy breaking down crude oil into oil products.
      In recent decades, these plants have become a lot more efficient. What
      if we keep making them 1% more efficient each year?
    `
  },
  replaceOldHouses: {
    name: 'Replace old with new houses',
    description: `
      One million old houses will be replaced with newly build houses. Newly
      build houses have much more stricter regulations with regards to
      insulation.
    `
  },
  solarPanels: {
    name: 'Install solar PV panels',
    description: `
      With a solar panel on your roof, you will turn yourself from a mere
      energy consumer into a producer. What if all houses
      would be equiped with solar PV panels?
    `
  },
  travelByTrain: {
    name: '5% of car journeys instead done by train',
    header: 'Travel by train',
    description: `
      People spent a lot of energy driving around in cars. What if we managed
      to convice 5% to use the train instead of a car? This will save energy,
      CO2 emissions, costs and shorten traffic jams!
    `
  }
};
<commit_msg>Translations to Dutch<commit_after>export default {
  batteries: {
    name: 'Thuisbatterijen',
    description: `
      Geef 20% van alle huishoudens een thuisbatterij die 19.8 kWh aan elektriciteit
      kan opslaan. Hiermee kunnen overschotten wind- en zonnestroom op een later
      tijdstip worden benut.
    `
  },
  buildOffshoreTurbines: {
    name: 'Bouw 250 offshore windturbines',
    header: 'Wind op zee',
    description: `
      Bouw 250 windturbines van 3 MWe. Windturbines produceren
      minder elektriciteit per MWe opgesteld vermogen dan fossiele centrales omdat het
      niet altijd waait. Windturbines op zee produceren ~40% van de tijd op vol vermogen.
    `
  },
  cheaperOil: {
    name: 'Make oil cheaper',
    header: 'Cheaper oil',
    description: `
      The price of oil is tracked by many and discussed on a daily basis in
      the news. Does it have an impact of the CO2 emissions of our
      energy system?
    `
  },
  closeConventionalCoal: {
    name: 'Sluit een conventionele kolencentrale',
    description: `
      Sluit een conventionele 800 megawatt (MWe) kolencentrale. De centrales worden
      niet meer gebouwd in welvarende landen vanwegen strengere milieuwetgevingen.
    `
  },
  closeModernCoal: {
    name: 'Sluit een moderne kolencentrale',
    description: `
      Sluit een moderne 800 megawatt (MWe) ckolencentrale. Dit is het meest
      gebruikelijke type kolencentrale in welvarende landen welke voldoet aan
      de relatief strikte milieuwetgevingen.
    `
  },
  electricTrucks: {
    name: '20% meer elektrische vrachtwagens',
    header: '20% elektrische vrachtwagens',
    description: `
      In Nederland verbruiken vrachtwagens ongeveer evenveel energie als autos.
      Wat zou het potentieel zijn voor elektrificatie van het vrachtvervoer?
    `
  },
  electricVehicles: {
    name: 'Een miljoen extra elektrische autos',
    header: 'Reis per elektrische auto',
    description: `
      Elektrische autos gebruiken maar de helft van de ‘well-to-wheel’ energie in
      vergelijking tot autos op benzine of diesel.
      Ze veroorzaken ook geen directe uitstoot dus zijn lekker schoon voor jou stad of dorp!
    `
  },
  fossilCarEfficiency: {
    name: 'Maak fossiele autos efficienter',
    header: 'Fossiele autos efficienter',
    description: `
      Nieuwe autos worden elk jaar bijna 2% efficienter. Om CO2-uitstoot te
      reduceren kun je beter in een efficientere nieuwe auto rijden.
    `
  },
  greenGas: {
    name: 'Maak 10% van het gas groen',
    header: '10% groengas',
    description: `
      Groengas is biogas dat opgewaardeerd is om bijmenging in het gasnet mogelijk te maken.
      Biogas kan worden gemaakt door vergisting of vergassing van biomassa.
    `
  },
  householdInsulationNew: {
    name: 'Dubbele isolatie van nieuwe huizen',
    header: 'Isolatie nieuwe huizen',
    description: `
      Nieuwbouw huizen – gebouwd na 1991 – hebben al een hogere isolatiegraad dan oudere huizen.
      In het algemeen hebben deze huizen geisoleerde spouwmuren, dubbelglas, en isolatie in vloeren
      en daken. Wat is de impact van het nog verder (maximaal) isoleren van deze huizen?
    `
  },
  householdInsulationOld: {
    name: 'Dubbele isolatie van oude huizen',
    header: 'Isolatie oude huizen',
    description: `
      De belangrijkste isolatiemaatregelen zijn dak-, muur-, vloerisolatie,
      en dubbelglas. Deze vier zijn verantwoordelijk voor 75% van de potentiële
      besparingen. Wat als we de gemiddelde isolatiegraad van huizen van vóór 1991
      konden verdubbelen?
    `
  },
  hybridHeatPumps: {
    name: 'Hybride warmtepompen',
    description: `
      Deze verwarmingsoptie is een combinatie van een kleine elektrische warmtepomp
      en een hoge rendementsketel op gas.
      Wat als elk huis met deze technologie zou worden verwarmd?
    `
  },
  ledLightingHouseholds: {
    name: 'Gebruik van LED-lampen',
    description: `
      Vervang alle lampen met LED-lampen in woningen. Ouderwetse gloeilampen hebben
      gemiddeld 1000 branduren, maar LED-lampen kunnen wel 50000 mee gaan. Daarnaast zijn
      ze ook nog eens 10 keer efficienter!
    `
  },
  ledLightingOffices: {
    name: 'Gebruik van LED-lampen in kantoren',
    description: `
      Vervang alle lampen met LED-lampen in kantoren en andere niet-residentiële gebouwen.
      LED-lampen zijn wel 10 keer zo efficient als gloeilampen en gaan ook nog eens langer mee!
    `
  },
  lngShips: {
    name: 'Alleen nog LNG-schepen',
    header: 'Schepen op LNG',
    description: `
      Vervang diesel met 'liquified natural gas' (LNG) voor scheepvaart.
      In vergelijking tot dieselschepen stoten shepen die op LNG
      varen 50% minder zwavel en 60% minder fijnstof uit. Het verschil in CO2-
      uitstoot is echter zeer klein.
    `
  },
  lngTrucks: {
    name: 'Alleen nog LNG-vrachtwagens',
    header: 'Vrachtwagens op LNG',
    description: `
      Vervang diesel met 'liquified natural' gas (LNG) voor vrachtvervoer op de weg.
      Deze brandstof reduceert de CO2 per km met 30%.
    `
  },
  refineryEfficiency: {
    name: '1% efficientie-toename per jaar voor raffinaderijen',
    header: 'Efficientere raffinaderijen',
    description: `
      Raffinaderijen gebruiken veel energie om olie om te zetten in olieproducten.
      Wat gebeurt er als deze energieslurpers de komende 33 jaar elk jaar 1% efficienter maken?
    `
  },
  replaceOldHouses: {
    name: 'Oude met nieuwe huizen vervangen',
    description: `
      Vervang een miljoen oude huizen met nieuwe, energiezuinigere huizen.
    `
  },
  solarPanels: {
    name: 'Zonnepanelen op huizen',
    description: `
      Met een zonnepaneel op je dak ben je niet alleen consument maar ook producent van stroom.
      Wat als we if alle huizen met zonnepanelen zouden bedekken?
    `
  },
  travelByTrain: {
    name: '5% van de autoritten per trein',
    header: 'Reizen per trein',
    description: `
      Autovervoer kost veel energie. Wat als we mensen kunnen overhalen om 5% (meer) van
      hun personenvervoer met de trein te doen? Dit bespaart energie, CO2-uitstoot,
      kosten en scheelt files.
    `
  }
};
<|endoftext|>


<commit_before>function newArray () { return []; };

var mutatorOpt = {
  check: function (v, path) {
    if (!_.isArray(v))
      throw new Meteor.Error(JSON.stringify(path) + ' is not an array');

    return true;
  }
};

var mutators = ['copyWithin', 'fill', 'pop', 'push', 'reverse', 'shift',
  'sort', 'splice', 'unshift'];

ArrayMethods = _.reduce(mutators, function (acc, v) {
  var method = Array.prototype[v];
  if (method)
    acc[v] = _.partial(Helpers.applyMutator, Array.prototype[v], mutatorOpt);

  return acc;
}, {});
<commit_msg>Remove copyWithin and fill array methods<commit_after>function newArray () { return []; };

var mutatorOpt = {
  check: function (v, path) {
    if (!_.isArray(v))
      throw new Meteor.Error(JSON.stringify(path) + ' is not an array');

    return true;
  }
};

var mutators = ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'];

ArrayMethods = _.reduce(mutators, function (acc, v) {
  var method = Array.prototype[v];
  if (method)
    acc[v] = _.partial(Helpers.applyMutator, Array.prototype[v], mutatorOpt);

  return acc;
}, {});
<|endoftext|>


<commit_before>const strings = {
  homeDeliveryMeals: {
    key: 'homeDeliveryMeals',
    msg: 'You may qualify for Home Delivery Meals',
    icon: 'icons/noun_744795_cc.png',
    url: 'http://www.smchealth.org/general-information/where-seniors-can-go-nutritious-meals'
  },
  freeSchoolMeals: {
    key: 'freeSchoolMeals',
    msg: 'You may qualify for free school meals',
    icon: 'icons/noun_614012_cc.png',
    url: 'http://www.smcoe.org/about-smcoe/districts-and-schools/'
  },
  reducedPriceSchoolMeals: {
    key: 'reducedPriceSchoolMeals',
    msg: 'You may qualify for reduced priced meals at school',
    icon: 'icons/noun_1048458_cc.png',
    url: 'http://www.smcoe.org/about-smcoe/districts-and-schools/'
  },
  adjunctWIC: {
    key: 'adjunctWIC',
    msg: 'You adjunctly qualify for WIC',
    icon: 'icons/noun_851501_cc.png',
    url: 'http://www.smchealth.org/wic'
  },
  WIC: {
    key: 'WIC',
    msg: 'You are WIC eligible',
    icon: 'icons/noun_851501_cc.png',
    url: 'http://www.smchealth.org/wic'
  },
  CalFresh: {
    key: 'CalFresh',
    msg: 'You may qualify for CalFresh',
    icon: 'icons/noun_1113355_cc.png',
    url: 'https://getcalfresh.org/'
  },
  notEligible: {
    key: 'notEligible',
    msg: 'Your income does not meet the eligibility requirements for the Federal Food Programs but here are local food resources',
    icon: 'icons/Life-Perseverance-Bricks-Nature-Determination-335446.jpg'
  }
};

const missing = (key) => {
  return {
    key: 'missing',
    msg: `ERROR: MISSING STRING DEFINITION FOR: ${key}`,
    icon: ""
  }
};

let __t = function(key) {
  return strings[key || ''] || missing(key || '');
};

export {__t};
<commit_msg>update the icon file too<commit_after>const strings = {
  homeDeliveryMeals: {
    key: 'homeDeliveryMeals',
    msg: 'You may qualify for Home Delivery Meals',
    icon: 'icons/noun_744795_cc.png',
    url: 'http://www.smchealth.org/general-information/where-seniors-can-go-nutritious-meals'
  },
  freeSchoolMeals: {
    key: 'freeSchoolMeals',
    msg: 'You may qualify for free school meals',
    icon: 'icons/noun_614012_cc.png',
    url: 'http://www.smcoe.org/about-smcoe/districts-and-schools/'
  },
  reducedPriceSchoolMeals: {
    key: 'reducedPriceSchoolMeals',
    msg: 'You may qualify for reduced priced meals at school',
    icon: 'icons/noun_1048458_cc.png',
    url: 'http://www.smcoe.org/about-smcoe/districts-and-schools/'
  },
  adjunctWIC: {
    key: 'adjunctWIC',
    msg: 'You adjunctly qualify for WIC',
    icon: 'icons/noun_851501_cc.png',
    url: 'http://www.smchealth.org/wic'
  },
  WIC: {
    key: 'WIC',
    msg: 'You are WIC eligible',
    icon: 'icons/noun_851501_cc.png',
    url: 'http://www.smchealth.org/wic'
  },
  CalFresh: {
    key: 'CalFresh',
    msg: 'You may qualify for CalFresh',
    icon: 'icons/CalFresh.png',
    url: 'https://getcalfresh.org/'
  },
  notEligible: {
    key: 'notEligible',
    msg: 'Your income does not meet the eligibility requirements for the Federal Food Programs but here are local food resources',
    icon: 'icons/Life-Perseverance-Bricks-Nature-Determination-335446.jpg'
  }
};

const missing = (key) => {
  return {
    key: 'missing',
    msg: `ERROR: MISSING STRING DEFINITION FOR: ${key}`,
    icon: ""
  }
};

let __t = function(key) {
  return strings[key || ''] || missing(key || '');
};

export {__t};
<|endoftext|>


<commit_before>import assert from 'assert';
import { tester } from 'graphql-tester';

const test = tester({
  url: 'http://localhost:3000/graphql',
  contentType: 'application/json'
});

const validLink = { from: 'moscow', to: 'helsinki' };
const createLink = async (link) => {

  const query = JSON.stringify({
    query: 'mutation ($link:TransitLinkInput!) {link(link:$link) {from {name,lat,lng}, to {name,lat,lng}}}',
    variables: { link }
  });

  const response = await test(query);
  assert(response.success == true);
  assert(response.status == 200);
  assert(response.data.link.from && response.data.link.to);
  return response;

};

describe('data/queries/links', () => {

  it('should create new link', async () => {
    createLink(validLink);
  });

  it('returns links by locality id', async () => {

    createLink(validLink);

    const query = JSON.stringify({
      query: 'query {links(localityId:1) {from {name,lat,lng}, to {name,lat,lng}}}',
      variables: {}
    });

    const response = await test(query);

    assert(response.success == true);
    assert(response.status == 200);
    assert(response.data.links.length > 0, '0 links by id results');

  });

  it('returns link by id', async () => {

    createLink(validLink);

    const query = JSON.stringify({
      query: 'query {link(id:1) {from {name,lat,lng}, to {name,lat,lng}}}',
      variables: {}
    });

    const response = await test(query);

    assert(response.success == true);
    assert(response.status == 200);
    assert(response.data.link.from && response.data.link.to);

  });

});
<commit_msg>Fixed link query tests<commit_after>import assert from 'assert';
import { tester } from 'graphql-tester';

const test = tester({
  url: 'http://localhost:3000/graphql',
  contentType: 'application/json'
});

const validLink = { from: 'moscow', to: 'helsinki' };
const createLink = async (link) => {

  const query = JSON.stringify({
    query: 'mutation ($link:TransitLinkInput!) {link(link:$link) {from {name,lat,lng}, to {name,lat,lng}}}',
    variables: { link }
  });

  const response = await test(query);
  assert(response.success == true);
  assert(response.status == 200);
  assert(response.data.link.from && response.data.link.to);
  return response;

};

describe('data/queries/links', () => {

  it('should create new link', async () => {
    await createLink(validLink);
  });

  it('returns links by locality id', async () => {

    await createLink(validLink);

    const query = JSON.stringify({
      query: 'query {links(localityId:1) {from {name,lat,lng}, to {name,lat,lng}}}',
      variables: {}
    });

    const response = await test(query);

    assert(response.success == true);
    assert(response.status == 200);
    assert(response.data.links.length > 0, '0 links by id results');

  });

  it('returns link by id', async () => {

    await createLink(validLink);

    const query = JSON.stringify({
      query: 'query {link(id:1) {from {name,lat,lng}, to {name,lat,lng}}}',
      variables: {}
    });

    const response = await test(query);

    assert(response.success == true);
    assert(response.status == 200);
    assert(response.data.link.from && response.data.link.to);

  });

});
<|endoftext|>


<commit_before>describe('Wiggle', function() {
  var wiggle;
  const screens = {
    desktop: {
      minWidth: 992,
      name: 'desktop'
    },
    tablet: {
      minWidth: 768,
      maxWidth: 991,
      name: 'tablet'
    },
    mobile: {
      maxWidth: 767,
      name: 'mobile'
    }
  }

  function mockActiveScreen(name) {
    size = screens[name].minWidth || screens[name].maxWidth;
    window.matchMedia = function(query) {
      return {
        matches: query.indexOf(size.toString()) !== -1
      }
    };
  }

  function waitResize(fn) {
    setTimeout(fn, 50);
  }

  beforeEach(function() {
    mockActiveScreen('desktop');

    wiggle = Wiggle.init([
      screens.desktop,
      screens.tablet,
      screens.mobile
    ]);
  });

  it('Wiggle should be initialized', function() {
    expect(wiggle.on).toEqual(jasmine.any(Function));
    expect(wiggle.queueOn).toEqual(jasmine.any(Function));
    expect(wiggle.off).toEqual(jasmine.any(Function));
    expect(wiggle.queueOff).toEqual(jasmine.any(Function));
    expect(wiggle.is).toEqual(jasmine.any(Function));
  });

  it('Wiggle should notify subscribers', function(done) {
    wiggle.on('desktop', done);

    expect(wiggle.is('desktop')).toEqual(true);
    expect(wiggle.is('tablet')).toEqual(false);
    expect(wiggle.is('mobile')).toEqual(false);
    expect(wiggle.is('notExisting')).toEqual(false);
  });

  xit('wiggle property should be immutable', function() {
    wiggle.is = 'changed is';
    wiggle.on = 'changed on';

    expect(wiggle.is).toEqual(jasmine.any(Function));
    expect(wiggle.on).toEqual(jasmine.any(Function));
  });

  it('On/Off listeners should be executed on resize', function(done) {
    var onDesktop = 0;
    var offDesktop = 0;
    var onTablet = 0;
    var offTablet = 0;
    var onMobile = 0;
    var offMobile = 0;

    // Initial screen size is on desktop
    wiggle.on('desktop', function() { onDesktop += 1; });
    wiggle.off('desktop', function() { offDesktop += 1; });
    wiggle.on('tablet', function() { onTablet += 1; });
    wiggle.off('tablet', function() { offTablet += 1; });
    wiggle.on('mobile', function() { onMobile += 1; });
    wiggle.off('mobile', function() { offMobile += 1; });

    expect(onDesktop).toEqual(1);
    expect(offDesktop).toEqual(0);
    expect(onTablet).toEqual(0);
    expect(offTablet).toEqual(1);
    expect(onMobile).toEqual(0);
    expect(offMobile).toEqual(1);

    // Set mobile to be active screen and activate resize event
    mockActiveScreen('mobile');
    window.dispatchEvent(new Event('resize'));

    waitResize(function() {
      expect(onDesktop).toEqual(1);
      expect(offDesktop).toEqual(1);
      expect(onTablet).toEqual(0);
      expect(offTablet).toEqual(1);
      expect(onMobile).toEqual(1);
      expect(offMobile).toEqual(1);

      done();
    });
  });

  it('queueOn/queueOff Listeners should be executed on resize', function(done) {
    var onDesktop = 0;
    var offDesktop = 0;

    // Initial screen size is on desktop
    wiggle.queueOn('desktop', function() { onDesktop += 1; });
    wiggle.queueOff('desktop', function() { offDesktop += 1; });

    // Queue should not be triggered on first screen size
    expect(onDesktop).toEqual(0);
    expect(offDesktop).toEqual(0);

    // Set mobile to be active screen and activate resize event
    mockActiveScreen('mobile');
    window.dispatchEvent(new Event('resize'));

    waitResize(function() {
      expect(onDesktop).toEqual(0);
      expect(offDesktop).toEqual(1);
      // Set desktop to be active screen and activate resize event
      mockActiveScreen('desktop');
      window.dispatchEvent(new Event('resize'));

      waitResize(function() {
        expect(onDesktop).toEqual(1);
        expect(offDesktop).toEqual(1);

        // No changes no listeners should be trigered
        window.dispatchEvent(new Event('resize'));

        waitResize(function() {
          expect(onDesktop).toEqual(1);
          expect(offDesktop).toEqual(1);
          done();
        });
      });
    });
  });
});
<commit_msg>uncoment spec<commit_after>describe('Wiggle', function() {
  var wiggle;
  const screens = {
    desktop: {
      minWidth: 992,
      name: 'desktop'
    },
    tablet: {
      minWidth: 768,
      maxWidth: 991,
      name: 'tablet'
    },
    mobile: {
      maxWidth: 767,
      name: 'mobile'
    }
  }

  function mockActiveScreen(name) {
    size = screens[name].minWidth || screens[name].maxWidth;
    window.matchMedia = function(query) {
      return {
        matches: query.indexOf(size.toString()) !== -1
      }
    };
  }

  function waitResize(fn) {
    setTimeout(fn, 50);
  }

  beforeEach(function() {
    mockActiveScreen('desktop');

    wiggle = Wiggle.init([
      screens.desktop,
      screens.tablet,
      screens.mobile
    ]);
  });

  it('Wiggle should be initialized', function() {
    expect(wiggle.on).toEqual(jasmine.any(Function));
    expect(wiggle.queueOn).toEqual(jasmine.any(Function));
    expect(wiggle.off).toEqual(jasmine.any(Function));
    expect(wiggle.queueOff).toEqual(jasmine.any(Function));
    expect(wiggle.is).toEqual(jasmine.any(Function));
  });

  it('Wiggle should notify subscribers', function(done) {
    wiggle.on('desktop', done);

    expect(wiggle.is('desktop')).toEqual(true);
    expect(wiggle.is('tablet')).toEqual(false);
    expect(wiggle.is('mobile')).toEqual(false);
    expect(wiggle.is('notExisting')).toEqual(false);
  });

  it('wiggle property should be immutable', function() {
    wiggle.is = 'changed is';
    wiggle.on = 'changed on';

    expect(wiggle.is).toEqual(jasmine.any(Function));
    expect(wiggle.on).toEqual(jasmine.any(Function));
  });

  it('On/Off listeners should be executed on resize', function(done) {
    var onDesktop = 0;
    var offDesktop = 0;
    var onTablet = 0;
    var offTablet = 0;
    var onMobile = 0;
    var offMobile = 0;

    // Initial screen size is on desktop
    wiggle.on('desktop', function() { onDesktop += 1; });
    wiggle.off('desktop', function() { offDesktop += 1; });
    wiggle.on('tablet', function() { onTablet += 1; });
    wiggle.off('tablet', function() { offTablet += 1; });
    wiggle.on('mobile', function() { onMobile += 1; });
    wiggle.off('mobile', function() { offMobile += 1; });

    expect(onDesktop).toEqual(1);
    expect(offDesktop).toEqual(0);
    expect(onTablet).toEqual(0);
    expect(offTablet).toEqual(1);
    expect(onMobile).toEqual(0);
    expect(offMobile).toEqual(1);

    // Set mobile to be active screen and activate resize event
    mockActiveScreen('mobile');
    window.dispatchEvent(new Event('resize'));

    waitResize(function() {
      expect(onDesktop).toEqual(1);
      expect(offDesktop).toEqual(1);
      expect(onTablet).toEqual(0);
      expect(offTablet).toEqual(1);
      expect(onMobile).toEqual(1);
      expect(offMobile).toEqual(1);

      done();
    });
  });

  it('queueOn/queueOff Listeners should be executed on resize', function(done) {
    var onDesktop = 0;
    var offDesktop = 0;

    // Initial screen size is on desktop
    wiggle.queueOn('desktop', function() { onDesktop += 1; });
    wiggle.queueOff('desktop', function() { offDesktop += 1; });

    // Queue should not be triggered on first screen size
    expect(onDesktop).toEqual(0);
    expect(offDesktop).toEqual(0);

    // Set mobile to be active screen and activate resize event
    mockActiveScreen('mobile');
    window.dispatchEvent(new Event('resize'));

    waitResize(function() {
      expect(onDesktop).toEqual(0);
      expect(offDesktop).toEqual(1);
      // Set desktop to be active screen and activate resize event
      mockActiveScreen('desktop');
      window.dispatchEvent(new Event('resize'));

      waitResize(function() {
        expect(onDesktop).toEqual(1);
        expect(offDesktop).toEqual(1);

        // No changes no listeners should be trigered
        window.dispatchEvent(new Event('resize'));

        waitResize(function() {
          expect(onDesktop).toEqual(1);
          expect(offDesktop).toEqual(1);
          done();
        });
      });
    });
  });
});
<|endoftext|>


<commit_before>'use strict';

/*
 * Defining the Package
 */
var Module = require('meanio').Module;

var Articles = new Module('Articles');

/*
 * All MEAN packages require registration
 * Dependency injection is used to define required modules
 */
Articles.register(function(app, auth, database) {

    //We enable routing. By default the Package Object is passed to the routes
    Articles.routes(app, auth, database);

    //We are adding a link to the main menu for all authenticated users
    Articles.menus.add({
        'roles': ['authenticated'],
        'title': 'Articles',
        'link': 'all articles'
    });
    Articles.menus.add({
        'roles': ['authenticated'],
        'title': 'Create New Article',
        'link': 'create article'
    });

    /*
    //Uncomment to use. Requires meanio@0.3.7 or above
    // Save settings with callback
    // Use this for saving data from administration pages
    Articles.settings({'someSetting':'some value'},function (err, settings) {
      //you now have the settings object
    });

    // Another save settings example this time with no callback
    // This writes over the last settings.
    Articles.settings({'anotherSettings':'some value'});

    // Get settings. Retrieves latest saved settigns
    Articles.settings(function (err, settings) {
      //you now have the settings object
    });
    */

    return Articles;
});
<commit_msg>no menu for article<commit_after>'use strict';

/*
 * Defining the Package
 */
var Module = require('meanio').Module;

var Articles = new Module('Articles');

/*
 * All MEAN packages require registration
 * Dependency injection is used to define required modules
 */
Articles.register(function(app, auth, database) {

    //We enable routing. By default the Package Object is passed to the routes
    Articles.routes(app, auth, database);

    //We are adding a link to the main menu for all authenticated users
    /*Articles.menus.add({
        'roles': ['authenticated'],
        'title': 'Articles',
        'link': 'all articles'
    });
    Articles.menus.add({
        'roles': ['authenticated'],
        'title': 'Create New Article',
        'link': 'create article'
    });*/

    /*
    //Uncomment to use. Requires meanio@0.3.7 or above
    // Save settings with callback
    // Use this for saving data from administration pages
    Articles.settings({'someSetting':'some value'},function (err, settings) {
      //you now have the settings object
    });

    // Another save settings example this time with no callback
    // This writes over the last settings.
    Articles.settings({'anotherSettings':'some value'});

    // Get settings. Retrieves latest saved settigns
    Articles.settings(function (err, settings) {
      //you now have the settings object
    });
    */

    return Articles;
});
<|endoftext|>


<commit_before>Package.describe({
  name: 'scorpiusjs:core',
  summary: 'A framework that makes complex as well as simple apps possible with minimal effort',
  version: "0.1.0",
  git: 'https://github.com/scorpiusjs/scorpius'
});

Package.onUse(function(api) {
  api.versionsFrom('1.4.1');

  api.use([
    'blaze-html-templates@1.0.1',
    'ecmascript@0.1.6',
    'scorpiusjs:base@0.1.0',
    'scorpiusjs:accounts@0.1.0',
    'scorpiusjs:config@0.1.0',
    'scorpiusjs:collections@0.1.0',
    'scorpiusjs:dictionary@0.1.0',
    'scorpiusjs:attributes@0.1.0',
    'scorpiusjs:lang-en@0.1.0'
    ]);

  api.imply([
    'scorpiusjs:lang-en',
    'scorpiusjs:base',
    'scorpiusjs:accounts',
    'scorpiusjs:config',
    'scorpiusjs:collections',
    'scorpiusjs:dictionary',
    'scorpiusjs:attributes',
    ]);

  api.export('scorpius');
});

Package.onTest(function(api) {
  api.use('tinytest');
  // api.use('scorpiusjs:core');
});
<commit_msg>Publish version v0.2.0<commit_after>Package.describe({
  name: 'scorpiusjs:core',
  summary: 'A framework that makes complex as well as simple apps possible with minimal effort',
  version: "0.2.0",
  git: 'https://github.com/scorpiusjs/scorpius'
});

Package.onUse(function(api) {
  api.versionsFrom('1.4.1');

  api.use([
    'blaze-html-templates@1.0.1',
    'ecmascript@0.1.6',
    'scorpiusjs:base@0.1.0',
    'scorpiusjs:accounts@0.1.0',
    'scorpiusjs:config@0.1.0',
    'scorpiusjs:collections@0.1.0',
    'scorpiusjs:dictionary@0.1.0',
    'scorpiusjs:attributes@0.1.0',
    'scorpiusjs:lang-en@0.1.0'
    ]);

  api.imply([
    'scorpiusjs:lang-en',
    'scorpiusjs:base',
    'scorpiusjs:accounts',
    'scorpiusjs:config',
    'scorpiusjs:collections',
    'scorpiusjs:dictionary',
    'scorpiusjs:attributes',
    ]);

  api.export('scorpius');
});

Package.onTest(function(api) {
  api.use('tinytest');
  // api.use('scorpiusjs:core');
});
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');
var errors = require('error-codes');
var colors = require('colors');

module.exports = function ($youmeb) {
  var $errors = errors($youmeb.config.get('error.format'));

  $youmeb.on('help', function (command, data, done) {
    data.commands.push(['errors', '', 'Display error list']);
    done();
  });

  $youmeb.on('cli-errors', function (parser, args, done) {
    defineAllErrors($youmeb, $errors, function (err) {
      if (err) {
        return done(err);
      }
      var arr = $errors.getAllErrors();
      var len = {key: 0, code: 0, message: 0};
      arr.forEach(function (raw) {
        var i, l;
        for (i in len) {
          l = (raw[i] || '').length;
          if (l > len[i]) {
            len[i] = l;
          }
        }
      });
      console.log();
      arr.forEach(function (raw) {
        console.log('  %s  %s  %s', space(raw.key, len.key).green, space(raw.code, len.code), space(raw.message, len.message));
      });
      console.log();
    });
  });

  this.on('init', function (config, done) {
    $youmeb.register('errors', $errors);
    defineAllErrors($youmeb, $errors, done);
  });

};

function defineAllErrors($youmeb, $errors, done) {
  getErrorsData($youmeb, function (err, data) {
    if (err) {
      return done(err);
    }
    data.forEach(function (raw) {
      $errors.define(raw[0], raw[1]);
    });
    done();
  });
}

function getErrorsData($youmeb, done) {
  var data = [];
  fs.readFile($youmeb.config.get('error.file'), 'utf8', function (err, content) {
    if (err) {
      return done(err);
    }
    content.split('\n').forEach(function (line) {
      line = line.trim();
      if (!line) {
        return;
      }
      var raw = line.split(/\s+/);
      data.push(raw);
    });
    done(null, data);
  });
}

function space(str, len) {
  var i = len - str.length;
  while (i > 0) {
    i -= 1;
    str += ' ';
  }
  return str;
}
<commit_msg>errors 檔案位置在某些情況下出現錯誤<commit_after>'use strict';

var fs = require('fs');
var path = require('path');
var errors = require('error-codes');
var colors = require('colors');

module.exports = function ($youmeb) {
  var $errors = errors($youmeb.config.get('error.format'));

  $youmeb.on('help', function (command, data, done) {
    data.commands.push(['errors', '', 'Display error list']);
    done();
  });

  $youmeb.on('cli-errors', function (parser, args, done) {
    defineAllErrors($youmeb, $errors, function (err) {
      if (err) {
        return done(err);
      }
      var arr = $errors.getAllErrors();
      var len = {key: 0, code: 0, message: 0};
      arr.forEach(function (raw) {
        var i, l;
        for (i in len) {
          l = (raw[i] || '').length;
          if (l > len[i]) {
            len[i] = l;
          }
        }
      });
      console.log();
      arr.forEach(function (raw) {
        console.log('  %s  %s  %s', space(raw.key, len.key).green, space(raw.code, len.code), space(raw.message, len.message));
      });
      console.log();
    });
  });

  this.on('init', function (config, done) {
    $youmeb.register('errors', $errors);
    defineAllErrors($youmeb, $errors, done);
  });

};

function defineAllErrors($youmeb, $errors, done) {
  getErrorsData($youmeb, function (err, data) {
    if (err) {
      return done(err);
    }
    data.forEach(function (raw) {
      $errors.define(raw[0], raw[1]);
    });
    done();
  });
}

function getErrorsData($youmeb, done) {
  var data = [];
  fs.readFile(path.join($youmeb.root, $youmeb.config.get('error.file')), 'utf8', function (err, content) {
    if (err) {
      return done(err);
    }
    content.split('\n').forEach(function (line) {
      line = line.trim();
      if (!line) {
        return;
      }
      var raw = line.split(/\s+/);
      data.push(raw);
    });
    done(null, data);
  });
}

function space(str, len) {
  var i = len - str.length;
  while (i > 0) {
    i -= 1;
    str += ' ';
  }
  return str;
}
<|endoftext|>


<commit_before>(function(){
	angular.module('ngSidepanel',[]);

	angular.module('ngSidepanel').factory('$parseSidepanelHtml',[function($compile){
		var count = 0;
		return function(template,controllerName,width,position,cssClass){
			var sidepanelId = 'sidepanel-' + count;
			count += 1;

			var htmlString = '';
			var isVertical = false;
			if(position == 'left' || position == 'right'){
				isVertical = true;
				htmlString = '
'
					+ '
'
					+ template
					+ '</' + 'div>'
					+ '</'+'div>';
			}
			else{
				htmlString = '
'
					+ '
'
					+ template
					+ '</' + 'div>'
					+ '</'+'div>';
			}

			angular.element('body').append(htmlString);

			if(isVertical){
				angular.element(window).resize(function() {
					var _w = angular.element( window ).width();
					var _h = angular.element( window ).height();

					// Do a custom code here

					if(_w <= 480){
						angular.element('#'+sidepanelId+' > .ng-sidepanel.left').animate({
							width : '95%'
						}, 400,function(){

						});

					}

					// Do a custom code here
					if(_w > 480){
						angular.element('#'+sidepanelId+' > .ng-sidepanel.left').animate({
							width : width
						}, 400,function(){

						});
					}
				});
			}
			return sidepanelId;
		};
	}]);

	/**
	 * @title $getSidepanelTemplate
	 * Fetches the template from $templateCache by using URL and if it is not existing in $templateCache
	 * then fetches it from remote url and refills $templateCache for next time usage
	 * @param options
	 * @return promise
	 */
	angular.module('ngSidepanel').service('$getSidepanelTemplate',['$templateRequest','$templateCache','$q','$timeout',
		function($templateRequest,$templateCache,$q,$timeout){
			return function(templateUrl){
				var defer = $q.defer();
				var template = $templateCache.get(templateUrl);
				if(template){
					var tempString = template;
					if(typeof(template) === 'string'){

					}
					else{
						tempString = template[1];
					}
					$timeout(function(){
						return defer.resolve(tempString)
					},10);
				}
				else{
					$templateRequest(templateUrl).then(function(data){
						var tempString = data;
						if(typeof(template) === 'string'){

						}
						else{
							tempString = template[1];
						}
						$templateCache.put(templateUrl,tempString);
						defer.resolve(tempString);
					},function(err){
						console.error(err);
						defer.reject('Template Not found');
					});
				}
				return defer.promise;
			};
		}]);

	/**
	 * Parses the options passed for creating sidepanel instance
	 */
	angular.module('ngSidepanel').service('$parseSidepanelOptions',['$q','$timeout','$controller','$rootScope',
		function($q,$timeout,$controller,$rootScope){
			return function(options){
				var defaultOptions = {
					template : '',
					templateUrl : null,
					controller : null,
					position : 'right',
					width : '20%',
					height : '90%',
					panelClass : '',
					resolve : null
				};
				if(options && typeof(options) == 'object'){
					for(var prop in options){
						if(options.hasOwnProperty(prop) && defaultOptions.hasOwnProperty(prop) !== -1){
							if(options[prop]){

								if(prop == 'position' && ['right','left','top','bottom'].indexOf(options[prop].toLowerCase()) == -1){
									defaultOptions[prop] = 'right';
								}
								else{
									defaultOptions[prop] = options[prop];
								}
							}
						}
					}
					return defaultOptions;
				}
				else{
					return defaultOptions;
				}
			};
		}]);

	angular.module('ngSidepanel').service('$sidepanel',[
		'$getSidepanelTemplate',
		'$parseSidepanelOptions',
		'$q',
		'$controller',
		'$rootScope',
		'$parseSidepanelHtml',
		'$compile',
		'$timeout',
		function(
			$getSidepanelTemplate,
			$parseSidepanelOptions,
			$q,
			$controller,
			$rootScope,
			$parseSidepanelHtml,
			$compile,
			$timeout
		){

			var defer = $q.defer();
			this.sidepanelInstance = {
			};
			this.open = function(panelOptions){
				defer = $q.defer();
				var parsedOptions = $parseSidepanelOptions(panelOptions);
				var animateProp = { height : '0%'};
				var animatePropFinal = { height : parsedOptions.height};
				if(panelOptions.position == 'right' || panelOptions.position == 'left'){
					animateProp = { width : '0%'};
					animatePropFinal = { width : parsedOptions.width};
				}
				if(!parsedOptions.template){
					$getSidepanelTemplate(parsedOptions.templateUrl).then(function(data){
						var sidePanelId = $parseSidepanelHtml(data,parsedOptions.controller,parsedOptions.width,parsedOptions.position,parsedOptions.panelClass);

						var ctrlDi = {
							$scope : $rootScope.$new(),
							$sidepanelInstance : {
								close : function(data){
									angular.element('#'+sidePanelId + ' > .ng-sidepanel').animate(animateProp, 400,function(){
										angular.element('#'+sidePanelId).remove();
										console.log(data);
										defer.resolve(data);
									});
								},
								dismiss : function(cause){
									angular.element('#'+sidePanelId + ' > .ng-sidepanel').animate(animateProp, 400,function(){
										angular.element('#'+sidePanelId).remove();
										console.log(data);
										defer.reject(cause);
									});
								}
							}
						};
						if(parsedOptions.resolve && typeof(parsedOptions.resolve) == 'object' ){
							for(var resProp in parsedOptions.resolve){
								if(parsedOptions.resolve.hasOwnProperty(resProp)){
									ctrlDi[resProp] = panelOptions.resolve[resProp];
								}
							}
						}
						/**
						 * Joins the template to body
						 * Instantiate the controller
						 * Compile the template and bind the controller scope
						 */
						if(parsedOptions.controller){
							var ctrlInstance = $controller(parsedOptions.controller,ctrlDi);
						}
						$compile(angular.element('#'+sidePanelId).contents())(ctrlDi.$scope);
						$timeout(function(){
							angular.element('#'+sidePanelId + ' > .ng-sidepanel').animate(animatePropFinal, 400,function(){
							});
						},200);

					},function(err){
						console.error(err);
					});
				}
				else{
					/**
					 * Joins the template to body
					 * Instantiate the controller
					 * Compile the template and bind the controller scope
					 */
					var sidePanelId = $parseSidepanelHtml(data,parsedOptions.controller,parsedOptions.width,parsedOptions.position,parsedOptions.panelClass);
					var ctrlDi = {
						$scope : $rootScope.$new(),
						$sidepanelInstance : {
							close : function(data){
								$timeout(function(){
									angular.element('#'+sidePanelId + ' > .ng-sidepanel').animate(animateProp, 400,function(){
										angular.element('#'+sidePanelId).remove();
										defer.resolve(data);
									});

								},100);

							},
							dismiss : function(cause){
								$timeout(function(){
									angular.element('#'+sidePanelId + ' > .ng-sidepanel').animate(animateProp, 400,function(){

										angular.element('#'+sidePanelId).remove();

										defer.reject(cause);
									});
								},100);
							}
						}
					};
					if(parsedOptions.resolve && typeof(parsedOptions.resolve) == 'object' ){
						for(var resProp in parsedOptions.resolve){
							if(parsedOptions.resolve.hasOwnProperty(resProp)){
								try{
									ctrlDi[resProp] = panelOptions.resolve[resProp]();
								}
								catch(ex){
									ctrlDi[resProp] = panelOptions.resolve[resProp];
								}
							}
						}
					}
					/**
					 * Joins the template to body
					 * Instantiate the controller
					 * Compile the template and bind the controller scope
					 */
					if(parsedOptions.controller){
						var ctrlInstance = $controller(parsedOptions.controller,ctrlDi);
					}
					$compile(angular.element('#'+sidePanelId).contents())(ctrlDi.$scope);
					$timeout(function(){
						angular.element('#'+sidePanelId + ' > .ng-sidepanel').animate(animatePropFinal, 400,'linear',function(){
						});
					},100);

				}
				this.sidepanelInstance.result = defer.promise;
				return this.sidepanelInstance;
			};

		}]);

})();

<commit_msg>dist/ngSidepanel.js<commit_after>(function(){
	angular.module('ngSidepanel',[]);

	angular.module('ngSidepanel').factory('$parseSidepanelHtml',[function($compile){
		var count = 0;
		return function(template,controllerName,width,position,cssClass){
			var sidepanelId = 'sidepanel-' + count;
			count += 1;

			var htmlString = '';
			var isVertical = false;
			if(position == 'left' || position == 'right'){
				isVertical = true;
				htmlString = '
'
					+ '
'
					+ template
					+ '</' + 'div>'
					+ '</'+'div>';
			}
			else{
				htmlString = '
'
					+ '
'
					+ template
					+ '</' + 'div>'
					+ '</'+'div>';
			}

			angular.element('[ng-app]').append(htmlString);

			if(isVertical){
				angular.element(window).resize(function() {
					var _w = angular.element( window ).width();
					var _h = angular.element( window ).height();

					// Do a custom code here

					if(_w <= 480){
						angular.element('#'+sidepanelId+' > .ng-sidepanel.left').animate({
							width : '95%'
						}, 400,function(){

						});

					}

					// Do a custom code here
					if(_w > 480){
						angular.element('#'+sidepanelId+' > .ng-sidepanel.left').animate({
							width : width
						}, 400,function(){

						});
					}
				});
			}
			return sidepanelId;
		};
	}]);

	/**
	 * @title $getSidepanelTemplate
	 * Fetches the template from $templateCache by using URL and if it is not existing in $templateCache
	 * then fetches it from remote url and refills $templateCache for next time usage
	 * @param options
	 * @return promise
	 */
	angular.module('ngSidepanel').service('$getSidepanelTemplate',['$templateRequest','$templateCache','$q','$timeout',
		function($templateRequest,$templateCache,$q,$timeout){
			return function(templateUrl){
				var defer = $q.defer();
				var template = $templateCache.get(templateUrl);
					$templateRequest(templateUrl).then(function(data){
						$templateCache.put(templateUrl,data);
						defer.resolve(data);
					},function(err){
						console.error(err);
						defer.reject('Template Not found');
					});

				return defer.promise;
			};
		}]);

	/**
	 * Parses the options passed for creating sidepanel instance
	 */
	angular.module('ngSidepanel').service('$parseSidepanelOptions',['$q','$timeout','$controller','$rootScope',
		function($q,$timeout,$controller,$rootScope){
			return function(options){
				var defaultOptions = {
					template : '',
					templateUrl : null,
					controller : null,
					position : 'right',
					width : '20%',
					height : '90%',
					panelClass : '',
					resolve : null
				};
				if(options && typeof(options) == 'object'){
					for(var prop in options){
						if(options.hasOwnProperty(prop) && defaultOptions.hasOwnProperty(prop) !== -1){
							if(options[prop]){

								if(prop == 'position' && ['right','left','top','bottom'].indexOf(options[prop].toLowerCase()) == -1){
									defaultOptions[prop] = 'right';
								}
								else{
									defaultOptions[prop] = options[prop];
								}
							}
						}
					}
					return defaultOptions;
				}
				else{
					return defaultOptions;
				}
			};
		}]);

	angular.module('ngSidepanel').service('$sidepanel',[
		'$getSidepanelTemplate',
		'$parseSidepanelOptions',
		'$q',
		'$controller',
		'$rootScope',
		'$parseSidepanelHtml',
		'$compile',
		'$timeout',
		function(
			$getSidepanelTemplate,
			$parseSidepanelOptions,
			$q,
			$controller,
			$rootScope,
			$parseSidepanelHtml,
			$compile,
			$timeout
		){

			var defer = $q.defer();
			this.sidepanelInstance = {
			};
			this.open = function(panelOptions){
				defer = $q.defer();
				var parsedOptions = $parseSidepanelOptions(panelOptions);
				var animateProp = { height : '0%'};
				var animatePropFinal = { height : parsedOptions.height};
				if(panelOptions.position == 'right' || panelOptions.position == 'left'){
					animateProp = { width : '0%'};
					animatePropFinal = { width : parsedOptions.width};
				}
				if(!parsedOptions.template){
					$getSidepanelTemplate(parsedOptions.templateUrl).then(function(data){
						var sidePanelId = $parseSidepanelHtml(data,parsedOptions.controller,parsedOptions.width,parsedOptions.position,parsedOptions.panelClass);

						var ctrlDi = {
							$scope : $rootScope.$new(),
							$sidepanelInstance : {
								close : function(data){
									angular.element('#'+sidePanelId + ' > .ng-sidepanel').animate(animateProp, 400,function(){
										angular.element('#'+sidePanelId).remove();
										defer.resolve(data);
									});
								},
								dismiss : function(cause){
									angular.element('#'+sidePanelId + ' > .ng-sidepanel').animate(animateProp, 400,function(){
										angular.element('#'+sidePanelId).remove();
										defer.reject(cause);
									});
								}
							}
						};
						if(parsedOptions.resolve && typeof(parsedOptions.resolve) == 'object' ){
							for(var resProp in parsedOptions.resolve){
								if(parsedOptions.resolve.hasOwnProperty(resProp)){
									ctrlDi[resProp] = panelOptions.resolve[resProp];
								}
							}
						}
						/**
						 * Joins the template to body
						 * Instantiate the controller
						 * Compile the template and bind the controller scope
						 */
						if(parsedOptions.controller){
							var ctrlInstance = $controller(parsedOptions.controller,ctrlDi);
						}
						$compile(angular.element('#'+sidePanelId).contents())(ctrlDi.$scope);
						$timeout(function(){
							angular.element('#'+sidePanelId + ' > .ng-sidepanel').animate(animatePropFinal, 400,function(){
								$timeout(function(){
									angular.element('#'+sidePanelId).bind('click',function(){
										angular.element('#'+sidePanelId + ' > .ng-sidepanel').animate(animateProp, 400,function(){
											angular.element('#'+sidePanelId).remove();
										});
									});

								},100);
							});
						},200);

					},function(err){
						console.error(err);
					});
				}
				else{
					/**
					 * Joins the template to body
					 * Instantiate the controller
					 * Compile the template and bind the controller scope
					 */
					var sidePanelId = $parseSidepanelHtml(data,parsedOptions.controller,parsedOptions.width,parsedOptions.position,parsedOptions.panelClass);
					var ctrlDi = {
						$scope : $rootScope.$new(),
						$sidepanelInstance : {
							close : function(data){
								$timeout(function(){
									angular.element('#'+sidePanelId + ' > .ng-sidepanel').animate(animateProp, 400,function(){
										angular.element('#'+sidePanelId).remove();
										defer.resolve(data);
									});

								},100);

							},
							dismiss : function(cause){
								$timeout(function(){
									angular.element('#'+sidePanelId + ' > .ng-sidepanel').animate(animateProp, 400,function(){

										angular.element('#'+sidePanelId).remove();

										defer.reject(cause);
									});
								},100);
							}
						}
					};
					if(parsedOptions.resolve && typeof(parsedOptions.resolve) == 'object' ){
						for(var resProp in parsedOptions.resolve){
							if(parsedOptions.resolve.hasOwnProperty(resProp)){
								try{
									ctrlDi[resProp] = panelOptions.resolve[resProp]();
								}
								catch(ex){
									ctrlDi[resProp] = panelOptions.resolve[resProp];
								}
							}
						}
					}
					/**
					 * Joins the template to body
					 * Instantiate the controller
					 * Compile the template and bind the controller scope
					 */
					if(parsedOptions.controller){
						var ctrlInstance = $controller(parsedOptions.controller,ctrlDi);
					}
					$compile(angular.element('#'+sidePanelId).contents())(ctrlDi.$scope);
					$timeout(function(){
						angular.element('#'+sidePanelId + ' > .ng-sidepanel').animate(animatePropFinal, 400,'linear',function(){
							$timeout(function(){
								angular.element('#'+sidePanelId).bind('click',function(){
									angular.element('#'+sidePanelId + ' > .ng-sidepanel').animate(animateProp, 400,function(){
										angular.element('#'+sidePanelId).remove();
									});
								});

							},100);
						});
					},100);

				}
				this.sidepanelInstance.result = defer.promise;
				return this.sidepanelInstance;
			};

		}]);

})();

<|endoftext|>


<commit_before>import React from 'react';
import { createComponent } from 'olymp-fela';
import { Card } from 'olymp-scrape';

const CardContainer = createComponent(
  ({ theme }) => ({
    width: '100%',
    position: 'relative',
    display: 'block',
  }),
  ({ attributes, className, node, children }) => (
    <Card
      {...attributes}
      className={className}
      xy={console.log(node.data.get('value'))}
      value={node.data.get('value')}
    >
      {children}
    </Card>
  ),
  p => Object.keys(p),
);

export default {
  type: 'cardLink',
  isVoid: true,
  kind: 'block',
  label: 'Reichhaltiger Link',
  category: 'Sonstiges',
  component: CardContainer,
  actions: [
    {
      type: 'small',
      icon: 'chain',
      label: 'Link',
      toggle: ({ onChange, value, node }) => {
        const href = window.prompt('Link');
        if (href) {
          onChange(
            value.change().setNodeByKey(node.key, {
              data: node.data.set('value', href),
            }),
          );
        } else {
          onChange(
            value.change().setNodeByKey(node.key, {
              data: node.data.set('value', null),
            }),
          );
        }
      },
    },
  ],
};
<commit_msg>Reichhaltiger Link => Meta-Link<commit_after>import React from 'react';
import { createComponent } from 'olymp-fela';
import { Card } from 'olymp-scrape';

const CardContainer = createComponent(
  ({ theme }) => ({
    width: '100%',
    position: 'relative',
    display: 'block',
  }),
  ({ attributes, className, node, children }) => (
    <Card
      {...attributes}
      className={className}
      xy={console.log(node.data.get('value'))}
      value={node.data.get('value')}
    >
      {children}
    </Card>
  ),
  p => Object.keys(p),
);

export default {
  type: 'cardLink',
  isVoid: true,
  kind: 'block',
  label: 'Meta-Link',
  category: 'Sonstiges',
  component: CardContainer,
  actions: [
    {
      type: 'small',
      icon: 'chain',
      label: 'Link',
      toggle: ({ onChange, value, node }) => {
        const href = window.prompt('Link');
        if (href) {
          onChange(
            value.change().setNodeByKey(node.key, {
              data: node.data.set('value', href),
            }),
          );
        } else {
          onChange(
            value.change().setNodeByKey(node.key, {
              data: node.data.set('value', null),
            }),
          );
        }
      },
    },
  ],
};
<|endoftext|>


<commit_before>exports.productionVersionId = "a838abee68bb";<commit_msg>Incrementing Production Version.<commit_after>exports.productionVersionId = "ba187295b790";<|endoftext|>