{"version":3,"file":"780.a8e9f6c448ea80cb.bundle.js","mappings":"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","sources":["webpack://WebComponents/./runestone/cellbotics/js/auto-bind.js","webpack://WebComponents/./runestone/cellbotics/js/permissions_polyfill.js","webpack://WebComponents/./runestone/cellbotics/js/sensor_polyfill/sensor.js","webpack://WebComponents/./runestone/cellbotics/js/sensor_polyfill/motion-sensors.js","webpack://WebComponents/./runestone/cellbotics/js/sensor_polyfill/geolocation-sensor.js","webpack://WebComponents/./runestone/cellbotics/js/simple_sensor.js"],"sourcesContent":["// .. Copyright (C) 2012-2020 Bryan A. Jones.\n//\n// This file is part of the CellBotics system.\n//\n// The CellBotics system is free software: you can redistribute it and/or\n// modify it under the terms of the GNU General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// The CellBotics system is distributed in the hope that it will be\n// useful, but WITHOUT ANY WARRANTY; without even the implied warranty\n// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n// General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with the CellBotics system. If not, see\n// .\n//\n// *********************************************************\n// |docname| - Automatically bind methods to their instances\n// *********************************************************\n\n\"use strict\";\n\n\n// The following two functions were taken from https://github.com/sindresorhus/auto-bind/blob/master/index.js and lightly modified. They provide an easy way to bind all callable methods to their instance. See `Binding Methods to Class Instance Objects `_ for more discussion on this crazy JavaScript necessity.\n//\n// Gets all non-builtin properties up the prototype chain\nconst getAllProperties = object => {\n\tconst properties = new Set();\n\n\tdo {\n\t\tfor (const key of Reflect.ownKeys(object)) {\n\t\t\tproperties.add([object, key]);\n\t\t}\n\t} while ((object = Reflect.getPrototypeOf(object)) && object !== Object.prototype);\n\n\treturn properties;\n};\n\n\n// Invoke this in the constructor of an object.\nexport function auto_bind(self) {\n for (const [object, key] of getAllProperties(self.constructor.prototype)) {\n if (key === 'constructor') {\n continue;\n }\n\n const descriptor = Reflect.getOwnPropertyDescriptor(object, key);\n if (descriptor && typeof descriptor.value === 'function') {\n self[key] = self[key].bind(self);\n }\n }\n}\n","// .. Copyright (C) 2012-2020 Bryan A. Jones.\n//\n// This file is part of the CellBotics system.\n//\n// The CellBotics system is free software: you can redistribute it and/or\n// modify it under the terms of the GNU General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// The CellBotics system is distributed in the hope that it will be\n// useful, but WITHOUT ANY WARRANTY; without even the implied warranty\n// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n// General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with the CellBotics system. If not, see\n// .\n//\n// ********************************************\n// |docname| - Polyfill for the Permissions API\n// ********************************************\n// This is primarily for iOS devices that don't provide Permissions, but use another method to allow access to various sensors.\n\n\"use strict\";\n\n// Only supply this if there's not Permissions and we have tne iOS flavor available. See sample code in https://dev.to/li/how-to-requestpermission-for-devicemotion-and-deviceorientation-events-in-ios-13-46g2 or the `W3C working draft `_.\nif (\n !navigator.permissions &&\n (typeof DeviceMotionEvent.requestPermission === \"function\") &&\n (typeof DeviceOrientationEvent.requestPermission === \"function\")\n) {\n navigator.permissions = {\n query: options => {\n // Ignore everything but the name, since our use case is only for SimpleSensor.\n switch (options.name) {\n case \"accelerometer\":\n case \"gyroscope\":\n // The requested permissions doesn't allow us to determine which of the following two permissions we need, so ask for both.\n return new Promise((resolve, reject) => {\n Promise.all([\n // The polyfill for the accelerometer, gyro, and related classes needs just this.\n DeviceMotionEvent.requestPermission(),\n // The polyfill for the orientation sensors needs just this.\n DeviceOrientationEvent.requestPermission()\n ]).then(\n // We now have an array of strings, the result of the requestPermission calls. If all are \"granted\", then return {state: \"granted\"}, else return {state: \"denied\"}.\n vals => resolve({state:\n (vals.every(x => x === \"granted\") ? \"granted\" : \"denied\")\n })\n )\n });\n\n // There's nothing else that needs permission to work.\n default:\n return Promise.resolve({state: \"granted\"});\n }\n }\n };\n}\n","// ********************************\n// |docname| - Base Sensor polyfill\n// ********************************\n// The `geolocation-sensor.js` and `motion-sensors.js` files depend on this.\n\n\"use strict\";\n\n// @ts-check\nconst __sensor__ = Symbol(\"__sensor__\");\n\nconst slot = __sensor__;\n\nfunction defineProperties(target, descriptions) {\n for (const property in descriptions) {\n Object.defineProperty(target, property, {\n configurable: true,\n value: descriptions[property]\n });\n }\n}\n\nconst EventTargetMixin = (superclass, ...eventNames) => class extends superclass {\n constructor(...args) {\n // @ts-ignore\n super(args);\n const eventTarget = document.createDocumentFragment();\n\n this.addEventListener = (type, ...args) => {\n return eventTarget.addEventListener(type, ...args);\n }\n\n this.removeEventListener = (...args) => {\n // @ts-ignore\n return eventTarget.removeEventListener(...args);\n }\n\n this.dispatchEvent = (event) => {\n defineProperties(event, { currentTarget: this });\n if (!event.target) {\n defineProperties(event, { target: this });\n }\n\n const methodName = `on${event.type}`;\n if (typeof this[methodName] == \"function\") {\n this[methodName](event);\n }\n\n const retValue = eventTarget.dispatchEvent(event);\n\n if (retValue && this.parentNode) {\n this.parentNode.dispatchEvent(event);\n }\n\n defineProperties(event, { currentTarget: null, target: null });\n\n return retValue;\n }\n }\n};\n\nclass EventTarget extends EventTargetMixin(Object) {};\n\nfunction defineReadonlyProperties(target, slot, descriptions) {\n const propertyBag = target[slot];\n for (const property in descriptions) {\n propertyBag[property] = descriptions[property];\n Object.defineProperty(target, property, {\n get: () => propertyBag[property]\n });\n }\n}\n\nclass SensorErrorEvent extends Event {\n constructor(type, errorEventInitDict) {\n super(type, errorEventInitDict);\n\n if (!errorEventInitDict || !(errorEventInitDict.error instanceof DOMException)) {\n throw TypeError(\n \"Failed to construct 'SensorErrorEvent':\" +\n \"2nd argument much contain 'error' property\"\n );\n }\n\n Object.defineProperty(this, \"error\", {\n configurable: false,\n writable: false,\n value: errorEventInitDict.error\n });\n }\n};\n\nfunction defineOnEventListener(target, name) {\n Object.defineProperty(target, `on${name}`, {\n enumerable: true,\n configurable: false,\n writable: true,\n value: null\n });\n}\n\nconst SensorState = {\n IDLE: 1,\n ACTIVATING: 2,\n ACTIVE: 3,\n}\n\nclass Sensor extends EventTarget {\n constructor(options) {\n super();\n this[slot] = new WeakMap;\n\n defineOnEventListener(this, \"reading\");\n defineOnEventListener(this, \"activate\");\n defineOnEventListener(this, \"error\");\n\n defineReadonlyProperties(this, slot, {\n activated: false,\n hasReading: false,\n timestamp: null\n })\n\n this[slot].state = SensorState.IDLE;\n\n this[slot].notifyError = (message, name) => {\n let error = new SensorErrorEvent(\"error\", {\n error: new DOMException(message, name)\n });\n this.dispatchEvent(error);\n this.stop();\n }\n\n this[slot].notifyActivatedState = () => {\n let activate = new Event(\"activate\");\n this[slot].activated = true;\n this.dispatchEvent(activate);\n this[slot].state = SensorState.ACTIVE;\n }\n\n this[slot].activateCallback = () => {};\n this[slot].deactivateCallback = () => {};\n\n this[slot].frequency = null;\n\n if (window && window.parent != window.top) {\n throw new DOMException(\"Only instantiable in a top-level browsing context\", \"SecurityError\");\n }\n\n if (options && typeof(options.frequency) == \"number\") {\n if (options.frequency > 60) {\n this.frequency = options.frequency;\n }\n }\n }\n\n start() {\n if (this[slot].state === SensorState.ACTIVATING || this[slot].state === SensorState.ACTIVE) {\n return;\n }\n this[slot].state = SensorState.ACTIVATING;\n this[slot].activateCallback();\n }\n\n stop() {\n if (this[slot].state === SensorState.IDLE) {\n return;\n }\n this[slot].activated = false;\n this[slot].hasReading = false;\n this[slot].timestamp = null;\n this[slot].deactivateCallback();\n\n this[slot].state = SensorState.IDLE;\n }\n}","// ***********************************\n// |docname| - Motion sensors polyfill\n// ***********************************\n// @ts-check\n\"use strict\";\n\nimport \"./sensor.js\";\n\n//const slot = __sensor__;\n\nlet orientation;\n\n// @ts-ignore\nif (screen.orientation) {\n // @ts-ignore\n orientation = screen.orientation;\n} else if (screen.msOrientation) {\n orientation = screen.msOrientation;\n} else {\n orientation = {};\n Object.defineProperty(orientation, \"angle\", {\n get: () => { return (window.orientation || 0) }\n });\n}\n\nconst DeviceOrientationMixin = (superclass, ...eventNames) => class extends superclass {\n constructor(...args) {\n // @ts-ignore\n super(args);\n\n for (const eventName of eventNames) {\n if (`on${eventName}` in window) {\n this[slot].eventName = eventName;\n break;\n }\n }\n\n this[slot].activateCallback = () => {\n window.addEventListener(this[slot].eventName, this[slot].handleEvent, { capture: true });\n }\n\n this[slot].deactivateCallback = () => {\n window.removeEventListener(this[slot].eventName, this[slot].handleEvent, { capture: true });\n }\n }\n};\n\nfunction toQuaternionFromEuler(alpha, beta, gamma) {\n const degToRad = Math.PI / 180\n\n const x = (beta || 0) * degToRad;\n const y = (gamma || 0) * degToRad;\n const z = (alpha || 0) * degToRad;\n\n const cZ = Math.cos(z * 0.5);\n const sZ = Math.sin(z * 0.5);\n const cY = Math.cos(y * 0.5);\n const sY = Math.sin(y * 0.5);\n const cX = Math.cos(x * 0.5);\n const sX = Math.sin(x * 0.5);\n\n const qx = sX * cY * cZ - cX * sY * sZ;\n const qy = cX * sY * cZ + sX * cY * sZ;\n const qz = cX * cY * sZ + sX * sY * cZ;\n const qw = cX * cY * cZ - sX * sY * sZ;\n\n return [qx, qy, qz, qw];\n}\n\nfunction rotateQuaternionByAxisAngle(quat, axis, angle) {\n const sHalfAngle = Math.sin(angle / 2);\n const cHalfAngle = Math.cos(angle / 2);\n\n const transformQuat = [\n axis[0] * sHalfAngle,\n axis[1] * sHalfAngle,\n axis[2] * sHalfAngle,\n cHalfAngle\n ];\n\n function multiplyQuaternion(a, b) {\n const qx = a[0] * b[3] + a[3] * b[0] + a[1] * b[2] - a[2] * b[1];\n const qy = a[1] * b[3] + a[3] * b[1] + a[2] * b[0] - a[0] * b[2];\n const qz = a[2] * b[3] + a[3] * b[2] + a[0] * b[1] - a[1] * b[0];\n const qw = a[3] * b[3] - a[0] * b[0] - a[1] * b[1] - a[2] * b[2];\n\n return [qx, qy, qz, qw];\n }\n\n function normalizeQuaternion(quat) {\n const length = Math.sqrt(quat[0] ** 2 + quat[1] ** 2 + quat[2] ** 2 + quat[3] ** 2);\n if (length === 0) {\n return [0, 0, 0, 1];\n }\n\n return quat.map(v => v / length);\n }\n\n return normalizeQuaternion(multiplyQuaternion(quat, transformQuat));\n}\n\nfunction toMat4FromQuat(mat, q) {\n const typed = mat instanceof Float32Array || mat instanceof Float64Array;\n\n if (typed && mat.length >= 16) {\n mat[0] = 1 - 2 * (q[1] ** 2 + q[2] ** 2);\n mat[1] = 2 * (q[0] * q[1] - q[2] * q[3]);\n mat[2] = 2 * (q[0] * q[2] + q[1] * q[3]);\n mat[3] = 0;\n\n mat[4] = 2 * (q[0] * q[1] + q[2] * q[3]);\n mat[5] = 1 - 2 * (q[0] ** 2 + q[2] ** 2);\n mat[6] = 2 * (q[1] * q[2] - q[0] * q[3]);\n mat[7] = 0;\n\n mat[8] = 2 * (q[0] * q[2] - q[1] * q[3]);\n mat[9] = 2 * (q[1] * q[2] + q[0] * q[3]);\n mat[10] = 1 - 2 * (q[0] ** 2 + q[1] ** 2);\n mat[11] = 0;\n\n mat[12] = 0;\n mat[13] = 0;\n mat[14] = 0;\n mat[15] = 1;\n }\n\n return mat;\n}\n\nfunction worldToScreen(quaternion) {\n return !quaternion ? null :\n rotateQuaternionByAxisAngle(\n quaternion,\n [0, 0, 1],\n - orientation.angle * Math.PI / 180\n );\n}\n\n// @ts-ignore\nconst RelativeOrientationSensor = window.RelativeOrientationSensor ||\nclass RelativeOrientationSensor extends DeviceOrientationMixin(Sensor, \"deviceorientation\") {\n constructor(options = {}) {\n super(options);\n\n switch (options.coordinateSystem || 'world') {\n case 'screen':\n Object.defineProperty(this, \"quaternion\", {\n get: () => worldToScreen(this[slot].quaternion)\n });\n break;\n case 'world':\n default:\n Object.defineProperty(this, \"quaternion\", {\n get: () => this[slot].quaternion\n });\n }\n\n this[slot].handleEvent = event => {\n // If there is no sensor we will get values equal to null.\n if (event.absolute || event.alpha === null) {\n // Spec: The implementation can still decide to provide\n // absolute orientation if relative is not available or\n // the resulting data is more accurate. In either case,\n // the absolute property must be set accordingly to reflect\n // the choice.\n this[slot].notifyError(\"Could not connect to a sensor\", \"NotReadableError\");\n return;\n }\n\n if (!this[slot].activated) {\n this[slot].notifyActivatedState();\n }\n\n this[slot].timestamp = performance.now();\n\n this[slot].quaternion = toQuaternionFromEuler(\n event.alpha,\n event.beta,\n event.gamma\n );\n\n this[slot].hasReading = true;\n this.dispatchEvent(new Event(\"reading\"));\n }\n\n this[slot].deactivateCallback = () => {\n this[slot].quaternion = null;\n }\n }\n\n populateMatrix(mat) {\n toMat4FromQuat(mat, this.quaternion);\n }\n}\n\n// @ts-ignore\nconst AbsoluteOrientationSensor = window.AbsoluteOrientationSensor ||\nclass AbsoluteOrientationSensor extends DeviceOrientationMixin(\n Sensor, \"deviceorientationabsolute\", \"deviceorientation\") {\n constructor(options = {}) {\n super(options);\n\n switch (options.coordinateSystem || 'world') {\n case 'screen':\n Object.defineProperty(this, \"quaternion\", {\n get: () => worldToScreen(this[slot].quaternion)\n });\n break;\n case 'world':\n default:\n Object.defineProperty(this, \"quaternion\", {\n get: () => this[slot].quaternion\n });\n }\n\n this[slot].handleEvent = event => {\n // If absolute is set, or webkitCompassHeading exists,\n // absolute values should be available.\n const isAbsolute = event.absolute === true || \"webkitCompassHeading\" in event;\n const hasValue = event.alpha !== null || event.webkitCompassHeading !== undefined;\n\n if (!isAbsolute || !hasValue) {\n // Spec: If an implementation can never provide absolute\n // orientation information, the event should be fired with\n // the alpha, beta and gamma attributes set to null.\n this[slot].notifyError(\"Could not connect to a sensor\", \"NotReadableError\");\n return;\n }\n\n if (!this[slot].activated) {\n this[slot].notifyActivatedState();\n }\n\n this[slot].hasReading = true;\n this[slot].timestamp = performance.now();\n\n const heading = event.webkitCompassHeading != null ? 360 - event.webkitCompassHeading : event.alpha;\n\n this[slot].quaternion = toQuaternionFromEuler(\n heading,\n event.beta,\n event.gamma\n );\n\n this.dispatchEvent(new Event(\"reading\"));\n }\n\n this[slot].deactivateCallback = () => {\n this[slot].quaternion = null;\n }\n }\n\n populateMatrix(mat) {\n toMat4FromQuat(mat, this.quaternion);\n }\n}\n\n// @ts-ignore\nconst Gyroscope = window.Gyroscope ||\nclass Gyroscope extends DeviceOrientationMixin(Sensor, \"devicemotion\") {\n constructor(options) {\n super(options);\n this[slot].handleEvent = event => {\n // If there is no sensor we will get values equal to null.\n if (event.rotationRate.alpha === null) {\n this[slot].notifyError(\"Could not connect to a sensor\", \"NotReadableError\");\n return;\n }\n\n if (!this[slot].activated) {\n this[slot].notifyActivatedState();\n }\n\n this[slot].timestamp = performance.now();\n\n this[slot].x = event.rotationRate.alpha;\n this[slot].y = event.rotationRate.beta;\n this[slot].z = event.rotationRate.gamma;\n\n this[slot].hasReading = true;\n this.dispatchEvent(new Event(\"reading\"));\n }\n\n defineReadonlyProperties(this, slot, {\n x: null,\n y: null,\n z: null\n });\n\n this[slot].deactivateCallback = () => {\n this[slot].x = null;\n this[slot].y = null;\n this[slot].z = null;\n }\n }\n}\n\n// @ts-ignore\nconst Accelerometer = window.Accelerometer ||\nclass Accelerometer extends DeviceOrientationMixin(Sensor, \"devicemotion\") {\n constructor(options) {\n super(options);\n this[slot].handleEvent = event => {\n // If there is no sensor we will get values equal to null.\n if (event.accelerationIncludingGravity.x === null) {\n this[slot].notifyError(\"Could not connect to a sensor\", \"NotReadableError\");\n return;\n }\n\n if (!this[slot].activated) {\n this[slot].notifyActivatedState();\n }\n\n this[slot].timestamp = performance.now();\n\n this[slot].x = event.accelerationIncludingGravity.x;\n this[slot].y = event.accelerationIncludingGravity.y;\n this[slot].z = event.accelerationIncludingGravity.z;\n\n this[slot].hasReading = true;\n this.dispatchEvent(new Event(\"reading\"));\n }\n\n defineReadonlyProperties(this, slot, {\n x: null,\n y: null,\n z: null\n });\n\n this[slot].deactivateCallback = () => {\n this[slot].x = null;\n this[slot].y = null;\n this[slot].z = null;\n }\n }\n}\n\n// @ts-ignore\nconst LinearAccelerationSensor = window.LinearAccelerationSensor ||\nclass LinearAccelerationSensor extends DeviceOrientationMixin(Sensor, \"devicemotion\") {\n constructor(options) {\n super(options);\n this[slot].handleEvent = event => {\n // If there is no sensor we will get values equal to null.\n if (event.acceleration.x === null) {\n this[slot].notifyError(\"Could not connect to a sensor\", \"NotReadableError\");\n return;\n }\n\n if (!this[slot].activated) {\n this[slot].notifyActivatedState();\n }\n\n this[slot].timestamp = performance.now();\n\n this[slot].x = event.acceleration.x;\n this[slot].y = event.acceleration.y;\n this[slot].z = event.acceleration.z;\n\n this[slot].hasReading = true;\n this.dispatchEvent(new Event(\"reading\"));\n }\n\n defineReadonlyProperties(this, slot, {\n x: null,\n y: null,\n z: null\n });\n\n this[slot].deactivateCallback = () => {\n this[slot].x = null;\n this[slot].y = null;\n this[slot].z = null;\n }\n }\n}\n\n// @ts-ignore\nconst GravitySensor = window.GravitySensor ||\n class GravitySensor extends DeviceOrientationMixin(Sensor, \"devicemotion\") {\n constructor(options) {\n super(options);\n this[slot].handleEvent = event => {\n // If there is no sensor we will get values equal to null.\n if (event.acceleration.x === null || event.accelerationIncludingGravity.x === null) {\n this[slot].notifyError(\"Could not connect to a sensor\", \"NotReadableError\");\n return;\n }\n\n if (!this[slot].activated) {\n this[slot].notifyActivatedState();\n }\n\n this[slot].timestamp = performance.now();\n\n this[slot].x = event.accelerationIncludingGravity.x - event.acceleration.x;\n this[slot].y = event.accelerationIncludingGravity.y - event.acceleration.y;\n this[slot].z = event.accelerationIncludingGravity.z - event.acceleration.z;\n\n this[slot].hasReading = true;\n this.dispatchEvent(new Event(\"reading\"));\n }\n\n defineReadonlyProperties(this, slot, {\n x: null,\n y: null,\n z: null\n });\n\n this[slot].deactivateCallback = () => {\n this[slot].x = null;\n this[slot].y = null;\n this[slot].z = null;\n }\n }\n}","// ***************************************\n// |docname| - Geolocation sensor polyfill\n// ***************************************\n// @ts-check\n\"use strict\";\n\nimport \"./sensor.js\";\n\n//const slot = __sensor__;\n\nclass GeolocationSensorSingleton {\n constructor() {\n if (!this.constructor.instance) {\n this.constructor.instance = this;\n }\n\n this.sensors = new Set();\n this.watchId = null;\n this.accuracy = null;\n this.lastPosition = null;\n\n return this.constructor.instance;\n }\n\n async obtainPermission() {\n let state = \"prompt\"; // Default for geolocation.\n // @ts-ignore\n if (navigator.permissions) {\n // @ts-ignore\n const permission = await navigator.permissions.query({ name:\"geolocation\"});\n state = permission.state;\n }\n\n return new Promise(resolve => {\n const successFn = position => {\n this.lastPosition = position;\n resolve(\"granted\");\n }\n\n const errorFn = err => {\n if (err.code === err.PERMISSION_DENIED) {\n resolve(\"denied\");\n } else {\n resolve(state);\n }\n }\n\n const options = { maximumAge: Infinity, timeout: 10 };\n navigator.geolocation.getCurrentPosition(successFn, errorFn, options);\n });\n }\n\n calculateAccuracy() {\n let enableHighAccuracy = false;\n\n for (const sensor of this.sensors) {\n if (sensor[slot].options.accuracy === \"high\") {\n enableHighAccuracy = true;\n break;\n }\n }\n return enableHighAccuracy;\n }\n\n async register(sensor) {\n const permission = await this.obtainPermission();\n if (permission !== \"granted\") {\n sensor[slot].notifyError(\"Permission denied.\", \"NowAllowedError\");\n return;\n }\n\n if (this.lastPosition) {\n const age = performance.now() - this.lastPosition.timeStamp;\n const maxAge = sensor[slot].options.maxAge;\n if (maxAge == null || age <= maxAge) {\n sensor[slot].handleEvent(age, this.lastPosition.coords);\n }\n }\n\n this.sensors.add(sensor);\n\n // Check whether we need to reconfigure our navigation.geolocation\n // watch, ie. tear it down and recreate.\n const accuracy = this.calculateAccuracy();\n if (this.watchId && this.accuracy === accuracy) {\n // We don't need to reset, return.\n return;\n }\n\n if (this.watchId) {\n navigator.geolocation.clearWatch(this.watchId);\n }\n\n const handleEvent = position => {\n this.lastPosition = position;\n\n const timestamp = position.timestamp - performance.timing.navigationStart;\n const coords = position.coords;\n\n for (const sensor of this.sensors) {\n sensor[slot].handleEvent(timestamp, coords);\n }\n }\n\n const handleError = error => {\n let type;\n switch(error.code) {\n case error.TIMEOUT:\n type = \"TimeoutError\";\n break;\n case error.PERMISSION_DENIED:\n type = \"NotAllowedError\";\n break;\n case error.POSITION_UNAVAILABLE:\n type = \"NotReadableError\";\n break;\n default:\n type = \"UnknownError\";\n }\n for (const sensor of this.sensors) {\n sensor[slot].handleError(error.message, type);\n }\n }\n\n const options = {\n enableHighAccuracy: accuracy,\n maximumAge: 0,\n timeout: Infinity\n }\n\n this.watchId = navigator.geolocation.watchPosition(\n handleEvent, handleError, options\n );\n }\n\n deregister(sensor) {\n this.sensors.delete(sensor);\n if (!this.sensors.size && this.watchId) {\n navigator.geolocation.clearWatch(this.watchId);\n this.watchId = null;\n }\n }\n}\n\n// @ts-ignore\nconst GeolocationSensor = window.GeolocationSensor ||\nclass GeolocationSensor extends Sensor {\n constructor(options = {}) {\n super(options);\n\n this[slot].options = options;\n\n const props = {\n latitude: null,\n longitude: null,\n altitude: null,\n accuracy: null,\n altitudeAccuracy: null,\n heading: null,\n speed: null\n }\n\n const propertyBag = this[slot];\n for (const propName in props) {\n propertyBag[propName] = props[propName];\n Object.defineProperty(this, propName, {\n get: () => propertyBag[propName]\n });\n }\n\n this[slot].handleEvent = (timestamp, coords) => {\n if (!this[slot].activated) {\n this[slot].notifyActivatedState();\n }\n\n this[slot].timestamp = timestamp;\n\n this[slot].accuracy = coords.accuracy;\n this[slot].altitude = coords.altitude;\n this[slot].altitudeAccuracy = coords.altitudeAccuracy;\n this[slot].heading = coords.heading;\n this[slot].latitude = coords.latitude;\n this[slot].longitude = coords.longitude;\n this[slot].speed = coords.speed;\n\n this[slot].hasReading = true;\n this.dispatchEvent(new Event(\"reading\"));\n }\n\n this[slot].handleError = (message, type) => {\n this[slot].notifyError(message, type);\n }\n\n this[slot].activateCallback = () => {\n (new GeolocationSensorSingleton()).register(this);\n }\n\n this[slot].deactivateCallback = () => {\n (new GeolocationSensorSingleton()).deregister(this);\n }\n }\n}","// .. Copyright (C) 2012-2020 Bryan A. Jones.\n//\n// This file is part of the CellBotics system.\n//\n// The CellBotics system is free software: you can redistribute it and/or\n// modify it under the terms of the GNU General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// The CellBotics system is distributed in the hope that it will be\n// useful, but WITHOUT ANY WARRANTY; without even the implied warranty\n// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n// General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with the CellBotics system. If not, see\n// .\n//\n// **********************************\n// |docname| - Interface with sensors\n// **********************************\n// This provides code to access `sensor APIs `_.\n\"use strict\";\n\nimport \"./permissions_polyfill.js\";\nimport \"./sensor_polyfill/geolocation-sensor.js\";\nimport \"./sensor_polyfill/motion-sensors.js\";\nimport { auto_bind } from \"./auto-bind.js\";\n\n// SimpleSensor\n// ============\n// This class wraps a `Sensor `_ with simple ``start``, ``ready``, and ``stop`` functions.\nclass SimpleSensor {\n constructor() {\n auto_bind(this);\n\n this.sensor = null;\n }\n\n // This was initially based on the MDN Sensor API docs.\n async start(\n // The class to use for the sensor to start. It must be based on the Sensor interface.\n sensor_class,\n // An array of strings, giving the name of the API to ask permissions of for this sensor. See https://developer.mozilla.org/en-US/docs/Web/API/Permissions/query.\n sensor_permission,\n // Options to pass to this sensor's constructor.\n sensor_options\n ) {\n if (this.sensor) {\n throw \"In use. Stop the sensor before starting another.\";\n }\n if (typeof sensor_class !== \"function\") {\n throw \"Not available.\";\n }\n\n // Get permission to use these sensors, if the API is supported.\n if (navigator.permissions) {\n let result = await Promise.all(sensor_permission.map(x => navigator.permissions.query({ name: x })));\n if (!result.every(val => val.state === \"granted\")) {\n throw `Permission to use the ${sensor_permission} sensor was denied.`;\n }\n }\n\n // To access a sensor:\n //\n // #. Create it, then start it, synchronously checking for errors in this process.\n // #. Await for a response from the sensor: an acceptance indicating the sensor works, or a rejection indicating a failure.\n //\n // Since the event handlers to accept or reject the promise must be set up in the synchronous phase, wrap everything in a promise. All the operations above therefore start when the promise is awaited.\n this.sensor = null;\n let on_error;\n let on_reading;\n let p = new Promise((resolve, reject) => {\n try {\n this.sensor = new sensor_class(sensor_options);\n\n // Handle callback errors by rejecting the promise.\n let that = this;\n on_error = event => {\n that.sensor.removeEventListener(\"error\", on_error);\n // Handle runtime errors.\n if (event.error.name === 'NotAllowedError') {\n reject(\"Access to this sensor is not allowed.\");\n } else if (event.error.name === 'NotReadableError' ) {\n reject('Cannot connect to the sensor.');\n }\n reject(`Unknown error: ${event.error.name}`);\n\n }\n this.sensor.addEventListener('error', on_error);\n\n // Wait for the first sensor reading to accept the promise.\n on_reading = event => {\n\n that.sensor.removeEventListener(\"reading\", on_reading);\n resolve();\n }\n this.sensor.addEventListener(\"reading\", on_reading);\n\n this.sensor.start();\n } catch (error) {\n // Handle construction errors.\n if (error.name === 'SecurityError') {\n // See the note above about feature policy.\n reject(\"Sensor construction was blocked by a feature policy.\");\n } else if (error.name === 'ReferenceError') {\n reject(\"Sensor is not supported by the User Agent.\");\n } else {\n reject(error);\n }\n }\n });\n\n // Start the sensor, waiting until it produces a reading or an error.\n try {\n console.log(`Await ${new Date()}`);\n await p;\n } catch (err) {\n this.stop();\n throw err;\n } finally {\n console.log(`Done ${new Date()}`);\n this.sensor.removeEventListener(\"error\", on_error);\n this.sensor.removeEventListener(\"reading\", on_reading);\n }\n }\n\n // True if the sensor is activated and has a reading.\n get ready() {\n return this.sensor && this.sensor.activated && this.sensor.hasReading;\n }\n\n // To save device power, be sure to stop the sensor as soon as the readings are no longer needed.\n stop() {\n this.sensor && this.sensor.stop();\n this.sensor = null;\n }\n}\n\n\n// Abstract helper classes\n// =======================\n// Several sensors return x, y, and z values. Collect the common code here.\nclass SimpleXYZSensor extends SimpleSensor {\n get x() {\n return this.sensor.x;\n }\n\n get y() {\n return this.sensor.y;\n }\n\n get z() {\n return this.sensor.z;\n }\n}\n\n\n// Two sensors return a quaternion or rotation matrix.\nclass SimpleOrientationSensor extends SimpleSensor {\n get quaternion() {\n return this.sensor.quaternion;\n }\n\n populateMatrix(targetMatrix) {\n return this.sensor.populateMatrix(targetMatrix);\n }\n}\n\n\n// Concrete classes\n// ================\n// Note the use of ``window.SensorName`` instead of ``SensorName`` for non-polyfills. This avoids exceptions if the particular sensor isn't defined, producing an ``undefined`` instead. For polyfills, we must use ``SensorName`` instead of ``window.SensorName``.\nexport class SimpleAmbientLightSensor extends SimpleSensor {\n async start(als_options) {\n return super.start(window.AmbientLightSensor, [\"ambient-light-sensor\"], als_options);\n }\n\n get illuminance() {\n return this.sensor.illuminance;\n }\n}\n\n\n// See the `W3C draft spec `_.\nexport class SimpleGeolocationSensor extends SimpleSensor {\n async start(geo_options) {\n return super.start(GeolocationSensor, [\"geolocation\"], geo_options);\n }\n\n get latitude() {\n return this.sensor.latitude;\n }\n\n get longitude() {\n return this.sensor.longitude;\n }\n\n get altitude() {\n return this.sensor.altitude;\n }\n\n get accuracy() {\n return this.sensor.accuracy;\n }\n\n get altitudeAccuracy() {\n return this.sensor.altitudeAccuracy;\n }\n\n get heading() {\n return this.sensor.heading;\n }\n\n get speed() {\n return this.sensor.speed;\n }\n}\n\n\nexport class SimpleAccelerometer extends SimpleXYZSensor {\n async start(accelerometer_options) {\n return super.start(Accelerometer, [\"accelerometer\"], accelerometer_options);\n }\n}\n\n\nexport class SimpleGyroscope extends SimpleXYZSensor {\n async start(gyro_options) {\n return super.start(Gyroscope, [\"gyroscope\"], gyro_options);\n }\n}\n\n\nexport class SimpleLinearAccelerationSensor extends SimpleXYZSensor {\n async start(accel_options) {\n return super.start(LinearAccelerationSensor, [\"accelerometer\"], accel_options);\n }\n}\n\n\nexport class SimpleGravitySensor extends SimpleXYZSensor {\n async start(grav_options) {\n return super.start(GravitySensor, [\"accelerometer\"], grav_options);\n }\n}\n\n\nexport class SimpleMagnetometer extends SimpleXYZSensor {\n async start(mag_options) {\n return super.start(window.Magnetometer, [\"magnetometer\"], mag_options);\n }\n}\n\n\nexport class SimpleAbsoluteOrientationSensor extends SimpleOrientationSensor {\n async start(orient_options) {\n return super.start(AbsoluteOrientationSensor, [\"accelerometer\", \"gyroscope\", \"magnetometer\"], orient_options);\n }\n}\n\n\nexport class SimpleRelativeOrientationSensor extends SimpleOrientationSensor {\n async start(orient_options) {\n return super.start(RelativeOrientationSensor, [\"accelerometer\", \"gyroscope\"], orient_options);\n }\n}\n"],"names":["auto_bind","self","object","key","properties","Set","Reflect","ownKeys","add","getPrototypeOf","Object","prototype","getAllProperties","constructor","descriptor","getOwnPropertyDescriptor","value","bind","navigator","permissions","DeviceMotionEvent","requestPermission","DeviceOrientationEvent","query","options","name","Promise","resolve","reject","all","then","vals","state","every","x","Symbol","Event","orientation","window","GeolocationSensor","Sensor","screen","msOrientation","defineProperty","get","DeviceOrientationMixin","superclass","eventNames","args","super","eventName","this","slot","activateCallback","addEventListener","handleEvent","capture","deactivateCallback","removeEventListener","RelativeOrientationSensor","AbsoluteOrientationSensor","Gyroscope","Accelerometer","LinearAccelerationSensor","GravitySensor","SimpleSensor","sensor","async","sensor_class","sensor_permission","sensor_options","map","val","on_error","on_reading","p","that","event","error","start","console","log","Date","err","stop","ready","activated","hasReading","SimpleXYZSensor","y","z","SimpleOrientationSensor","quaternion","populateMatrix","targetMatrix","SimpleAmbientLightSensor","als_options","AmbientLightSensor","illuminance","SimpleGeolocationSensor","geo_options","latitude","longitude","altitude","accuracy","altitudeAccuracy","heading","speed","SimpleAccelerometer","accelerometer_options","SimpleGyroscope","gyro_options","SimpleLinearAccelerationSensor","accel_options","SimpleGravitySensor","grav_options","SimpleMagnetometer","mag_options","Magnetometer","SimpleAbsoluteOrientationSensor","orient_options","SimpleRelativeOrientationSensor"],"sourceRoot":""}