<commit_before>import React, { Component } from 'react'
import { connect } from "react-redux"
import { Stage, Layer, Image, Circle, Line } from "react-konva"
import { Segment, Header, Button, Progress, Dropdown } from "semantic-ui-react"
import Slider from "rc-slider"
import _ from "lodash"

import Inventory from "../../components/Inventory"

import { requestWorlds } from "../../actions/world"
import { requestEntities } from "../../actions/entity"
import { requestPlayers } from "../../actions/player"
import { requestTileEntities } from "../../actions/tile-entity"

const TILE_SIZE = 512;
const HALF_TILE = TILE_SIZE / 2;
const ZOOM_SPEED = 0.01;
const MIN_ZOOM = 0.1;
const MAX_ZOOM = 16.0;

const totalOffset = (element) => {
		let top = 0;
		let left = 0;

		do {
				top += element.offsetTop  || 0;
				left += element.offsetLeft || 0;
				element = element.offsetParent;
		} while(element);

		return {
				top: top,
				left: left
		};
}

const marks = {
	0.400: MIN,
	0.707: "0.25x",
	0.841: "0.5x",
	1: "-",
	1.189: "2x",
	1.414: "4x",
	1.682: "8x",
	2: MAX,
}

class Map extends Component {

	constructor(props) {
		super(props);

		this.state = {
			biomes: [],
			top: 0,
			left: 0,
			width: 0,
			height: 0,
			display: "none",
			content: null,
			center: {
				x: 0,
				z: 0,
			},
			zoom: 1,
			dragging: false,
			worldId: null,
		}

		this.timeouts = []

		this.handleObjMouseDown = this.handleObjMouseDown.bind(this)
		this.handleMouseDown = this.handleMouseDown.bind(this)
		this.handleMouseMove = this.handleMouseMove.bind(this)
		this.handleMouseOutUp = this.handleMouseOutUp.bind(this)
		this.handleWheel = this.handleWheel.bind(this)
		this.handleWorldChange = this.handleWorldChange.bind(this)

		this.updateDimensions = _.debounce(this.updateDimensions.bind(this), 500)
		this.getAllBiomes = _.debounce(this.getAllBiomes.bind(this), 500)
		this.worldToScreen = this.worldToScreen.bind(this)
		this.screenToWorld = this.screenToWorld.bind(this)
		this.center = this.center.bind(this)
	}

	componentDidMount() {
		this.props.requestEntities();
		this.props.requestPlayers();
		this.props.requestTileEntities();
		this.props.requestWorlds();

		window.addEventListener("resize", this.updateDimensions);
		this.updateDimensions();
	}

	componentWillUnmount() {
		window.removeEventListener("resize", this.updateDimensions);
	}

	updateDimensions() {
		if (!this.wrapper) return;

		this.setState({
			width: this.wrapper.offsetWidth,
			height: window.innerHeight - totalOffset(this.wrapper).top - 30,
		}, () => this.getAllBiomes())
	}

	getAllBiomes() {
		// If we didn't select a world yet do nothing
		if (!this.state.worldId) return;

		// z is inverse here because it's in screen coordinates
		const min = this.screenToWorld({ x: 0, z: this.state.height })
		const max = this.screenToWorld({ x: this.state.width, z: 0 })

		_.each(this.timeouts, timeout => clearTimeout(timeout))

		this.setState({
			biomes: _.filter(this.state.biomes, biome =>
				biome.x + HALF_TILE >= min.x && biome.x - HALF_TILE <= max.x &&
				biome.z + HALF_TILE >= min.z && biome.z - HALF_TILE <= max.z)
		}, () => {
			min.x = min.x - min.x % TILE_SIZE - TILE_SIZE
			min.z = min.z - min.z % TILE_SIZE - TILE_SIZE

			max.x = max.x - max.x % TILE_SIZE + TILE_SIZE
			max.z = max.z - max.z % TILE_SIZE + TILE_SIZE

			let index = 0;
			this.timeouts = [];
			for (let x = min.x; x <= max.x; x += TILE_SIZE) {
				for (let z = min.z; z <= max.z; z += TILE_SIZE) {
					if (_.find(this.state.biomes, { x: x, z: z }))
						continue;

					this.timeouts.push(
						setTimeout(() => this.getBiome(x, z), index * 100)
					)
					index++;
				}
			}
		})
	}

	getBiome(x, z) {
		const image = new window.Image();
		image.src = "/api/map/" + this.state.worldId + "/" + (x / TILE_SIZE) + "/" + (z / TILE_SIZE) + "?key=" + this.props.apiKey;
		image.onload = () => {
			this.setState({
				biomes: _.concat(this.state.biomes, {
					x: x,
					z: z,
					image,
				})
			})
		}
	}

	handleWorldChange(event, data) {
		this.setState({
			biomes: [],
			worldId: data.value,
		}, () => this.getAllBiomes())
	}

	handleObjMouseDown(event, obj) {
		event.evt.cancelBubble = true;

		const loc = this.worldToScreen(obj.location.position)

		this.setState({
			left: loc.x,
			top: loc.z,
			display: "block",
			content: <Segment>

						{obj.name ? obj.name : obj.type ? obj.type : obj.uuid ? obj.uuid : null}

					{obj.uuid}

					{obj.inventory ?
						<Inventory items={obj.inventory.items} />
					: null }
					{obj.health ?
						<Progress color="green" percent={(obj.health.current/obj.health.max)*100} />
					: null}
					<Button color="red" onClick={() => this.deleteEntity(obj)}>
						Destroy
					</Button>
				</Segment>,
		})
	}

	handleMouseDown(event) {
		if (event.evt.cancelBubble) return;

		this.setState({
			dragging: true,
			display: "none",
		})
	}

	handleMouseMove(event) {
		if (!this.state.dragging) return;

		this.setState({
			center: {
				x: this.state.center.x + event.evt.movementX / this.state.zoom,
				z: this.state.center.z - event.evt.movementY / this.state.zoom,
			}
		}, () => this.getAllBiomes())
	}

	handleMouseOutUp(event) {
		if (event.evt.cancelBubble) return;

		this.setState({
			dragging: false,
		})
	}

	handleWheel(event) {
		const d = event.evt.deltaY
		const diff = Math.abs(d * ZOOM_SPEED)
		const newValue = d > 0 ? this.state.zoom / diff : this.state.zoom * diff

		this.setState({
			zoom: Math.min(Math.max(newValue, MIN_ZOOM), MAX_ZOOM),
		}, () => this.getAllBiomes())
	}

	handleZoomChange(value) {
		this.setState({
			zoom: Math.min(Math.max(Math.pow(value, 4), MIN_ZOOM), MAX_ZOOM),
		}, () => this.getAllBiomes())
	}

	deleteEntity(entity) {

	}

	center() {
		return {
			x: Math.floor(this.state.width / 2) + this.state.center.x * this.state.zoom,
			z: Math.floor(this.state.height / 2) - this.state.center.z * this.state.zoom,
		}
	}

	worldToScreen({ x, z }) {
		const center = this.center()
		return {
			x: center.x + x * this.state.zoom,
			z: center.z - z * this.state.zoom,
		}
	}

	screenToWorld({ x, z }) {
		const center = this.center()
		return {
			x: (x - center.x) / this.state.zoom,
			z: (center.z - z) / this.state.zoom,
		}
	}

	render() {
		const center = this.center()
		const cX = center.x
		const cZ = center.z

		return (
			<Segment basic style={{ position: "relative" }}>

 this.wrapper = w}>
					<Stage width={this.state.width} height={this.state.height} ref={s => this.stage = s}
							onContentMouseDown={e => this.handleMouseDown(e)}
							onContentMouseUp={e => this.handleMouseOutUp(e)}
							onContentMouseOut={e => this.handleMouseOutUp(e)}
							onContentMouseMove={e => this.handleMouseMove(e)}
							onContentWheel={e => this.handleWheel(e)}>
						<Layer>
						{ _.map(this.state.biomes, biome => {
								const pos = this.worldToScreen(biome)

								return <Image
									key={biome.x + "+" + biome.z}
									x={pos.x - HALF_TILE * this.state.zoom}
									y={pos.z - HALF_TILE * this.state.zoom}
									image={biome.image}
									width={TILE_SIZE * this.state.zoom}
									height={TILE_SIZE * this.state.zoom}
								/>
						})}
						</Layer>
						<Layer>
							<Line points={[0, cZ, 2000, cZ]} stroke="Black" strokeWidth={1} />
							<Line points={[cX, 0, cX, 2000]} stroke="Black" strokeWidth={1} />
						</Layer>
						<Layer>
							{ _.map(_.filter(this.props.entities, e => e.location.world.uuid === this.state.worldId), ent => {
								const pos = this.worldToScreen(ent.location.position)

								return <Circle
									key={ent.uuid}
									x={pos.x - 4}
									y={pos.z - 4}
									width={8}
									height={8}
									fill={"Red"}
									perfectDrawEnabled={false}
									onMouseDown={e => this.handleObjMouseDown(e, ent)}
								/>
							})}
							{ _.map(_.filter(this.props.players, p => p.location.world.uuid === this.state.worldId), player => {
								const pos = this.worldToScreen(player.location.position)

								return <Circle
									key={player.uuid}
									x={pos.x - 4}
									y={pos.z - 4}
									width={8}
									height={8}
									fill={"Gold"}
									perfectDrawEnabled={false}
									onMouseDown={e => this.handleObjMouseDown(e, player)}
								/>
							})}
							{ _.map(_.filter(this.props.tileEntities, te => te.location.world.uuid === this.state.worldId), te => {
								const pos = this.worldToScreen(te.location.position)

								return <Circle
									key={"te-" + te.location.position.x + "-" + te.location.position.z}
									x={pos.x - 4}
									y={pos.z - 4}
									width={8}
									height={8}
									fill={"Green"}
									perfectDrawEnabled={false}
									onMouseDown={e => this.handleObjMouseDown(e, te)}
								/>
							})}
						</Layer>
					</Stage>

						{this.state.content}

				<Segment style={{ position: "absolute", "top": 0, "left": 10 }}>
					<Dropdown
						id="world" placeholder="Select world..."
						value={this.state.worldId} onChange={this.handleWorldChange}
						options={_.map(this.props.worlds, world =>
							({ value: world.uuid, text: world.name + " (" + world.dimensionType.name + ")" })
						)}
					/>
				</Segment>
				<Segment style={{ position: "absolute", "top": 60, "left": 10, height: "25vh", width: 80 }}>
					<Slider
						vertical marks={marks} min={0.400} max={2} step={0.001} value={Math.pow(this.state.zoom, 1/4)}
						onChange={v => this.handleZoomChange(v)}
						trackStyle={{ backgroundColor: 'blue' }}
						handleStyle={{ borderColor: 'blue' }}
					/>
				</Segment>
			</Segment>
		)
	}
}

const mapStateToProps = (_state) => {
	return {
		entities: _state.entity.entities,
		worlds: _state.world.worlds,
		players: _state.player.players,
		tileEntities: _state.tileEntity.tileEntities,
		apiKey: _state.api.key,
	}
}

const mapDispatchToProps = (dispatch) => {
	return {
		requestWorlds: () => dispatch(requestWorlds(true)),
		requestEntities: () => dispatch(requestEntities(true)),
		requestPlayers: () => dispatch(requestPlayers(true)),
		requestTileEntities: () => dispatch(requestTileEntities(true)),
	}
}

export default connect(mapStateToProps, mapDispatchToProps)(Map);
<commit_msg>feat(map): Improve map display<commit_after>import React, { Component } from 'react'
import { connect } from "react-redux"
import { Stage, Layer, Image, Circle, Line } from "react-konva"
import { Segment, Header, Button, Progress, Dropdown } from "semantic-ui-react"
import Slider from "rc-slider"
import _ from "lodash"

import Inventory from "../../components/Inventory"
import { formatRange } from "../../components/Util"

import { requestWorlds } from "../../actions/world"
import { requestEntities } from "../../actions/entity"
import { requestPlayers } from "../../actions/player"
import { requestTileEntities } from "../../actions/tile-entity"

const TILE_SIZE = 512;
const HALF_TILE = TILE_SIZE / 2;
const ZOOM_SPEED = 0.01;
const MIN_ZOOM = 0.1;
const MAX_ZOOM = 16.0;

const totalOffset = (element) => {
		let top = 0;
		let left = 0;

		do {
				top += element.offsetTop  || 0;
				left += element.offsetLeft || 0;
				element = element.offsetParent;
		} while(element);

		return {
				top: top,
				left: left
		};
}

const marks = {
	0.400: MIN,
	0.707: "0.25x",
	0.841: "0.5x",
	1: "-",
	1.189: "2x",
	1.414: "4x",
	1.682: "8x",
	2: MAX,
}

class Map extends Component {

	constructor(props) {
		super(props);

		this.state = {
			biomes: [],
			top: 0,
			left: 0,
			width: 0,
			height: 0,
			display: "none",
			content: null,
			center: {
				x: 0,
				z: 0,
			},
			zoom: 1,
			dragging: false,
			worldId: null,
		}

		this.timeouts = []

		this.handleObjMouseDown = this.handleObjMouseDown.bind(this)
		this.handleMouseDown = this.handleMouseDown.bind(this)
		this.handleMouseMove = this.handleMouseMove.bind(this)
		this.handleMouseOutUp = this.handleMouseOutUp.bind(this)
		this.handleWheel = this.handleWheel.bind(this)
		this.handleWorldChange = this.handleWorldChange.bind(this)

		this.updateDimensions = _.debounce(this.updateDimensions.bind(this), 500)
		this.getAllBiomes = _.debounce(this.getAllBiomes.bind(this), 500)
		this.worldToScreen = this.worldToScreen.bind(this)
		this.screenToWorld = this.screenToWorld.bind(this)
		this.center = this.center.bind(this)
	}

	componentDidMount() {
		this.props.requestEntities();
		this.props.requestPlayers();
		this.props.requestTileEntities();
		this.props.requestWorlds();

		window.addEventListener("resize", this.updateDimensions);
		this.updateDimensions();
	}

	componentWillUnmount() {
		window.removeEventListener("resize", this.updateDimensions);
	}

	updateDimensions() {
		if (!this.wrapper) return;

		this.setState({
			width: this.wrapper.offsetWidth,
			height: window.innerHeight - totalOffset(this.wrapper).top - 30,
		}, () => this.getAllBiomes())
	}

	getAllBiomes() {
		// If we didn't select a world yet do nothing
		if (!this.state.worldId) return;

		// z is inverse here because it's in screen coordinates
		const min = this.screenToWorld({ x: 0, z: this.state.height })
		const max = this.screenToWorld({ x: this.state.width, z: 0 })

		_.each(this.timeouts, timeout => clearTimeout(timeout))

		this.setState({
			biomes: _.filter(this.state.biomes, biome =>
				biome.x + HALF_TILE >= min.x && biome.x - HALF_TILE <= max.x &&
				biome.z + HALF_TILE >= min.z && biome.z - HALF_TILE <= max.z)
		}, () => {
			min.x = min.x - min.x % TILE_SIZE - TILE_SIZE
			min.z = min.z - min.z % TILE_SIZE - TILE_SIZE

			max.x = max.x - max.x % TILE_SIZE + TILE_SIZE
			max.z = max.z - max.z % TILE_SIZE + TILE_SIZE

			let index = 0;
			this.timeouts = [];
			for (let x = min.x; x <= max.x; x += TILE_SIZE) {
				for (let z = min.z; z <= max.z; z += TILE_SIZE) {
					if (_.find(this.state.biomes, { x: x, z: z }))
						continue;

					this.timeouts.push(
						setTimeout(() => this.getBiome(x, z), index * 100)
					)
					index++;
				}
			}
		})
	}

	getBiome(x, z) {
		const image = new window.Image();
		image.src = "/api/map/" + this.state.worldId + "/" + (x / TILE_SIZE) + "/" + (z / TILE_SIZE) + "?key=" + this.props.apiKey;
		image.onload = () => {
			this.setState({
				biomes: _.concat(this.state.biomes, {
					x: x,
					z: z,
					image,
				})
			})
		}
	}

	handleWorldChange(event, data) {
		this.setState({
			biomes: [],
			worldId: data.value,
		}, () => this.getAllBiomes())
	}

	handleObjMouseDown(event, obj) {
		event.evt.cancelBubble = true;

		const loc = this.worldToScreen(obj.location.position)

		this.setState({
			left: loc.x,
			top: loc.z,
			display: "block",
			content: <Segment>

						{obj.name ? obj.name : obj.type ? obj.type : obj.uuid ? obj.uuid : null}

					{obj.inventory &&
						<Inventory items={obj.inventory.items} />}
					{obj.health &&
						<Progress
							progress
							color="red"
							percent={formatRange(obj.health.current, obj.health.max)}
						/>}
					{obj.food &&
						<Progress
							progress
							color="green"
							percent={formatRange(obj.food.foodLevel, 20)}
						/>}
					<Button color="red" onClick={() => this.deleteEntity(obj)}>
						Destroy
					</Button>
				</Segment>,
		})
	}

	handleMouseDown(event) {
		if (event.evt.cancelBubble) return;

		this.setState({
			dragging: true,
			display: "none",
		})
	}

	handleMouseMove(event) {
		if (!this.state.dragging) return;

		this.setState({
			center: {
				x: this.state.center.x + event.evt.movementX / this.state.zoom,
				z: this.state.center.z - event.evt.movementY / this.state.zoom,
			}
		}, () => this.getAllBiomes())
	}

	handleMouseOutUp(event) {
		if (event.evt.cancelBubble) return;

		this.setState({
			dragging: false,
		})
	}

	handleWheel(event) {
		const d = event.evt.deltaY
		const diff = Math.abs(d * ZOOM_SPEED)
		const newValue = d > 0 ? this.state.zoom / diff : this.state.zoom * diff

		this.setState({
			zoom: Math.min(Math.max(newValue, MIN_ZOOM), MAX_ZOOM),
		}, () => this.getAllBiomes())
	}

	handleZoomChange(value) {
		this.setState({
			zoom: Math.min(Math.max(Math.pow(value, 4), MIN_ZOOM), MAX_ZOOM),
		}, () => this.getAllBiomes())
	}

	deleteEntity(entity) {

	}

	center() {
		return {
			x: Math.floor(this.state.width / 2) + this.state.center.x * this.state.zoom,
			z: Math.floor(this.state.height / 2) - this.state.center.z * this.state.zoom,
		}
	}

	worldToScreen({ x, z }) {
		const center = this.center()
		return {
			x: center.x + x * this.state.zoom,
			z: center.z - z * this.state.zoom,
		}
	}

	screenToWorld({ x, z }) {
		const center = this.center()
		return {
			x: (x - center.x) / this.state.zoom,
			z: (center.z - z) / this.state.zoom,
		}
	}

	render() {
		const center = this.center()
		const cX = center.x
		const cZ = center.z

		return (
			<Segment basic style={{ position: "relative" }}>

 this.wrapper = w}>
					<Stage width={this.state.width} height={this.state.height} ref={s => this.stage = s}
							onContentMouseDown={e => this.handleMouseDown(e)}
							onContentMouseUp={e => this.handleMouseOutUp(e)}
							onContentMouseOut={e => this.handleMouseOutUp(e)}
							onContentMouseMove={e => this.handleMouseMove(e)}
							onContentWheel={e => this.handleWheel(e)}>
						<Layer>
						{ _.map(this.state.biomes, biome => {
								const pos = this.worldToScreen(biome)

								return <Image
									key={biome.x + "+" + biome.z}
									x={pos.x - HALF_TILE * this.state.zoom}
									y={pos.z - HALF_TILE * this.state.zoom}
									image={biome.image}
									width={TILE_SIZE * this.state.zoom}
									height={TILE_SIZE * this.state.zoom}
								/>
						})}
						</Layer>
						<Layer>
							<Line points={[0, cZ, 2000, cZ]} stroke="Black" strokeWidth={1} />
							<Line points={[cX, 0, cX, 2000]} stroke="Black" strokeWidth={1} />
						</Layer>
						<Layer>
							{ _.map(_.filter(this.props.entities, e => e.location.world.uuid === this.state.worldId), ent => {
								const pos = this.worldToScreen(ent.location.position)

								return <Circle
									key={ent.uuid}
									x={pos.x - 4}
									y={pos.z - 4}
									width={8}
									height={8}
									fill={"Red"}
									perfectDrawEnabled={false}
									onMouseDown={e => this.handleObjMouseDown(e, ent)}
								/>
							})}
							{ _.map(_.filter(this.props.players, p => p.location.world.uuid === this.state.worldId), player => {
								const pos = this.worldToScreen(player.location.position)

								return <Circle
									key={player.uuid}
									x={pos.x - 4}
									y={pos.z - 4}
									width={8}
									height={8}
									fill={"Gold"}
									perfectDrawEnabled={false}
									onMouseDown={e => this.handleObjMouseDown(e, player)}
								/>
							})}
							{ _.map(_.filter(this.props.tileEntities, te => te.location.world.uuid === this.state.worldId), te => {
								const pos = this.worldToScreen(te.location.position)

								return <Circle
									key={"te-" + te.location.position.x + "-" + te.location.position.z}
									x={pos.x - 4}
									y={pos.z - 4}
									width={8}
									height={8}
									fill={"Green"}
									perfectDrawEnabled={false}
									onMouseDown={e => this.handleObjMouseDown(e, te)}
								/>
							})}
						</Layer>
					</Stage>

						{this.state.content}

				<Segment style={{ position: "absolute", "top": 0, "left": 10 }}>
					<Dropdown
						id="world" placeholder="Select world..."
						value={this.state.worldId} onChange={this.handleWorldChange}
						options={_.map(this.props.worlds, world =>
							({
								value: world.uuid,
								text: world.name + " (" + world.dimensionType.name + ")"
							})
						)}
					/>
				</Segment>
				<Segment style={{ position: "absolute", "top": 60, "left": 10, height: "25vh", width: 80 }}>
					<Slider
						vertical
						marks={marks}
						min={0.400}
						max={2}
						step={0.001}
						value={Math.pow(this.state.zoom, 1/4)}
						onChange={v => this.handleZoomChange(v)}
						trackStyle={{ backgroundColor: 'blue' }}
						handleStyle={{ borderColor: 'blue' }}
					/>
				</Segment>
			</Segment>
		)
	}
}

const mapStateToProps = (_state) => {
	return {
		entities: _state.entity.entities,
		worlds: _state.world.worlds,
		players: _state.player.players,
		tileEntities: _state.tileEntity.tileEntities,
		apiKey: _state.api.key,
	}
}

const mapDispatchToProps = (dispatch) => {
	return {
		requestWorlds: () => dispatch(requestWorlds(true)),
		requestEntities: () => dispatch(requestEntities(true)),
		requestPlayers: () => dispatch(requestPlayers(true)),
		requestTileEntities: () => dispatch(requestTileEntities(true)),
	}
}

export default connect(mapStateToProps, mapDispatchToProps)(Map);
<|endoftext|>


<commit_before>import events from '../../lib/layerEvents';

let mapboxSourceProps = {
  sourceId: {
    type: String
  }
}

let mapboxLayerStyleProps = {
  layerId: {
    type: String,
    required: true
  },
  metadata: Object,
  refLayer: String,
  'source-layer': String,
  minzoom: Number,
  maxzoom: Number,
  paint: Object,
  before: Object
}

let componentProps = {
  eventsToListen: {
    validator(eventsArray) {
      if (!(eventsArray instanceof Array)) {
        return false;
      }
      for (let e of eventsArray) {
        if (!events.includes(e)) return false;
      }
      return true;
    },
    default: () => []
  },
  clearSource: {
    type: Boolean,
    default: true
  },
  hidden: {
    type: Boolean,
    default: false
  },
  replaceSource: {
    type: Boolean,
    default: false
  },
  replace: {
    type: Boolean,
    default: false
  }
}

import bus from '../../messageBus';
import layerEvents from '../../lib/layerEvents';

export default {
  props: {
    ...mapboxSourceProps,
    ...mapboxLayerStyleProps,
    ...componentProps
  },

  data() {
    return {
      initial: true,
      map: undefined
    }
  },

  computed: {
    sourceLoaded() {
      return this.map.isSourceLoaded(this.sourceId);
    },
    mapLayer() {
      return this.map.getLayer(this.layerId);
    }
  },

  watch: {
    eventsToListen(events) {
      if (this.initial) return;
      this.unBindEvents(layerEvents);
      this.bindEvents(events);
    }
  },

  beforeDestroy() {
    if (this.map) {
      this.map.removeLayer(this.layerId);
      if (this.clearSource) {
        try {
          this.map.removeSource(this.sourceId)
        } catch (error) {
          this.$emit('mgl-source-does-not-exist', error);
          bus.$emit('mgl-source-does-not-exist', error);
        }
      }
    }
  },

  methods: {
    _bindEvents(events) {
      if (events.length === 0) return;
      events.forEach(eventName => {
        this.map.on(eventName, this.layerId, event => {
          this.$emit(`mgl-${ event }`, event);
        })
      });
    },

    _unBindEvents(events) {
      events.forEach(eventName => {
        this.map.off(eventName, this.layerId);
      });
    },

    _watchSourceLoading(data) {
      if (data.dataType === 'source' && data.sourceId === this.sourceId) {
        this._emitSourceLoading();
        this.map.off('dataloading', this.watchSourceLoading)
      }
    },

    _emitSourceLoading() {
      this.$emit('mgl-layer-source-loading', {
        sourceId: this.sourceId,
        map: this.map,
        component: this
      });
      bus.$emit('mgl-layer-source-loading', {
        sourceId: this.sourceId,
        map: this.map,
        component: this
      });
    },

    _emitSourceError(error) {
      this.$emit('mgl-layer-source-error', {
        map: this.map,
        component: this,
        sourceId: this.sourceId,
        error
      });
      bus.$emit('mgl-layer-source-error', {
        map: this.map,
        component: this,
        sourceId: this.sourceId,
        error
      });
    },

    _emitLayerError(error) {
      this.$emit('mgl-layer-error', {
        map: this.map,
        component: this,
        layerId: this.layerId,
        error
      });
      bus.$emit('mgl-layer-error', {
        map: this.map,
        component: this,
        layerId: this.layerId,
        error
      });
    },

    _emitLayerExists() {
      this.$emit('mgl-layer-exists', {
        map: this.map,
        component: this,
        layer: this.layerId
      });
      bus.$emit('mgl-layer-exists', {
        map: this.map,
        component: this,
        layer: this.layerId
      });
    },

    _emitLayerAdded() {
      this.$emit('mgl-layer-added', {
        map: this.map,
        component: this,
        layerId: this.layerId
      });
      bus.$emit('mgl-layer-added', {
        map: this.map,
        component: this,
        layerId: this.layerId
      });
    },

    _emitLayerRemoved() {
      this.$emit('mgl-layer-removed', {
        map: this.map,
        component: this,
        layerId: this.layerId
      });
      bus.$emit('mgl-layer-removed', {
        map: this.map,
        component: this,
        layerId: this.layerId
      });
    },

    move(beforeId) {
      this.map.moveLayer(this.layerId, beforeId);
    }
  }
}
<commit_msg>Refactoring layer events emitter Organizing common code for emitting event into method _emitMapEvent()<commit_after>import events from '../../lib/layerEvents';

let mapboxSourceProps = {
  sourceId: {
    type: String
  }
}

let mapboxLayerStyleProps = {
  layerId: {
    type: String,
    required: true
  },
  metadata: Object,
  refLayer: String,
  'source-layer': String,
  minzoom: Number,
  maxzoom: Number,
  paint: Object,
  before: Object
}

let componentProps = {
  eventsToListen: {
    validator(eventsArray) {
      if (!(eventsArray instanceof Array)) {
        return false;
      }
      for (let e of eventsArray) {
        if (!events.includes(e)) return false;
      }
      return true;
    },
    default: () => []
  },
  clearSource: {
    type: Boolean,
    default: true
  },
  hidden: {
    type: Boolean,
    default: false
  },
  replaceSource: {
    type: Boolean,
    default: false
  },
  replace: {
    type: Boolean,
    default: false
  }
}

import bus from '../../messageBus';
import layerEvents from '../../lib/layerEvents';

export default {
  props: {
    ...mapboxSourceProps,
    ...mapboxLayerStyleProps,
    ...componentProps
  },

  data() {
    return {
      initial: true,
      map: undefined
    }
  },

  computed: {
    sourceLoaded() {
      return this.map.isSourceLoaded(this.sourceId);
    },
    mapLayer() {
      return this.map.getLayer(this.layerId);
    }
  },

  watch: {
    eventsToListen(events) {
      if (this.initial) return;
      this.unBindEvents(layerEvents);
      this.bindEvents(events);
    }
  },

  beforeDestroy() {
    if (this.map) {
      this.map.removeLayer(this.layerId);
      if (this.clearSource) {
        try {
          this.map.removeSource(this.sourceId)
        } catch (error) {
          this.$emit('mgl-source-does-not-exist', error);
          bus.$emit('mgl-source-does-not-exist', error);
        }
      }
    }
  },

  methods: {
    _bindEvents(events) {
      if (events.length === 0) return;
      events.forEach(eventName => {
        this.map.on(eventName, this.layerId, event => {
          this.$emit(`mgl-${ event }`, event);
        })
      });
    },

    _unBindEvents(events) {
      events.forEach(eventName => {
        this.map.off(eventName, this.layerId);
      });
    },

    _watchSourceLoading(data) {
      if (data.dataType === 'source' && data.sourceId === this.sourceId) {
        this._emitSourceLoading();
        this.map.off('dataloading', this.watchSourceLoading)
      }
    },

    _emitMapEvent(name, data={}) {
      this.$emit(name, {
        map: this.map,
        component: this,
        ...data
      });
      bus.$emit(name, {
        map: this.map,
        component: this,
        ...data
      });
    },

    _emitSourceLoading() {
      this._emitMapEvent('mgl-layer-source-loading', { sourceId: this.sourceId });
    },

    _emitSourceError(error) {
      this._emitMapEvent('mgl-layer-source-error', { sourceId: this.sourceId, error });
    },

    _emitLayerError(error) {
      this._emitMapEvent('mgl-layer-error', { layerId: this.layerId, error });
    },

    _emitLayerExists() {
      this._emitMapEvent('mgl-layer-exists', { layerId: this.layerId });
    },

    _emitLayerAdded() {
      this._emitMapEvent('mgl-layer-added', { layerId: this.layerId });
    },

    _emitLayerRemoved() {
      this._emitMapEvent('mgl-layer-removed', { layerId: this.layerId });
    },

    _emitLayerMoved(beforeId) {
      this._emitMapEvent('mgl-layer-moved', { layerId: this.layerId, beforeId: beforeId });
    },

    move(beforeId) {
      this.map.moveLayer(this.layerId, beforeId);
      this._emitLayerMoved(beforeId);
    }
  }
}
<|endoftext|>


<commit_before>/* ======= Instance Methods ======= */

var hasConsole = typeof window.console !== undefined;

/**
* Logs a Message
* @param {String} msg
*/
Moon.prototype.log = function(msg) {
  if(!config.silent && hasConsole) console.log(msg);
}

/**
* Throws an Error
* @param {String} msg
*/
Moon.prototype.error = function(msg) {
  if(hasConsole) console.error("[Moon] ERR: " + msg);
}

/**
* Sets Value in Data
* @param {String} key
* @param {String} val
*/
Moon.prototype.set = function(key, val) {
  this.$data[key] = val;
  if(!this.$destroyed) this.build(this.$el.childNodes, this.$dom.children);
  this.$hooks.updated();
}

/**
* Gets Value in Data
* @param {String} key
* @return {String} Value of key in data
*/
Moon.prototype.get = function(key) {
  return this.$data[key];
}

/**
* Calls a method
* @param {String} method
*/
Moon.prototype.callMethod = function(method, args) {
  args = args || [];
  this.$methods[method].apply(this, args);
}

/**
* Destroys Moon Instance
*/
Moon.prototype.destroy = function() {
  Object.defineProperty(this, '$data', {
    set: function(value) {
      _data = value;
    }
  });
  this.$destroyed = true;
  this.$hooks.destroyed();
}

/**
* Builds the DOM With Data
* @param {Array} children
*/
Moon.prototype.build = function(children, vdom) {
  for(var i = 0; i < children.length; i++) {
    var vnode = vdom[i];
    var child = children[i];
    if(vnode !== undefined && !vnode.once) {
      if(child.nodeName === "#text") {
        var valueOfVNode = "";
        valueOfVNode = vnode.val(this.$data);
        child.textContent = valueOfVNode;
      } else if(vnode.props) {
        for(var attr in vnode.props) {
          var compiledProp = vnode.props[attr](this.$data);
          if(directives[attr]) {
            child.removeAttribute(attr);
            directives[attr](child, compiledProp, vnode);
          } else {
            child.setAttribute(attr, compiledProp);
          }
        }
      }

      this.build(child.childNodes, vnode.children);
    }
  }
}

/**
* Initializes Moon
*/
Moon.prototype.init = function() {
  this.log("======= Moon =======");
  this.$hooks.created();

  setInitialElementValue(this.$el, this.$template);

  this.$dom = createVirtualDOM(this.$el);

  this.build(this.$el.childNodes, this.$dom.children);
  this.$hooks.mounted();
}
<commit_msg>take only virtual dom as param<commit_after>/* ======= Instance Methods ======= */

var hasConsole = typeof window.console !== undefined;

/**
* Logs a Message
* @param {String} msg
*/
Moon.prototype.log = function(msg) {
  if(!config.silent && hasConsole) console.log(msg);
}

/**
* Throws an Error
* @param {String} msg
*/
Moon.prototype.error = function(msg) {
  if(hasConsole) console.error("[Moon] ERR: " + msg);
}

/**
* Sets Value in Data
* @param {String} key
* @param {String} val
*/
Moon.prototype.set = function(key, val) {
  this.$data[key] = val;
  if(!this.$destroyed) this.build(this.$el.childNodes, this.$dom.children);
  this.$hooks.updated();
}

/**
* Gets Value in Data
* @param {String} key
* @return {String} Value of key in data
*/
Moon.prototype.get = function(key) {
  return this.$data[key];
}

/**
* Calls a method
* @param {String} method
*/
Moon.prototype.callMethod = function(method, args) {
  args = args || [];
  this.$methods[method].apply(this, args);
}

/**
* Destroys Moon Instance
*/
Moon.prototype.destroy = function() {
  Object.defineProperty(this, '$data', {
    set: function(value) {
      _data = value;
    }
  });
  this.$destroyed = true;
  this.$hooks.destroyed();
}

/**
* Builds the DOM With Data
* @param {Array} children
*/
Moon.prototype.build = function(vdom) {
  for(var i = 0; i < children.length; i++) {
    var vnode = vdom[i];
    if(vnode !== undefined && !vnode.once) {
      if(child.nodeName === "#text") {
        var valueOfVNode = "";
        valueOfVNode = vnode.val(this.$data);
        child.textContent = valueOfVNode;
      } else if(vnode.props) {
        for(var attr in vnode.props) {
          var compiledProp = vnode.props[attr](this.$data);
          if(directives[attr]) {
            child.removeAttribute(attr);
            directives[attr](child, compiledProp, vnode);
          } else {
            child.setAttribute(attr, compiledProp);
          }
        }
      }

      this.build(child.childNodes, vnode.children);
    }
  }
}

/**
* Initializes Moon
*/
Moon.prototype.init = function() {
  this.log("======= Moon =======");
  this.$hooks.created();

  setInitialElementValue(this.$el, this.$template);

  this.$dom = createVirtualDOM(this.$el);

  this.build(this.$el.childNodes, this.$dom.children);
  this.$hooks.mounted();
}
<|endoftext|>


<commit_before>import React from "react";
import _ from "lodash";
import { styles, options } from "./index";
import cssColors from "css-color-names"
import typeScale from "./styles/typeScale"
import lineHeights from "./styles/lineHeight"

/*
 * Wrap takes a Component or a render function and recursively replaces
 * the prop 'cls' (or custom overridden prop name) with the respective 'style' definitions.
 * Render functions are decorated so that when they are invoked the resulting
 * element tree will be be recursively evaluated and 'cls' will be replaced with
 * 'style' definitions.
 */
export function wrap(componentOrFunction) {
    if (!(componentOrFunction.prototype && "render" in componentOrFunction.prototype)) {
        const func = componentOrFunction;

        return function wrappedRender(...args) {
            /* eslint-disable no-invalid-this */
            return recursiveStyle(func.apply(this, args))
        };
    }
    const WrappedComponent = componentOrFunction;
    const newClass = class extends WrappedComponent {
        render() {
            return recursiveStyle(super.render());
        }
    }

    /* Fix name */
    newClass.displayName = WrappedComponent.displayName || WrappedComponent.name

    return newClass;
}

function setStyles(props, clsPropName) {
    const newProps = {}
    if (_.isArray(props.style)) {
        newProps.style = props.style.slice()

    } else if (_.isObject(props.style)) {
        newProps.style = [props.style]

    } else {
        newProps.style = []
    }

    const splitted = props[clsPropName].replace(/-/gu, "_").split(" ")
    const fontSize = _.find(_.keys(typeScale), fSetting => _.includes(splitted, fSetting));

    for (let i = 0; i < splitted.length; i++) {
        const cls = splitted[i];
        if (cls.length > 0) {
            if (styles[cls]) {

                /* Style found */
                newProps.style.push(styles[cls]);

            } else if (cls.startsWith("lh_")) {

                /* Get font style */
                if (!_.isString(fontSize)) {
                    throw new Error(`setting '${cls}' needs explicit font-size`);
                }

                newProps.style.push({
                    lineHeight: lineHeights[cls.replace(/_/gu, "-")] * styles[fontSize].fontSize
                })

            } else if (cls.startsWith("bg_")) {
                newProps.style.push({
                    backgroundColor: cls.slice(3)
                })

            } else if (cls.startsWith("b__")) {
                newProps.style.push({
                    borderColor: cls.slice(3)
                })

            } else if (cls.startsWith("tint_")) {
                newProps.style.push({
                    tintColor: cls.slice(3)
                })

            } else if (cssColors[cls] || (/^(rgb|#|hsl)/).test(cls)) {
                newProps.style.push({
                    color: cls
                })

            } else {
                throw new Error(`style '${cls}' not found`);
            }

        }
    }

    return newProps;
}

function recursiveStyle(elementsTree) {
    const { props } = elementsTree;
    const { clsPropName } = options;
    let newProps = null;
    let translated = false;

    /* Parse cls string */
    if (_.isString(props[clsPropName])) {
        translated = true;
        newProps = setStyles(props, clsPropName);
    }

    let newChildren = props.children;
    if (_.isArray(newChildren)) {

        /* Convert child array */
        newChildren = React.Children.toArray(newChildren);
        for (let i = 0; i < newChildren.length; i++) {
            const c = newChildren[i];
            if (React.isValidElement(c)) {
                const converted = recursiveStyle(c);
                if (converted !== c) {
                    translated = true;
                    newChildren[i] = converted;
                }
            }
        }

    } else if (React.isValidElement(newChildren)) {

        /* Convert single child */
        const converted = recursiveStyle(newChildren);
        if (converted !== newChildren) {
            translated = true;
            newChildren = converted;
        }
    } else if (_.isFunction(newChildren)) {

        /* Convert a fumction child to evaluate on invocation */
        const originalChildrenFunction = newChildren;
        const converted = (...args) => recursiveStyle(originalChildrenFunction(...args));
        if (converted !== newChildren) {
            translated = true;
            newChildren = converted;
        }
    }

    if (translated) {
        return React.cloneElement(elementsTree, newProps, newChildren)
    }

    return elementsTree;
}
<commit_msg>forgot one<commit_after>import React from "react";
import _ from "lodash";
import { styles, options } from "./index";
import cssColors from "css-color-names"
import typeScale from "./styles/typeScale"
import lineHeights from "./styles/lineHeight"

/*
 * Wrap takes a Component or a render function and recursively replaces
 * the prop 'cls' (or custom overridden prop name) with the respective 'style' definitions.
 * Render functions are decorated so that when they are invoked the resulting
 * element tree will be be recursively evaluated and 'cls' will be replaced with
 * 'style' definitions.
 */
export function wrap(componentOrFunction) {
    if (!(componentOrFunction.prototype && "render" in componentOrFunction.prototype)) {
        const func = componentOrFunction;

        return function wrappedRender(...args) {
            /* eslint-disable no-invalid-this */
            return recursiveStyle(func.apply(this, args))
        };
    }
    const WrappedComponent = componentOrFunction;
    const newClass = class extends WrappedComponent {
        render() {
            return recursiveStyle(super.render());
        }
    }

    /* Fix name */
    newClass.displayName = WrappedComponent.displayName || WrappedComponent.name

    return newClass;
}

function setStyles(props, clsPropName) {
    const newProps = {}
    if (_.isArray(props.style)) {
        newProps.style = props.style.slice()

    } else if (_.isObject(props.style)) {
        newProps.style = [props.style]

    } else {
        newProps.style = []
    }

    const splitted = props[clsPropName].replace(/-/gu, "_").split(" ")
    const fontSize = _.find(_.keys(typeScale), fSetting => _.includes(splitted, fSetting));

    for (let i = 0; i < splitted.length; i++) {
        const cls = splitted[i];
        if (cls.length > 0) {
            if (styles[cls]) {

                /* Style found */
                newProps.style.push(styles[cls]);

            } else if (cls.startsWith("lh_")) {

                /* Get font style */
                if (!_.isString(fontSize)) {
                    throw new Error(`setting '${cls}' needs explicit font-size`);
                }

                newProps.style.push({
                    lineHeight: lineHeights[cls.replace(/_/gu, "-")] * styles[fontSize].fontSize
                })

            } else if (cls.startsWith("bg_")) {
                newProps.style.push({
                    backgroundColor: cls.slice(3)
                })

            } else if (cls.startsWith("b__")) {
                newProps.style.push({
                    borderColor: cls.slice(3)
                })

            } else if (cls.startsWith("tint_")) {
                newProps.style.push({
                    tintColor: cls.slice(3)
                })

            } else if (cssColors[cls] || (/^(rgb|#|hsl)/u).test(cls)) {
                newProps.style.push({
                    color: cls
                })

            } else {
                throw new Error(`style '${cls}' not found`);
            }

        }
    }

    return newProps;
}

function recursiveStyle(elementsTree) {
    const { props } = elementsTree;
    const { clsPropName } = options;
    let newProps = null;
    let translated = false;

    /* Parse cls string */
    if (_.isString(props[clsPropName])) {
        translated = true;
        newProps = setStyles(props, clsPropName);
    }

    let newChildren = props.children;
    if (_.isArray(newChildren)) {

        /* Convert child array */
        newChildren = React.Children.toArray(newChildren);
        for (let i = 0; i < newChildren.length; i++) {
            const c = newChildren[i];
            if (React.isValidElement(c)) {
                const converted = recursiveStyle(c);
                if (converted !== c) {
                    translated = true;
                    newChildren[i] = converted;
                }
            }
        }

    } else if (React.isValidElement(newChildren)) {

        /* Convert single child */
        const converted = recursiveStyle(newChildren);
        if (converted !== newChildren) {
            translated = true;
            newChildren = converted;
        }
    } else if (_.isFunction(newChildren)) {

        /* Convert a fumction child to evaluate on invocation */
        const originalChildrenFunction = newChildren;
        const converted = (...args) => recursiveStyle(originalChildrenFunction(...args));
        if (converted !== newChildren) {
            translated = true;
            newChildren = converted;
        }
    }

    if (translated) {
        return React.cloneElement(elementsTree, newProps, newChildren)
    }

    return elementsTree;
}
<|endoftext|>


<commit_before>window.sv = {};
window.sv.isDebugMode = false;

//window.sv.logs = (function () {
//  var logs = [];
//  if (window.console && console.log) {
//    var oldInfo = console.info,
//      oldLog = console.log,
//      oldWarn = console.warn,
//      oldError = console.error, maxLogLengths = 100;
//
//    function logging(msg, colour, csl, thisArg, arguments) {
//      if (window.sv.isDebugMode) {
//        if (logs.length > maxLogLengths) {
//          window.clearLogs();
//        }
//
//        logs.push('
' + (JSON.stringify(arguments)) + '
');
//        csl.apply(thisArg, arguments);
//        return;
//      }
//      if(!window.sv.isDebugMode && colour === 'red'){
//        csl.apply(thisArg, arguments);
//      }
//    }
//
//    console.info = function (msg) {
//      logging(msg, 'blue', oldInfo, this, arguments);
//    };
//    console.log = function (msg) {
//      logging(msg, 'black', oldLog, this, arguments);
//    };
//    console.warn = function (msg) {
//      logging(msg, '#ff6600', oldWarn, this, arguments);
//    };
//    console.error = function (msg) {
//      logging(msg, 'red', oldError, this, arguments);
//    };
//
//  }
//
//  window.hideLogs = function () {
//    document.getElementById('logger').style.display = 'none';
//    window.clearLogs();
//  };
//
//  window.clearLogs = function () {
//    window.sv.logs.splice(0, window.sv.logs.length);
//    var logger = document.getElementById('logger');
//    logger.innerHTML = '<button class="button button-balanced button-full button-highlight" ' +
//      'onclick="hideLogs()">Hide logs </button> <button class="button button-assertive button-full"' +
//      'onclick="clearLogs()">Clear logs </button>

';
//
//  };
//
//  return logs;
//})();
//console.log('logs init? ', window.sv.logs);

// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a  attribute in index.html)
// the 2nd parameter is an array of 'requires'
// 'starter.controllers' is found in controllers.js
angular.module('svBeaconPrototype', [
    'ionic',
    'ngCordova',
    'ngStorage',
    'svBeaconPrototype.validations',
    'svBeaconPrototype.router',
    'svBeaconPrototype.messages',
    'svBeaconPrototype.offline',
    'svBeaconPrototype.network',
    'svBeaconPrototype.audio',
    'svBeaconPrototype.date',
    'svBeaconPrototype.photo',
    'svBeaconPrototype.messages',
    'svBeaconPrototype.googleGeocode',
    'svBeaconPrototype.validations',
    'svBeaconPrototype.location',
    'svBeaconPrototype.googleAnalytics'
  ])

  .run(function ($log, $rootScope, $window, Router, Cordovas) {
    $log.info('Welcome to SpeciesReporting...');

    $rootScope.isDebugMode = ($window.sv && $window.sv.isDebugMode);

    function init() {

      // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
      // for form inputs)
      if (window.cordova && window.cordova.plugins.Keyboard) {
        cordova.plugins.Keyboard.hideKeyboardAccessoryBar(false);
        cordova.plugins.Keyboard.disableScroll(true);

        cordova.getAppVersion(function (version) {
          $rootScope.appVersion = version;
        });

      }

      if (window.StatusBar) {
        // org.apache.cordova.statusbar required
        StatusBar.styleDefault();
      }

      if ($window.screen && $window.screen.lockOrientation) {
        $window.screen.lockOrientation('portrait');
      }
    }

    Cordovas.isAppReady().then(function(){
      Router.init($rootScope);
    });

    Cordovas.isPluginsReady().then(function () {
      init();
    })
  })

  .config(function ($stateProvider, $urlRouterProvider, $ionicConfigProvider) {
    $ionicConfigProvider.views.swipeBackEnabled(false);
    $stateProvider

      .state('app', {
        url: '/app',
        abstract: true,
        templateUrl: 'features/side-menu/side-menu.tpl.html',
        controller: 'SideMenuCtrl'
      })

      .state('app.home', {
        url: '/home',
        views: {
          'menuContent': {
            templateUrl: 'features/home/home.tpl.html',
            controller: 'HomeCtrl'
          }
        }
      })

      .state('app.range', {
        url: '/range',
        views: {
          'menuContent': {
            templateUrl: 'features/range/range.tpl.html',
            controller: 'RangeCtrl'
          }
        }
      })

      .state('app.register', {
        url: '/register',
        views: {
          'menuContent': {
            templateUrl: 'features/register/register.tpl.html',
            controller: 'RegisterCtrl'
          }
        }
      })

      .state('app.my-details', {
        url: '/my-details',
        views: {
          'menuContent': {
            templateUrl: 'features/my-details/my-details.tpl.html',
            controller: 'MyDetailsCtrl'
          }
        }
      });

    // if none of the above states are matched, use this as the fallback
    $urlRouterProvider.otherwise('/app/home');

  });
<commit_msg>enbaling screen logger<commit_after>window.sv = {};
window.sv.isDebugMode = true;

window.sv.logs = (function () {
  var logs = [];
  if (window.console && console.log) {
    var oldInfo = console.info,
      oldLog = console.log,
      oldWarn = console.warn,
      oldError = console.error, maxLogLengths = 100;

    function logging(msg, colour, csl, thisArg, arguments) {
      if (window.sv.isDebugMode) {
        if (logs.length > maxLogLengths) {
          window.clearLogs();
        }

        logs.push('
' + (JSON.stringify(arguments)) + '
');
        csl.apply(thisArg, arguments);
        return;
      }
      if(!window.sv.isDebugMode && colour === 'red'){
        csl.apply(thisArg, arguments);
      }
    }

    console.info = function (msg) {
      logging(msg, 'blue', oldInfo, this, arguments);
    };
    console.log = function (msg) {
      logging(msg, 'black', oldLog, this, arguments);
    };
    console.warn = function (msg) {
      logging(msg, '#ff6600', oldWarn, this, arguments);
    };
    console.error = function (msg) {
      logging(msg, 'red', oldError, this, arguments);
    };

  }

  window.hideLogs = function () {
    document.getElementById('logger').style.display = 'none';
    window.clearLogs();
  };

  window.clearLogs = function () {
    window.sv.logs.splice(0, window.sv.logs.length);
    var logger = document.getElementById('logger');
    logger.innerHTML = '<button class="button button-balanced button-full button-highlight" ' +
      'onclick="hideLogs()">Hide logs </button> <button class="button button-assertive button-full"' +
      'onclick="clearLogs()">Clear logs </button>

';

  };

  return logs;
})();
console.log('logs init? ', window.sv.logs);

// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a  attribute in index.html)
// the 2nd parameter is an array of 'requires'
// 'starter.controllers' is found in controllers.js
angular.module('svBeaconPrototype', [
    'ionic',
    'ngCordova',
    'ngStorage',
    'svBeaconPrototype.validations',
    'svBeaconPrototype.router',
    'svBeaconPrototype.messages',
    'svBeaconPrototype.offline',
    'svBeaconPrototype.network',
    'svBeaconPrototype.audio',
    'svBeaconPrototype.date',
    'svBeaconPrototype.photo',
    'svBeaconPrototype.messages',
    'svBeaconPrototype.googleGeocode',
    'svBeaconPrototype.validations',
    'svBeaconPrototype.location',
    'svBeaconPrototype.googleAnalytics'
  ])

  .run(function ($log, $rootScope, $window, Router, Cordovas) {
    $log.info('Welcome to SpeciesReporting...');

    $rootScope.isDebugMode = ($window.sv && $window.sv.isDebugMode);

    function init() {

      // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
      // for form inputs)
      if (window.cordova && window.cordova.plugins.Keyboard) {
        cordova.plugins.Keyboard.hideKeyboardAccessoryBar(false);
        cordova.plugins.Keyboard.disableScroll(true);

        cordova.getAppVersion(function (version) {
          $rootScope.appVersion = version;
        });

      }

      if (window.StatusBar) {
        // org.apache.cordova.statusbar required
        StatusBar.styleDefault();
      }

      if ($window.screen && $window.screen.lockOrientation) {
        $window.screen.lockOrientation('portrait');
      }
    }

    Cordovas.isAppReady().then(function(){
      Router.init($rootScope);
    });

    Cordovas.isPluginsReady().then(function () {
      init();
    })
  })

  .config(function ($stateProvider, $urlRouterProvider, $ionicConfigProvider) {
    $ionicConfigProvider.views.swipeBackEnabled(false);
    $stateProvider

      .state('app', {
        url: '/app',
        abstract: true,
        templateUrl: 'features/side-menu/side-menu.tpl.html',
        controller: 'SideMenuCtrl'
      })

      .state('app.home', {
        url: '/home',
        views: {
          'menuContent': {
            templateUrl: 'features/home/home.tpl.html',
            controller: 'HomeCtrl'
          }
        }
      })

      .state('app.range', {
        url: '/range',
        views: {
          'menuContent': {
            templateUrl: 'features/range/range.tpl.html',
            controller: 'RangeCtrl'
          }
        }
      })

      .state('app.register', {
        url: '/register',
        views: {
          'menuContent': {
            templateUrl: 'features/register/register.tpl.html',
            controller: 'RegisterCtrl'
          }
        }
      })

      .state('app.my-details', {
        url: '/my-details',
        views: {
          'menuContent': {
            templateUrl: 'features/my-details/my-details.tpl.html',
            controller: 'MyDetailsCtrl'
          }
        }
      });

    // if none of the above states are matched, use this as the fallback
    $urlRouterProvider.otherwise('/app/home');

  });
<|endoftext|>


<commit_before>/* @flow */

import { isPayPalDomain } from '@paypal/sdk-client/src';
import { PopupOpenError as _PopupOpenError } from 'zoid/src';

import { setupLogger, allowIframe as _allowIframe } from '../lib';
import { getCheckoutComponent } from '../checkout';
import { getButtonsComponent } from '../buttons';

const CheckoutComponent = getCheckoutComponent();

export const Buttons = getButtonsComponent();
export let Checkout;
export let PopupOpenError;
export let allowIframe;

if (isPayPalDomain()) {
    Checkout = CheckoutComponent;
    PopupOpenError = _PopupOpenError;
    allowIframe = _allowIframe;
}

export function setupButtons() {
    setupLogger();
}
<commit_msg>Temporarily add paypal.request<commit_after>/* @flow */

import { isPayPalDomain } from '@paypal/sdk-client/src';
import { PopupOpenError as _PopupOpenError } from 'zoid/src';

import { setupLogger, allowIframe as _allowIframe } from '../lib';
import { getCheckoutComponent } from '../checkout';
import { getButtonsComponent } from '../buttons';

const CheckoutComponent = getCheckoutComponent();

export const Buttons = getButtonsComponent();
export let Checkout;
export let PopupOpenError;
export let allowIframe;

export const request = {
    addHeaderBuilder: () => {
        // pass
    }
};

if (isPayPalDomain()) {
    Checkout = CheckoutComponent;
    PopupOpenError = _PopupOpenError;
    allowIframe = _allowIframe;
}

export function setupButtons() {
    setupLogger();
}
<|endoftext|>


<commit_before><commit_msg>unload room settings if room does not have any<commit_after><|endoftext|>


<commit_before>$(function() {
  parseGET();
  if (typeof frame_map === "undefined") frame_map = false; // in frame_map mode we have limited controls and map abilities

  var loc = osm.getCookie('_osm_location');
  var center;
  var zoom;
  var layer = 'M';
  var overlaysAsString = '';
  if(loc) {
    var locs = loc.split('|');
    center = new L.LatLng(locs[1], locs[0]);
    zoom = locs[2];
    layer = locs[3] || 'M';
    overlaysAsString = locs[4] || '';
  } else if(clientLat || clientLon) {
    center = new L.LatLng(clientLat, clientLon);
    zoom = 12;
    layer = "M";
  }
  else {
    center = new L.LatLng(62.0, 88.0);
    zoom = $(window).width() > 1200 ? 3 : 2;
    layer = "M";
  }

  osm.initLayers();

  //some pice of paranoia
  baseLayer = osm.layers[osm.layerHash2name[layer]] || osm.layers.layerMapnik;

  osm.map = new L.Map('map', {zoomControl: false, center: center, zoom: zoom, layers: [baseLayer]});

  if (!frame_map)
    osm.map.addLayer(osm.layers.search_marker);
  for(var i = 0; i < overlaysAsString.length; i++){
        //don't save OSB layer
        var hash = overlaysAsString.charAt(i);
        if(hash != 'U'){
            var over = osm.layers[osm.layerHash2name[hash]];
            if(over){
                osm.map.addLayer(over);
            }
        }
  }

  L.Icon.Default.imagePath='/img';
  osm.markers.initialize();
  osm.markers.readMap();

  if (!frame_map) {
    $("#leftpan div h1").bind('click',function(){
      osm.leftpan.toggle(this.parentNode.id, true);
    });
    osm.leftpan.on=true;
    osm.leftpan.refsizetab();
  }

 if (!frame_map) {
  osm.map.control_layers = new L.Control.Layers(
    osm.baseLayers,
    osm.overlays,
    {
      layerHashes: osm.layerHashes
    }
  );
  osm.map.addControl(osm.map.control_layers);

  osm.leftpan.panel = $_('leftpan');
  osm.leftpan.content = $_('content_pan');
  osm.mappan.panel = $_('mappan');
  osm.input = $_('qsearch');
  osm.input.focus();
  osm.search_marker = new L.LayerGroup();
  osm.map.addLayer(osm.search_marker);

  if (osm.getCookie("_osm_htp") == "false")
    osm.ui.togglehtp();
  if (osm.getCookie("_osm_leftpan") == "false")
    setTimeout("osm.leftpan.toggle(false)", 500);

  osm.map.addControl(new L.Control.Scale({width: 100, position: 'bottomleft'}));

  osm.map.permalink = new L.Control.Permalink(osm.map.control_layers);
  osm.map.addControl(osm.map.permalink);
  osm.map.addControl(new L.Control.Zoom({shiftClick: true}));
  osm.map.addControl(new L.Control.Distance());
  osm.map.addControl(new L.Control.inJOSM({target:'hiddenIframe', linktitle: 'Редактировать в JOSM'}));
  osm.validators.initialize();
  osm.poi.initialize();

  search.inLoad();

  osm.editUpdate();
  osm.map.on('moveend', osm.saveLocation);
  osm.map.on('layeradd', osm.saveLocation);
  osm.map.on('layerremove', osm.saveLocation);
  osm.map.on('moveend', osm.editUpdate);

  osm.layers.osb.on('add', function(){osm.osbclick($_('mainmenupage-osb').children[0],true,this);});
  osm.layers.osb.on('remove', function(){osm.osbclick($_('mainmenupage-osb').children[0],false,this);});
  osm.setLinkOSB();
  // osm.initModes();

  $("#mappan #htpbutton").bind("click", function(){osm.ui.togglehtp()});
  if (get.hidetoppan) osm.ui.togglehtp();

  if ($('#leftpantab').height()>300)
    osm.dyk.load();
  $(window).resize(osm.leftpan.refsizetab);

  osm.map.on('moveend', osm.opento);

 }
});

osm.initLayers = function(){

  osm.layerHashes = {};
  osm.layerHash2name = {};
  osm.layerHash2title = {};
  osm.baseLayers = {};
  osm.overlays = {};

  osm.registerLayer(
    'layerMapnik',
    new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {maxZoom: 18, attribution: "Map data © OpenStreetMap contributors"}),
    'Mapnik',
    'M',
    true
  );

  osm.registerLayer(
    'layerKosmo',
    new L.TileLayer('http://{s}.tile.osmosnimki.ru/kosmo/{z}/{x}/{y}.png', {
        maxZoom: 18,
        attribution: "Map data &copy OpenStreetMap contributors, CC-BY-SA; rendering by kosmosnimki.ru"}
    ),
    'Космоснимки',
    'K',
    true
  );

  osm.registerLayer(
    'layerMQ',
    new L.TileLayer('http://otile{s}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png', {
      maxZoom: 18,
      attribution: "Map data © OpenStreetMap contributors, tiles © " +
         "MapQuest ",
      subdomains: '1234'}),
    'MapQuest',
    'Q',
    true
  );

  osm.registerLayer(
    'layerCycle',
    new L.TileLayer('http://{s}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png', {maxZoom: 18, attribution: "Map data © OpenStreetMap contributors (Cycle)"}),
    'Велокарта',
    'C',
    true
  );

  osm.registerLayer(
    'layerMS',
    new L.TileLayer('http://129.206.74.245:8001/tms_r.ashx?x={x}&y={y}&z={z}', {
      maxZoom: 18,
      attribution: "Map data © OpenStreetMap contributors, rendering GIScience Research Group @ University of Heidelberg"}),
    'MapSurfer.net',
    'S',
    true
  );

  osm.registerLayer(
    'layerBing',
    new L.BingLayer('ApaoUzCK5_6HzEgOsPL_HFxYj-RVA2FAvcvQHX4XKeR6tjzl9lquWXiZSwBFe8h-', {maxZoom: 18}),
    'Снимки Bing',
    'B',
    true
  );

  osm.registerLayer(
    'layerEmpty',
    new L.TileLayer('img/blank.png', {maxZoom: 18}),
    'Пустой фоновый слой',
    'E',
    true
  );

/*
  osm.registerLayer(
    'layerLatlonBuildings',
    new L.TileLayer('http://{s}.tile.osmosnimki.ru/buildings/{z}/{x}/{y}.png', {maxZoom: 18, attribution: "Трёхмерные здания © LatLon.org", subdomains: 'abcdef'}),
    'Трёхмерные здания',
    'Z',
    false
  );
*/
  if (!frame_map)
  osm.registerLayer(
    'osb',
    new L.OpenStreetBugs({dblClick: false, iconOpen:"img/osb/open_bug_marker.png", iconClosed:"img/osb/closed_bug_marker.png", iconActive:"img/osb/active_bug_marker.png", editArea:0.001, bugid: get.bugid}),
    'Ошибки на карте',
    'U',
    false
  );

  osm.registerLayer(
    'layerPt',
    new L.TileLayer('http://pt.openmap.lt/{z}/{x}/{y}.png', {maxZoom: 18, attribution: "Маршруты © openmap.lt"}),
    //new L.TileLayer('http://{s}.tile.osmosnimki.ru/pt/{z}/{x}/{y}.png', {maxZoom: 18, attribution: "Маршруты © LatLon.org", subdomains: 'abcdef'}),
    'Общественный транспорт',
    'T',
    false
  );

  osm.registerLayer(
    'layerKosmoHyb',
    new L.TileLayer('http://{s}.tile.osmosnimki.ru/hyb/{z}/{x}/{y}.png', {
      maxZoom: 18,
      attribution: "Map data &copy OpenStreetMap contributors, CC-BY-SA; rendering by kosmosnimki.ru"}),
    'Космоснимки (гибрид)',
    'H',
    false
  );

  osm.registerLayer(
    'layerMSHyb',
    new L.TileLayer('http://129.206.74.245:8003/tms_h.ashx?x={x}&y={y}&z={z}', {
      maxZoom: 18,
      attribution: "Map data © OpenStreetMap contributors, rendering " +
                   "GIScience Research Group @ University of Heidelberg"}),
    'MapSurfer.net (гибрид)',
    'Y',
    false
  );

  if (!frame_map) {
  osm.registerLayer(
    'search_marker',
    new L.LayerGroup()
  );

  WPCLayer = L.KML.extend({
    visible: false,
    onAdd: function(map) {
      L.KML.prototype.onAdd.apply(this, [map]);
      this._map.on('moveend',reloadKML,this);
      this.visible = true;
      reloadKML();
    },
    onRemove: function(map) {
      this._map.off('moveend',reloadKML,this);
      this.visible = false;
      L.KML.prototype.onRemove.apply(this, [map]);
    }
  });

  wpc.layers = new WPCLayer();

  osm.registerLayer(
    'layerWikiFoto',
    wpc.layers,
    'Фото (ВикиСклад) beta',
    'W',
    false
  );

  osm.registerLayer(
    'layerWeatherCities',
     new OsmJs.Weather.LeafletLayer({type: 'city', lang: 'ru', temperatureDigits: 0}),
    'Погода (OpenWeatherMap) - города',
    'w',
    false
  );

  osm.registerLayer(
    'layerWeatherStations',
     new OsmJs.Weather.LeafletLayer({type: 'station', lang: 'ru'}),
    'Погода (OpenWeatherMap) - станции',
    's',
    false
  );
  }

  osm.registerLayer(
    'layerHillshading',
    new L.TileLayer('http://toolserver.org/~cmarqu/hill/{z}/{x}/{y}.png', {
      maxZoom: 18,
      attribution: "Hillshading © toolserver.org"}),
    'Рельеф',
    'h',
    false
  );

  osm.registerLayer(
    'layerGPSPoint',
    new L.TileLayer('http://zverik.osm.rambler.ru/gps/tiles/{z}/{x}/{y}.png', {
      maxZoom: 14}),
    'GPS точки',
    'g',
    false
  );

    osm.registerLayer(
    'layerOpenSeaMap',
    new L.TileLayer('http://tiles.openseamap.org/seamark/{z}/{x}/{y}.png', {
      maxZoom: 18,
      attribution: "OpenSeaMap"}),
    'Открытая морская карта',
    'O',
    false
  );

}

osm.registerLayer = function (name, layer, title, hash, isBase){
    osm.layers[name] = layer;

    if(title){
        osm.layerHashes[title] = hash;
    }

    if(hash){
        osm.layerHash2name[hash] = name;
        if(title){
            osm.layerHash2title[hash] = title;
        }
    }

    if(undefined !== isBase){
        if(isBase){
          osm.baseLayers[title] = osm.layers[name];
        }
        else {
          osm.overlays[title] = osm.layers[name];
        }
    }
}
<commit_msg>убрана геолокация в режиме frame<commit_after>$(function() {
  parseGET();
  if (typeof frame_map === "undefined") frame_map = false; // in frame_map mode we have limited controls and map abilities

  var overlaysAsString = '';
  if (frame_map) {
    center = new L.LatLng(62.0, 88.0);
    zoom = $(window).width() > 1200 ? 3 : 2;
    layer = "M";
  } else {
    var loc = osm.getCookie('_osm_location');
    var center;
    var zoom;
    var layer = 'M';
    if(loc) {
      var locs = loc.split('|');
      center = new L.LatLng(locs[1], locs[0]);
      zoom = locs[2];
      layer = locs[3] || 'M';
      overlaysAsString = locs[4] || '';
    } else if(clientLat || clientLon) {
      center = new L.LatLng(clientLat, clientLon);
      zoom = 12;
    } else {
      center = new L.LatLng(62.0, 88.0);
      zoom = $(window).width() > 1200 ? 3 : 2;
    }
  }

  osm.initLayers();

  //some pice of paranoia
  baseLayer = osm.layers[osm.layerHash2name[layer]] || osm.layers.layerMapnik;

  osm.map = new L.Map('map', {zoomControl: false, center: center, zoom: zoom, layers: [baseLayer]});

  if (!frame_map)
    osm.map.addLayer(osm.layers.search_marker);
  for(var i = 0; i < overlaysAsString.length; i++){
        //don't save OSB layer
        var hash = overlaysAsString.charAt(i);
        if(hash != 'U'){
            var over = osm.layers[osm.layerHash2name[hash]];
            if(over){
                osm.map.addLayer(over);
            }
        }
  }

  L.Icon.Default.imagePath='/img';
  osm.markers.initialize();
  osm.markers.readMap();

  if (!frame_map) {
    $("#leftpan div h1").bind('click',function(){
      osm.leftpan.toggle(this.parentNode.id, true);
    });
    osm.leftpan.on=true;
    osm.leftpan.refsizetab();
  }

 if (!frame_map) {
  osm.map.control_layers = new L.Control.Layers(
    osm.baseLayers,
    osm.overlays,
    {
      layerHashes: osm.layerHashes
    }
  );
  osm.map.addControl(osm.map.control_layers);

  osm.leftpan.panel = $_('leftpan');
  osm.leftpan.content = $_('content_pan');
  osm.mappan.panel = $_('mappan');
  osm.input = $_('qsearch');
  osm.input.focus();
  osm.search_marker = new L.LayerGroup();
  osm.map.addLayer(osm.search_marker);

  if (osm.getCookie("_osm_htp") == "false")
    osm.ui.togglehtp();
  if (osm.getCookie("_osm_leftpan") == "false")
    setTimeout("osm.leftpan.toggle(false)", 500);

  osm.map.addControl(new L.Control.Scale({width: 100, position: 'bottomleft'}));

  osm.map.permalink = new L.Control.Permalink(osm.map.control_layers);
  osm.map.addControl(osm.map.permalink);
  osm.map.addControl(new L.Control.Zoom({shiftClick: true}));
  osm.map.addControl(new L.Control.Distance());
  osm.map.addControl(new L.Control.inJOSM({target:'hiddenIframe', linktitle: 'Редактировать в JOSM'}));
  osm.validators.initialize();
  osm.poi.initialize();

  search.inLoad();

  osm.editUpdate();
  osm.map.on('moveend', osm.saveLocation);
  osm.map.on('layeradd', osm.saveLocation);
  osm.map.on('layerremove', osm.saveLocation);
  osm.map.on('moveend', osm.editUpdate);

  osm.layers.osb.on('add', function(){osm.osbclick($_('mainmenupage-osb').children[0],true,this);});
  osm.layers.osb.on('remove', function(){osm.osbclick($_('mainmenupage-osb').children[0],false,this);});
  osm.setLinkOSB();
  // osm.initModes();

  $("#mappan #htpbutton").bind("click", function(){osm.ui.togglehtp()});
  if (get.hidetoppan) osm.ui.togglehtp();

  if ($('#leftpantab').height()>300)
    osm.dyk.load();
  $(window).resize(osm.leftpan.refsizetab);

  osm.map.on('moveend', osm.opento);

 }
});

osm.initLayers = function(){

  osm.layerHashes = {};
  osm.layerHash2name = {};
  osm.layerHash2title = {};
  osm.baseLayers = {};
  osm.overlays = {};

  osm.registerLayer(
    'layerMapnik',
    new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {maxZoom: 18, attribution: "Map data © OpenStreetMap contributors"}),
    'Mapnik',
    'M',
    true
  );

  osm.registerLayer(
    'layerKosmo',
    new L.TileLayer('http://{s}.tile.osmosnimki.ru/kosmo/{z}/{x}/{y}.png', {
        maxZoom: 18,
        attribution: "Map data &copy OpenStreetMap contributors, CC-BY-SA; rendering by kosmosnimki.ru"}
    ),
    'Космоснимки',
    'K',
    true
  );

  osm.registerLayer(
    'layerMQ',
    new L.TileLayer('http://otile{s}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png', {
      maxZoom: 18,
      attribution: "Map data © OpenStreetMap contributors, tiles © " +
         "MapQuest ",
      subdomains: '1234'}),
    'MapQuest',
    'Q',
    true
  );

  osm.registerLayer(
    'layerCycle',
    new L.TileLayer('http://{s}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png', {maxZoom: 18, attribution: "Map data © OpenStreetMap contributors (Cycle)"}),
    'Велокарта',
    'C',
    true
  );

  osm.registerLayer(
    'layerMS',
    new L.TileLayer('http://129.206.74.245:8001/tms_r.ashx?x={x}&y={y}&z={z}', {
      maxZoom: 18,
      attribution: "Map data © OpenStreetMap contributors, rendering GIScience Research Group @ University of Heidelberg"}),
    'MapSurfer.net',
    'S',
    true
  );

  osm.registerLayer(
    'layerBing',
    new L.BingLayer('ApaoUzCK5_6HzEgOsPL_HFxYj-RVA2FAvcvQHX4XKeR6tjzl9lquWXiZSwBFe8h-', {maxZoom: 18}),
    'Снимки Bing',
    'B',
    true
  );

  osm.registerLayer(
    'layerEmpty',
    new L.TileLayer('img/blank.png', {maxZoom: 18}),
    'Пустой фоновый слой',
    'E',
    true
  );

/*
  osm.registerLayer(
    'layerLatlonBuildings',
    new L.TileLayer('http://{s}.tile.osmosnimki.ru/buildings/{z}/{x}/{y}.png', {maxZoom: 18, attribution: "Трёхмерные здания © LatLon.org", subdomains: 'abcdef'}),
    'Трёхмерные здания',
    'Z',
    false
  );
*/
  if (!frame_map)
  osm.registerLayer(
    'osb',
    new L.OpenStreetBugs({dblClick: false, iconOpen:"img/osb/open_bug_marker.png", iconClosed:"img/osb/closed_bug_marker.png", iconActive:"img/osb/active_bug_marker.png", editArea:0.001, bugid: get.bugid}),
    'Ошибки на карте',
    'U',
    false
  );

  osm.registerLayer(
    'layerPt',
    new L.TileLayer('http://pt.openmap.lt/{z}/{x}/{y}.png', {maxZoom: 18, attribution: "Маршруты © openmap.lt"}),
    //new L.TileLayer('http://{s}.tile.osmosnimki.ru/pt/{z}/{x}/{y}.png', {maxZoom: 18, attribution: "Маршруты © LatLon.org", subdomains: 'abcdef'}),
    'Общественный транспорт',
    'T',
    false
  );

  osm.registerLayer(
    'layerKosmoHyb',
    new L.TileLayer('http://{s}.tile.osmosnimki.ru/hyb/{z}/{x}/{y}.png', {
      maxZoom: 18,
      attribution: "Map data &copy OpenStreetMap contributors, CC-BY-SA; rendering by kosmosnimki.ru"}),
    'Космоснимки (гибрид)',
    'H',
    false
  );

  osm.registerLayer(
    'layerMSHyb',
    new L.TileLayer('http://129.206.74.245:8003/tms_h.ashx?x={x}&y={y}&z={z}', {
      maxZoom: 18,
      attribution: "Map data © OpenStreetMap contributors, rendering " +
                   "GIScience Research Group @ University of Heidelberg"}),
    'MapSurfer.net (гибрид)',
    'Y',
    false
  );

  if (!frame_map) {
  osm.registerLayer(
    'search_marker',
    new L.LayerGroup()
  );

  WPCLayer = L.KML.extend({
    visible: false,
    onAdd: function(map) {
      L.KML.prototype.onAdd.apply(this, [map]);
      this._map.on('moveend',reloadKML,this);
      this.visible = true;
      reloadKML();
    },
    onRemove: function(map) {
      this._map.off('moveend',reloadKML,this);
      this.visible = false;
      L.KML.prototype.onRemove.apply(this, [map]);
    }
  });

  wpc.layers = new WPCLayer();

  osm.registerLayer(
    'layerWikiFoto',
    wpc.layers,
    'Фото (ВикиСклад) beta',
    'W',
    false
  );

  osm.registerLayer(
    'layerWeatherCities',
     new OsmJs.Weather.LeafletLayer({type: 'city', lang: 'ru', temperatureDigits: 0}),
    'Погода (OpenWeatherMap) - города',
    'w',
    false
  );

  osm.registerLayer(
    'layerWeatherStations',
     new OsmJs.Weather.LeafletLayer({type: 'station', lang: 'ru'}),
    'Погода (OpenWeatherMap) - станции',
    's',
    false
  );
  }

  osm.registerLayer(
    'layerHillshading',
    new L.TileLayer('http://toolserver.org/~cmarqu/hill/{z}/{x}/{y}.png', {
      maxZoom: 18,
      attribution: "Hillshading © toolserver.org"}),
    'Рельеф',
    'h',
    false
  );

  osm.registerLayer(
    'layerGPSPoint',
    new L.TileLayer('http://zverik.osm.rambler.ru/gps/tiles/{z}/{x}/{y}.png', {
      maxZoom: 14}),
    'GPS точки',
    'g',
    false
  );

    osm.registerLayer(
    'layerOpenSeaMap',
    new L.TileLayer('http://tiles.openseamap.org/seamark/{z}/{x}/{y}.png', {
      maxZoom: 18,
      attribution: "OpenSeaMap"}),
    'Открытая морская карта',
    'O',
    false
  );

}

osm.registerLayer = function (name, layer, title, hash, isBase){
    osm.layers[name] = layer;

    if(title){
        osm.layerHashes[title] = hash;
    }

    if(hash){
        osm.layerHash2name[hash] = name;
        if(title){
            osm.layerHash2title[hash] = title;
        }
    }

    if(undefined !== isBase){
        if(isBase){
          osm.baseLayers[title] = osm.layers[name];
        }
        else {
          osm.overlays[title] = osm.layers[name];
        }
    }
}
<|endoftext|>


<commit_before>/* @flow strict-local */
import type { ThemeName } from '../../types';
import { BRAND_COLOR } from '../../styles';
import cssEmojis from './cssEmojis';

const defaultTheme = `
html {
  -webkit-user-select: none; /* Safari 3.1+ */
  -moz-user-select: none; /* Firefox 2+ */
  -ms-user-select: none; /* IE 10+ */
  user-select: none; /* Standard syntax */
  -khtml-user-select: none;
  -webkit-touch-callout: none;
}
body {
  font-family: sans-serif;
  line-height: 1.4;
  margin: 0;
  width: 100%;
  max-width: 100%;
  font-size: 15px;
}
a {
  color: #08c;
}
p {
  margin: 0;
}
code {
  font-size: .857em;
  white-space: pre-wrap;
  padding: 0 0.25em;
}
pre {
  padding: 0.5em;
  margin: 0.5em 0;
  font-size: 0.75em;
  white-space: pre;
  overflow-x: auto;
  word-wrap: normal;
}
code, pre {
  border-radius: 3px;
  border: 1px solid rgba(127, 127, 127, 0.25);
  background-color: rgba(127, 127, 127, 0.125);
  font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
}
table {
  border-collapse: collapse;
  width: 100%;
}
table, th, td {
  border: 1px solid rgba(127, 127, 127, 0.25);
}
thead {
  background: rgba(127, 127, 127, 0.1);
}
th, td {
  align: center;
  padding: 0.25em 0.5em;
}
hr {
  margin: 1em 0;
  border: 0;
  border-top: 1px solid rgba(127, 127, 127, 0.5);
}
.alert-word {
  background-color: hsla(102, 85%, 57%, .5);
}
.highlight {
  background-color: hsl(51, 94%, 74%);
}
.subheader {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  margin-bottom: 0.25em;
}
.timerow {
  text-align: center;
  color: #999;
  display: flex;
  align-items: center;
  padding: 0.5em 0;
}
.timerow-left,
.timerow-right {
  flex: 1;
  height: 1px;
  margin: 0.5em;
}
.timerow-left {
  background: -webkit-linear-gradient(left, transparent 10%, #999 100%);
}
.timerow-right {
  background: -webkit-linear-gradient(left, #999 0%, transparent 90%);
}
.timestamp {
  color: #999;
  font-size: 14px;
  white-space: nowrap;
}
.message {
  display: flex;
  word-wrap: break-word;
  padding: 1em;
}
.message-brief {
  padding: 0 1em 1em 4em;
}
.message p + p {
  margin-top: 1em;
}
.avatar {
  min-width: 2em;
  width: 2em;
  height: 2em;
  margin-right: 1em;
}
.avatar img {
  width: 100%;
  border-radius: 3px;
}
.content {
  width: 100%;
  max-width: 100%;
  overflow: hidden;
}
.username {
  font-weight: bold;
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow: hidden;
}
.user-group-mention,
.user-mention {
  white-space: nowrap;
  background-color: rgba(0, 0, 0, 0.1);
  border-radius: 3px;
  padding: 0 .2em;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2);
}
.header-wrapper {
  position: -webkit-sticky;
  position: sticky;
  top: -1px;
  padding: 0.5em;
  z-index: 100;
}
.avatar,
.header-wrapper {
  cursor: pointer;
}
.stream-header {
  padding: 0;
  display: flex;
  flex-direction: row;
}
.stream-text,
.topic-text,
.private-header {
  padding: 0 0.5em;
  line-height: 2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.topic-text {
  flex: 1;
  padding-left: 0.5em;
  background: #ccc;
  min-width: 30%;
}
[data-mentioned="true"], [data-wildcard_mentioned="true"] {
  background: rgba(255, 0, 0, 0.05);
}
.message:not([data-read="true"]) {
}
.arrow-right {
  width: 0;
  height: 0;
  border-top: 1em solid transparent;
  border-bottom: 1em solid transparent;
  border-left: 1em solid green;
}
.private-header {
  background: #444;
  color: white;
}
.loading-avatar {
  min-width: 2em;
  width: 2em;
  height: 2em;
  margin-right: 1em;
  border-radius: 4px;
  background: rgba(127, 127, 127, 0.9);
}
.loading-content {
  width: 100%;
}
.loading-subheader {
  display: flex;
  justify-content: space-between;
}
.loading-content .block {
  background: linear-gradient(
    to right,
    rgba(127, 127, 127, 0.5) 0%,
    rgba(127, 127, 127, 0.5) 40%,
    rgba(127, 127, 127, 0.25) 51%,
    rgba(127, 127, 127, 0.5) 60%,
    rgba(127, 127, 127, 0.5) 100%
  );
  background-size: 200% 200%;
  animation: gradient-scroll 1s linear infinite;

  border-radius: 10px;
  height: 8px;
  margin-bottom: 10px;
}
@keyframes gradient-scroll {
  0% { background-position: 100% 50% }
  100% { background-position: 0 50% }
}
.loading-subheader .name {
  width: 10em;
  background-color: rgba(127, 127, 127, 0.9);
}
.loading-subheader .timestamp {
  width: 5em;
}
@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}
.loading-spinner, .outbox-spinner {
  width: 2em;
  height: 2em;
  border-radius: 50%;
  margin: 1em auto;
  font-size: 10px;
  border: 3px solid rgba(82, 194, 175, 0.25);
  border-left: 3px solid rgba(82, 194, 175, 0.75);
  animation: spin 1s linear infinite;
}
.outbox-spinner {
  margin: -16px 0 0 0;
  border-width: 2px;
  width: 12px;
  height: 12px;
  float: right;
}
.message_inline_image {
  text-align: center;
}
.message_inline_image img,
.message_inline_ref img,
.twitter-image img {
  width: 100%;
  height: 30vh;
  object-fit: contain;
}
blockquote {
  padding-left: 0.5em;
  margin: 0.5em 0 0.5em 0;
  border-left: 3px solid rgba(127, 127, 127, 0.5);
}
.message ul {
  padding-left: 1.2em;
  margin: 0.2em 0 0 0;
}
.message ul + p {
  margin-top: 1em;
}
.codehilite .gi { color: #00a000; }
.codehilite .gd { color: #a00000; }
.codehilite .k { color: #008000; font-weight: bold; }
.codehilite .kd { color: #008000; font-weight: bold; }
.codehilite .nf { color: #00f; }
.codehilite .s2 { color: #ba2121; }
.codehilite .cp { color: #bc7a00; }
.codehilite .kt { color: #b00040; }
.codehilite .nc { color: #00f; font-weight: bold; }
.codehilite .nb { color: #008000; }
.codehilite .s1 { color: #ba2121; }
.twitter-tweet {
  border: 2px solid rgba(29, 161, 242, 0.5);
  background: rgba(29, 161, 242, 0.1);
  border-radius: 0.25em;
  padding: 0.5em 1em;
  margin: 0.5em 0;
}
.twitter-avatar {
  border-radius: 0.25em;
  margin: 0.4em 0.4em 0.2em 0;
  float: left;
  width: 2.2em;
  height: 2.2em;
}
.twitter-image {
  text-align: center;
  margin: 0.5em auto;
}
.message-tags {
  text-align: right;
  margin: 0.25em 0;
  font-size: 10px;
}
.message-tag {
  padding: 0.25em 0.5em;
  margin-left: 4;
  border-radius: 2px;
  color: rgba(127, 127, 127, 0.75);
  background: rgba(0, 0, 0, 0.1);
}
.reaction-list {
  margin: 0.5em 0;
}
.reaction {
  color: rgba(127, 127, 127, 1);
  display: inline-block;
  padding: 5px 6.5px;
  border-radius: 4px;
  border: 1px solid rgba(127, 127, 127, 0.75);
  line-height: 1em;
  height: 1em;
  margin: .25em 0.5em .25em 0;
}
.reaction img {
  pointer-events: none;
  cursor: default;
  max-height: 1em;
  max-width: 1em;
  vertical-align: top;
}
.self-voted {
  color: ${BRAND_COLOR};
  border: 1px solid ${BRAND_COLOR};
  background: rgba(36, 202, 194, 0.1);
}
.hidden {
  display: none;
}
.emoji {
  display: inline-block;
  height: 18px;
  width: 18px;
  white-space: nowrap;
  color: transparent;
  vertical-align: text-top;
}
.emoji:before {
  color: white;
}
#typing {
  display: flex;
  padding-left: 1em;
}
#typing .content {
  padding-top: 0.5em;
  padding-bottom: 1em;
}
#typing span {
  display: inline-block;
  background-color: #B6B5BA;
  width: 0.5em;
  height: 0.5em;
  border-radius: 100%;
  margin-right: 5px;
  animation: bob 2s infinite;
}
#typing span:nth-child(2) {
  animation-delay: 0.15s;
}
#typing span:nth-child(3) {
  animation-delay: 0.3s;
  margin-right: 0;
}
@keyframes bob {
  10% {
    transform: translateY(-10px);
    background-color: #9E9DA2;
  }
  50% {
    transform: translateY(0);
    background-color: #B6B5BA;
  }
}
.typing-list {
  background: green;
  height: 20px;
}
#message-loading {
  position: fixed;
  width: 100%;
  opacity: 0.25;
}
#js-error-detailed {
  position: fixed;
  width: 100%;
  background: red;
  color: white;
  font-size: 10px;
}
#js-error-plain, #js-error-plain-dummy {
  z-index: 1000;
  width: 100%;
  background: red;
  color: white;
  font-size: 15px;
  padding: 4px;
  text-align: center;
}
#js-error-plain {
  position: fixed;
}
#js-error-plain-dummy {
  visibility: hidden;
}
#scroll-bottom {
  position: fixed;
  z-index: 200;
  right: 5px;
  bottom: 15px;
}
#scroll-bottom a {
  display: block;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: rgba(82, 194, 175, 0.5);
}
#scroll-bottom .text {
  clip: rect(0 0 0 0);
  overflow: hidden;
  position: absolute;
  height: 1px;
  width: 1px;
}
#scroll-bottom svg {
  width: 32px;
  height: 32px;
  fill: rgba(255, 255, 255, 0.75);
}
`;

const darkTheme = `
body {
  color: #d5d9dd;
  background: #212D3B;
}
.topic-text {
  background: #54606E;
}
.highlight {
  background-color: hsla(51, 100%, 64%, 0.42);
}
`;

export default (theme: ThemeName, highlightUnreadMessages: boolean) => `
<style>
${defaultTheme}
${theme === 'night' ? darkTheme : ''}
${cssEmojis}
${highlightUnreadMessages ? '.message:not([data-read="true"]) { background: red; }' : ''}
</style>
<style id="style-hide-js-error-plain">
#js-error-plain, #js-error-plain-dummy {
  display: none;
}
</style>
<style id="generated-styles"></style>
`;
<commit_msg>webview: Remove duplicate font size style for error message<commit_after>/* @flow strict-local */
import type { ThemeName } from '../../types';
import { BRAND_COLOR } from '../../styles';
import cssEmojis from './cssEmojis';

const defaultTheme = `
html {
  -webkit-user-select: none; /* Safari 3.1+ */
  -moz-user-select: none; /* Firefox 2+ */
  -ms-user-select: none; /* IE 10+ */
  user-select: none; /* Standard syntax */
  -khtml-user-select: none;
  -webkit-touch-callout: none;
}
body {
  font-family: sans-serif;
  line-height: 1.4;
  margin: 0;
  width: 100%;
  max-width: 100%;
  font-size: 15px;
}
a {
  color: #08c;
}
p {
  margin: 0;
}
code {
  font-size: .857em;
  white-space: pre-wrap;
  padding: 0 0.25em;
}
pre {
  padding: 0.5em;
  margin: 0.5em 0;
  font-size: 0.75em;
  white-space: pre;
  overflow-x: auto;
  word-wrap: normal;
}
code, pre {
  border-radius: 3px;
  border: 1px solid rgba(127, 127, 127, 0.25);
  background-color: rgba(127, 127, 127, 0.125);
  font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
}
table {
  border-collapse: collapse;
  width: 100%;
}
table, th, td {
  border: 1px solid rgba(127, 127, 127, 0.25);
}
thead {
  background: rgba(127, 127, 127, 0.1);
}
th, td {
  align: center;
  padding: 0.25em 0.5em;
}
hr {
  margin: 1em 0;
  border: 0;
  border-top: 1px solid rgba(127, 127, 127, 0.5);
}
.alert-word {
  background-color: hsla(102, 85%, 57%, .5);
}
.highlight {
  background-color: hsl(51, 94%, 74%);
}
.subheader {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  margin-bottom: 0.25em;
}
.timerow {
  text-align: center;
  color: #999;
  display: flex;
  align-items: center;
  padding: 0.5em 0;
}
.timerow-left,
.timerow-right {
  flex: 1;
  height: 1px;
  margin: 0.5em;
}
.timerow-left {
  background: -webkit-linear-gradient(left, transparent 10%, #999 100%);
}
.timerow-right {
  background: -webkit-linear-gradient(left, #999 0%, transparent 90%);
}
.timestamp {
  color: #999;
  font-size: 14px;
  white-space: nowrap;
}
.message {
  display: flex;
  word-wrap: break-word;
  padding: 1em;
}
.message-brief {
  padding: 0 1em 1em 4em;
}
.message p + p {
  margin-top: 1em;
}
.avatar {
  min-width: 2em;
  width: 2em;
  height: 2em;
  margin-right: 1em;
}
.avatar img {
  width: 100%;
  border-radius: 3px;
}
.content {
  width: 100%;
  max-width: 100%;
  overflow: hidden;
}
.username {
  font-weight: bold;
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow: hidden;
}
.user-group-mention,
.user-mention {
  white-space: nowrap;
  background-color: rgba(0, 0, 0, 0.1);
  border-radius: 3px;
  padding: 0 .2em;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2);
}
.header-wrapper {
  position: -webkit-sticky;
  position: sticky;
  top: -1px;
  padding: 0.5em;
  z-index: 100;
}
.avatar,
.header-wrapper {
  cursor: pointer;
}
.stream-header {
  padding: 0;
  display: flex;
  flex-direction: row;
}
.stream-text,
.topic-text,
.private-header {
  padding: 0 0.5em;
  line-height: 2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.topic-text {
  flex: 1;
  padding-left: 0.5em;
  background: #ccc;
  min-width: 30%;
}
[data-mentioned="true"], [data-wildcard_mentioned="true"] {
  background: rgba(255, 0, 0, 0.05);
}
.message:not([data-read="true"]) {
}
.arrow-right {
  width: 0;
  height: 0;
  border-top: 1em solid transparent;
  border-bottom: 1em solid transparent;
  border-left: 1em solid green;
}
.private-header {
  background: #444;
  color: white;
}
.loading-avatar {
  min-width: 2em;
  width: 2em;
  height: 2em;
  margin-right: 1em;
  border-radius: 4px;
  background: rgba(127, 127, 127, 0.9);
}
.loading-content {
  width: 100%;
}
.loading-subheader {
  display: flex;
  justify-content: space-between;
}
.loading-content .block {
  background: linear-gradient(
    to right,
    rgba(127, 127, 127, 0.5) 0%,
    rgba(127, 127, 127, 0.5) 40%,
    rgba(127, 127, 127, 0.25) 51%,
    rgba(127, 127, 127, 0.5) 60%,
    rgba(127, 127, 127, 0.5) 100%
  );
  background-size: 200% 200%;
  animation: gradient-scroll 1s linear infinite;

  border-radius: 10px;
  height: 8px;
  margin-bottom: 10px;
}
@keyframes gradient-scroll {
  0% { background-position: 100% 50% }
  100% { background-position: 0 50% }
}
.loading-subheader .name {
  width: 10em;
  background-color: rgba(127, 127, 127, 0.9);
}
.loading-subheader .timestamp {
  width: 5em;
}
@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}
.loading-spinner, .outbox-spinner {
  width: 2em;
  height: 2em;
  border-radius: 50%;
  margin: 1em auto;
  font-size: 10px;
  border: 3px solid rgba(82, 194, 175, 0.25);
  border-left: 3px solid rgba(82, 194, 175, 0.75);
  animation: spin 1s linear infinite;
}
.outbox-spinner {
  margin: -16px 0 0 0;
  border-width: 2px;
  width: 12px;
  height: 12px;
  float: right;
}
.message_inline_image {
  text-align: center;
}
.message_inline_image img,
.message_inline_ref img,
.twitter-image img {
  width: 100%;
  height: 30vh;
  object-fit: contain;
}
blockquote {
  padding-left: 0.5em;
  margin: 0.5em 0 0.5em 0;
  border-left: 3px solid rgba(127, 127, 127, 0.5);
}
.message ul {
  padding-left: 1.2em;
  margin: 0.2em 0 0 0;
}
.message ul + p {
  margin-top: 1em;
}
.codehilite .gi { color: #00a000; }
.codehilite .gd { color: #a00000; }
.codehilite .k { color: #008000; font-weight: bold; }
.codehilite .kd { color: #008000; font-weight: bold; }
.codehilite .nf { color: #00f; }
.codehilite .s2 { color: #ba2121; }
.codehilite .cp { color: #bc7a00; }
.codehilite .kt { color: #b00040; }
.codehilite .nc { color: #00f; font-weight: bold; }
.codehilite .nb { color: #008000; }
.codehilite .s1 { color: #ba2121; }
.twitter-tweet {
  border: 2px solid rgba(29, 161, 242, 0.5);
  background: rgba(29, 161, 242, 0.1);
  border-radius: 0.25em;
  padding: 0.5em 1em;
  margin: 0.5em 0;
}
.twitter-avatar {
  border-radius: 0.25em;
  margin: 0.4em 0.4em 0.2em 0;
  float: left;
  width: 2.2em;
  height: 2.2em;
}
.twitter-image {
  text-align: center;
  margin: 0.5em auto;
}
.message-tags {
  text-align: right;
  margin: 0.25em 0;
  font-size: 10px;
}
.message-tag {
  padding: 0.25em 0.5em;
  margin-left: 4;
  border-radius: 2px;
  color: rgba(127, 127, 127, 0.75);
  background: rgba(0, 0, 0, 0.1);
}
.reaction-list {
  margin: 0.5em 0;
}
.reaction {
  color: rgba(127, 127, 127, 1);
  display: inline-block;
  padding: 5px 6.5px;
  border-radius: 4px;
  border: 1px solid rgba(127, 127, 127, 0.75);
  line-height: 1em;
  height: 1em;
  margin: .25em 0.5em .25em 0;
}
.reaction img {
  pointer-events: none;
  cursor: default;
  max-height: 1em;
  max-width: 1em;
  vertical-align: top;
}
.self-voted {
  color: ${BRAND_COLOR};
  border: 1px solid ${BRAND_COLOR};
  background: rgba(36, 202, 194, 0.1);
}
.hidden {
  display: none;
}
.emoji {
  display: inline-block;
  height: 18px;
  width: 18px;
  white-space: nowrap;
  color: transparent;
  vertical-align: text-top;
}
.emoji:before {
  color: white;
}
#typing {
  display: flex;
  padding-left: 1em;
}
#typing .content {
  padding-top: 0.5em;
  padding-bottom: 1em;
}
#typing span {
  display: inline-block;
  background-color: #B6B5BA;
  width: 0.5em;
  height: 0.5em;
  border-radius: 100%;
  margin-right: 5px;
  animation: bob 2s infinite;
}
#typing span:nth-child(2) {
  animation-delay: 0.15s;
}
#typing span:nth-child(3) {
  animation-delay: 0.3s;
  margin-right: 0;
}
@keyframes bob {
  10% {
    transform: translateY(-10px);
    background-color: #9E9DA2;
  }
  50% {
    transform: translateY(0);
    background-color: #B6B5BA;
  }
}
.typing-list {
  background: green;
  height: 20px;
}
#message-loading {
  position: fixed;
  width: 100%;
  opacity: 0.25;
}
#js-error-detailed {
  position: fixed;
  width: 100%;
  background: red;
  color: white;
  font-size: 10px;
}
#js-error-plain, #js-error-plain-dummy {
  z-index: 1000;
  width: 100%;
  background: red;
  color: white;
  padding: 4px;
  text-align: center;
}
#js-error-plain {
  position: fixed;
}
#js-error-plain-dummy {
  visibility: hidden;
}
#scroll-bottom {
  position: fixed;
  z-index: 200;
  right: 5px;
  bottom: 15px;
}
#scroll-bottom a {
  display: block;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: rgba(82, 194, 175, 0.5);
}
#scroll-bottom .text {
  clip: rect(0 0 0 0);
  overflow: hidden;
  position: absolute;
  height: 1px;
  width: 1px;
}
#scroll-bottom svg {
  width: 32px;
  height: 32px;
  fill: rgba(255, 255, 255, 0.75);
}
`;

const darkTheme = `
body {
  color: #d5d9dd;
  background: #212D3B;
}
.topic-text {
  background: #54606E;
}
.highlight {
  background-color: hsla(51, 100%, 64%, 0.42);
}
`;

export default (theme: ThemeName, highlightUnreadMessages: boolean) => `
<style>
${defaultTheme}
${theme === 'night' ? darkTheme : ''}
${cssEmojis}
${highlightUnreadMessages ? '.message:not([data-read="true"]) { background: red; }' : ''}
</style>
<style id="style-hide-js-error-plain">
#js-error-plain, #js-error-plain-dummy {
  display: none;
}
</style>
<style id="generated-styles"></style>
`;
<|endoftext|>