Commit cbf008fa authored by Roque's avatar Roque

erp5_officejs_drone_capture_flag: new script operator feature and more

- add a new operator script editor
- update finish rules and scoring system
- refactor map parameters
- map randomization is done now by new class map utils
- update init flag info msg
- import/export script feature
- update web site CSP
- ui: activate js syntax in user script editor
- ui: styles, section titles, etc - doc api update
- fixes/refactoring
-- fix default target coordinates bug
-- control empty/invalid user scripts
-- raise an error on user script syntax error
-- fix onUpdate timestamp parameter (to integer milliseconds)
-- fix drone loiter (based on nexedi/erp5!1817/)
parent 41270486
...@@ -36,7 +36,6 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -36,7 +36,6 @@ var FixedWingDroneAPI = /** @class */ (function () {
** Function called on start phase of the drone, just before onStart AI script ** Function called on start phase of the drone, just before onStart AI script
*/ */
FixedWingDroneAPI.prototype.internal_start = function (drone) { FixedWingDroneAPI.prototype.internal_start = function (drone) {
drone._targetCoordinates = drone.getCurrentPosition();
drone._maxDeceleration = this.getMaxDeceleration(); drone._maxDeceleration = this.getMaxDeceleration();
if (drone._maxDeceleration <= 0) { if (drone._maxDeceleration <= 0) {
throw new Error('max deceleration must be superior to 0'); throw new Error('max deceleration must be superior to 0');
...@@ -194,6 +193,7 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -194,6 +193,7 @@ var FixedWingDroneAPI = /** @class */ (function () {
distance, distance,
distanceCos, distanceCos,
distanceSin, distanceSin,
distanceToTarget,
currentSinLat, currentSinLat,
currentLonRad, currentLonRad,
groundSpeed, groundSpeed,
...@@ -205,11 +205,19 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -205,11 +205,19 @@ var FixedWingDroneAPI = /** @class */ (function () {
verticalSpeed, verticalSpeed,
yawToDirection; yawToDirection;
if (this._loiter_mode && Math.sqrt( if (this._loiter_mode) {
Math.pow(drone._targetCoordinates.x - drone.position.x, 2) + distanceToTarget = Math.sqrt(
Math.pow(drone._targetCoordinates.y - drone.position.y, 2) Math.pow(drone._targetCoordinates.x - drone.position.x, 2)
) <= this._loiter_radius) { + Math.pow(drone._targetCoordinates.y - drone.position.y, 2)
);
if (Math.abs(distanceToTarget - this._loiter_radius) <= 1) {
newYaw = bearing - 90; newYaw = bearing - 90;
} else if (distanceToTarget < this._loiter_radius) {
newYaw = bearing - 135;
} else {
newYaw = this._getNewYaw(drone, bearing, delta_time);
}
} else { } else {
newYaw = this._getNewYaw(drone, bearing, delta_time); newYaw = this._getNewYaw(drone, bearing, delta_time);
} }
......
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1010.35063.25322.10700</string> </value> <value> <string>1010.45437.13560.55142</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1692366624.83</float> <float>1692989145.27</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -2,10 +2,227 @@ ...@@ -2,10 +2,227 @@
/*jslint nomen: true, indent: 2, maxlen: 80, todo: true, /*jslint nomen: true, indent: 2, maxlen: 80, todo: true,
unparam: true */ unparam: true */
var GAMEPARAMETERS = {}, TEAM_USER = "user", TEAM_ENEMY = "enemy"; var GAMEPARAMETERS = {}, TEAM_USER = "user", TEAM_ENEMY = "enemy", R = 6371e3;
//for DEBUG/TEST mode //for DEBUG/TEST mode
var baseLogFunction = console.log, console_log = ""; var baseLogFunction = console.log, console_log = "";
/******************************* MAP UTILS ************************************/
var MapUtils = /** @class */ (function () {
"use strict";
var FLAG_EPSILON = 15;
//** CONSTRUCTOR
function MapUtils(map_param) {
var _this = this, max_width = _this.latLonDistance(
[map_param.min_lat, map_param.min_lon],
[map_param.min_lat, map_param.max_lon]),
max_height = _this.latLonDistance(
[map_param.min_lat, map_param.min_lon],
[map_param.max_lat, map_param.min_lon]),
map_size = Math.ceil(Math.max(max_width, max_height));
_this.map_param = map_param;
_this.map_param.map_size = map_size;
_this.map_info = {
"depth": map_param.map_size,
"width": map_param.map_size,
"geo_flag_list": [],
"geo_obstacle_list": [],
"flag_distance_epsilon": map_param.flag_distance_epsilon || FLAG_EPSILON
};
Object.assign(_this.map_info, _this.map_param);
_this.map_info.min_x = _this.longitudToX(map_param.min_lon);
_this.map_info.min_y = _this.latitudeToY(map_param.min_lat);
_this.map_info.max_x = _this.longitudToX(map_param.max_lon);
_this.map_info.max_y = _this.latitudeToY(map_param.max_lat);
}
MapUtils.prototype.latLonDistance = function (c1, c2) {
var q1 = c1[0] * Math.PI / 180,
q2 = c2[0] * Math.PI / 180,
dq = (c2[0] - c1[0]) * Math.PI / 180,
dl = (c2[1] - c1[1]) * Math.PI / 180,
a = Math.sin(dq / 2) * Math.sin(dq / 2) +
Math.cos(q1) * Math.cos(q2) *
Math.sin(dl / 2) * Math.sin(dl / 2),
c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
};
MapUtils.prototype.longitudToX = function (lon) {
return (this.map_info.map_size / 360.0) * (180 + lon);
};
MapUtils.prototype.latitudeToY = function (lat) {
return (this.map_info.map_size / 180.0) * (90 - lat);
};
MapUtils.prototype.convertToLocalCoordinates =
function (latitude, longitude, altitude) {
var map_info = this.map_info,
x = this.longitudToX(longitude),
y = this.latitudeToY(latitude);
return {
x: ((x - map_info.min_x) / (map_info.max_x - map_info.min_x)) *
1000 - map_info.width / 2,
y: ((y - map_info.min_y) / (map_info.max_y - map_info.min_y)) *
1000 - map_info.depth / 2,
z: altitude
};
};
MapUtils.prototype.convertToGeoCoordinates = function (x, y, z) {
var lon = x + this.map_info.width / 2,
lat = y + this.map_info.depth / 2;
lon = lon / 1000;
lon = lon * (this.map_info.max_x - this.map_info.min_x) +
this.map_info.min_x;
lon = lon / (this.map_info.map_size / 360.0) - 180;
lat = lat / 1000;
lat = lat * (this.map_info.max_y - this.map_info.min_y) +
this.map_info.min_y;
lat = 90 - lat / (this.map_info.map_size / 180.0);
return {
x: lat,
y: lon,
z: z
};
};
MapUtils.prototype.randomize = function () {
//TODO randomize start_ASML and map height
var _this = this;
function randomIntFromInterval(min, max, random_seed) {
return Math.floor(random_seed.quick() * (max - min + 1) + min);
}
function randomPosition(random_seed, map_size) {
var sign_x = random_seed.quick() < 0.5 ? -1 : 1,
sign_y = random_seed.quick() < 0.5 ? -1 : 1,
pos_x = sign_x * random_seed.quick() * map_size / 2,
pos_y = sign_y * random_seed.quick() * map_size / 2;
return [pos_x, pos_y];
}
var random_seed = new Math.seedrandom(_this.map_param.map_seed), i,
n_enemies = randomIntFromInterval(5, 10, random_seed),
n_flags = randomIntFromInterval(5, 10, random_seed), //TODO change range
n_obstacles = randomIntFromInterval(5, 15, random_seed),
flag_list = [], obstacle_list = [], enemy_list = [], random_position,
obstacles_types = ["box", "cylinder"], type,
obstacle_limit = [_this.map_param.map_size / 6, _this.map_param.map_size / 100,
_this.map_param.map_size / 6, 30],
geo_flag_info, geo_obstacle, coordinates;
//enemies
for (i = 0; i < n_enemies; i += 1) {
random_position = randomPosition(random_seed, _this.map_param.map_size);
enemy_list.push({
"id": i + 10000,
"type": "EnemyDroneAPI",
"position": {
"x": random_position[0],
"y": random_position[1],
"z": 15 //TODO random z? yes
}
});
}
//flags
for (i = 0; i < n_flags; i += 1) {
//avoid flags near the limits
random_position = randomPosition(random_seed, _this.map_param.map_size * 0.75);
flag_list.push({
"position": {
"x": random_position[0],
"y": random_position[1],
"z": 10
},
"score": randomIntFromInterval(1, 5, random_seed),
"weight": randomIntFromInterval(1, 5, random_seed)
});
}
function checkDistance(position, position_list) {
function distance(a, b) {
return Math.sqrt((a.x - b.x) ** 2 + (a.y - b.y) ** 2);
}
var el;
for (el = 0; el < position_list.length; el += 1) {
if (distance(position, position_list[el].position) < _this.map_param.map_size / 6) {
return true;
}
}
return false;
}
//obstacles
for (i = 0; i < n_obstacles; i += 1) {
random_position = randomPosition(random_seed, _this.map_param.map_size);
if (checkDistance({ 'x': random_position[0],
'y': random_position[1]}, flag_list)) {
i -= 1;
} else {
type = randomIntFromInterval(0, 2, random_seed);
obstacle_list.push({
"type": obstacles_types[type],
"position": {
"x": random_position[0],
"y": random_position[1],
"z": 15 //TODO random z?
},
"scale": {
"x": randomIntFromInterval(20, obstacle_limit[type], random_seed),
"y": randomIntFromInterval(20, obstacle_limit[type], random_seed),
"z": randomIntFromInterval(5, obstacle_limit[3], random_seed)
},
"rotation": {
"x": 0,
"y": 0,
"z": 0
}
});
}
}
_this.map_param.obstacle_list = obstacle_list;
_this.map_param.enemy_list = enemy_list;
_this.map_param.flag_list = flag_list;
_this.map_param.starting_position = {
"x": 0,
"y": _this.map_param.map_size / 2 * -0.75,
"z": 15
};
_this.map_info.initial_position = _this.map_param.starting_position;
Object.assign(_this.map_info, _this.map_param);
_this.map_param.flag_list.forEach(function (flag_info, index) {
coordinates = _this.convertToGeoCoordinates(
flag_info.position.x,
flag_info.position.y,
flag_info.position.z
);
geo_flag_info = {
'id': flag_info.id,
'score': flag_info.score,
'weight': flag_info.weight,
'position': {
'x': coordinates.x,
'y': coordinates.y,
'z': coordinates.z
}
};
_this.map_info.geo_flag_list.push(geo_flag_info);
});
_this.map_param.obstacle_list.forEach(function (obstacle_info, index) {
geo_obstacle = {};
Object.assign(geo_obstacle, obstacle_info);
geo_obstacle.position = _this.convertToGeoCoordinates(
obstacle_info.position.x,
obstacle_info.position.y,
obstacle_info.position.z
);
_this.map_info.geo_obstacle_list.push(geo_obstacle);
});
return _this.map_info;
};
return MapUtils;
}());
/******************************************************************************/
/******************************* DRONE MANAGER ********************************/ /******************************* DRONE MANAGER ********************************/
var DroneManager = /** @class */ (function () { var DroneManager = /** @class */ (function () {
"use strict"; "use strict";
...@@ -135,6 +352,7 @@ var DroneManager = /** @class */ (function () { ...@@ -135,6 +352,7 @@ var DroneManager = /** @class */ (function () {
configurable: true configurable: true
}); });
DroneManager.prototype.internal_start = function () { DroneManager.prototype.internal_start = function () {
this._targetCoordinates = this.position;
this._API.internal_start(this); this._API.internal_start(this);
this._canPlay = true; this._canPlay = true;
this._canCommunicate = true; this._canCommunicate = true;
...@@ -175,14 +393,15 @@ var DroneManager = /** @class */ (function () { ...@@ -175,14 +393,15 @@ var DroneManager = /** @class */ (function () {
return; return;
}; };
DroneManager.prototype.internal_update = function (delta_time) { DroneManager.prototype.internal_update = function (delta_time) {
var context = this; var context = this, milliseconds;
if (this._controlMesh) { if (this._controlMesh) {
context._API.internal_update(context, delta_time); context._API.internal_update(context, delta_time);
if (context._canUpdate) { if (context._canUpdate) {
context._canUpdate = false; context._canUpdate = false;
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
return context.onUpdate(context._API._gameManager._game_duration); milliseconds = Math.floor(context._API._gameManager._game_duration);
return context.onUpdate(milliseconds);
}) })
.push(function () { .push(function () {
context._canUpdate = true; context._canUpdate = true;
...@@ -408,15 +627,42 @@ var DroneManager = /** @class */ (function () { ...@@ -408,15 +627,42 @@ var DroneManager = /** @class */ (function () {
var MapManager = /** @class */ (function () { var MapManager = /** @class */ (function () {
"use strict"; "use strict";
var EPSILON = 9.9, var SEED = '6!',
START_Z = 15, //default square map
R = 6371e3; MAP_HEIGHT = 700,
START_AMSL = 595,
MIN_LAT = 45.6419,
MAX_LAT = 45.65,
MIN_LON = 14.265,
MAX_LON = 14.2766,
MAP = {
"height": MAP_HEIGHT,
"start_AMSL": START_AMSL,
"map_seed": SEED,
"min_lat": MIN_LAT,
"max_lat": MAX_LAT,
"min_lon": MIN_LON,
"max_lon": MAX_LON
};
//** CONSTRUCTOR //** CONSTRUCTOR
function MapManager(scene) { function MapManager(scene, map_param) {
var _this = this, max_sky, skybox, skyboxMat, largeGroundMat, flag_material, var _this = this, max_sky, skybox, skyboxMat, largeGroundMat, flag_material,
largeGroundBottom, width, depth, terrain, max, flag_a, flag_b, mast, flag, largeGroundBottom, width, depth, terrain, max, flag_a, flag_b, mast, flag,
count = 0, new_obstacle; count = 0, new_obstacle;
this.setMapInfo(GAMEPARAMETERS.map, GAMEPARAMETERS.initialPosition); if (!map_param) {
// Use default map base parameters
map_param = MAP;
}
_this.mapUtils = new MapUtils(map_param);
if (!map_param.randomized) {
// Randomize map here
map_param = _this.mapUtils.randomize();
console.log("[INFO] using map randomly generated within the game");
} else {
console.log("[INFO] using map randomly generated outside game");
}
_this.map_info = map_param;
max = _this.map_info.width; max = _this.map_info.width;
if (_this.map_info.depth > max) { if (_this.map_info.depth > max) {
max = _this.map_info.depth; max = _this.map_info.depth;
...@@ -551,117 +797,41 @@ var MapManager = /** @class */ (function () { ...@@ -551,117 +797,41 @@ var MapManager = /** @class */ (function () {
mast.material = flag_material; mast.material = flag_material;
flag = BABYLON.Mesh.MergeMeshes([flag_a, flag_b, mast]); flag = BABYLON.Mesh.MergeMeshes([flag_a, flag_b, mast]);
flag.id = index; flag.id = index;
//flag.weight = _this.map_info.flag_weight;
flag.location = flag_info.position; flag.location = flag_info.position;
flag.drone_collider_list = []; //flag.drone_collider_list = [];
flag.weight = flag_info.weight;
flag.score = flag_info.score;
flag.id = index;
_this._flag_list.push(flag); _this._flag_list.push(flag);
}); });
} }
MapManager.prototype.setMapInfo = function (map_dict, initial_position) {
var max_width = this.latLonDistance([map_dict.min_lat, map_dict.min_lon],
[map_dict.min_lat, map_dict.max_lon]),
max_height = this.latLonDistance([map_dict.min_lat, map_dict.min_lon],
[map_dict.max_lat, map_dict.min_lon]),
map_size = Math.ceil(Math.max(max_width, max_height)),
starting_point = map_size / 2 * -0.75;
this.map_info = {
"depth": map_size,
"height": map_dict.height,
"width": map_size,
"map_size": map_size,
"start_AMSL": map_dict.start_AMSL,
"flag_list": map_dict.flag_list,
"geo_flag_list": [],
"flag_distance_epsilon": map_dict.flag_distance_epsilon || EPSILON,
"obstacle_list": map_dict.obstacle_list,
"geo_obstacle_list": [],
"initial_position": {
"x": 0,
"y": starting_point,
"z": START_Z
}
};
this.map_info.min_x = this.longitudToX(map_dict.min_lon);
this.map_info.min_y = this.latitudeToY(map_dict.min_lat);
this.map_info.max_x = this.longitudToX(map_dict.max_lon);
this.map_info.max_y = this.latitudeToY(map_dict.max_lat);
var map = this;
map_dict.flag_list.forEach(function (flag_info, index) {
map.map_info.geo_flag_list.push(map.convertToGeoCoordinates(
flag_info.position.x,
flag_info.position.y,
flag_info.position.z
));
});
map_dict.obstacle_list.forEach(function (obstacle_info, index) {
var geo_obstacle = {};
Object.assign(geo_obstacle, obstacle_info);
geo_obstacle.position = map.convertToGeoCoordinates(
obstacle_info.position.x,
obstacle_info.position.y,
obstacle_info.position.z
);
map.map_info.geo_obstacle_list.push(geo_obstacle);
});
};
MapManager.prototype.getMapInfo = function () { MapManager.prototype.getMapInfo = function () {
return this.map_info; return this.map_info;
}; };
MapManager.prototype.longitudToX = function (lon) {
return (this.map_info.map_size / 360.0) * (180 + lon);
};
MapManager.prototype.latitudeToY = function (lat) {
return (this.map_info.map_size / 180.0) * (90 - lat);
};
//TODO refactor latLonOffset, should be the reverse of lat-lon distance //TODO refactor latLonOffset, should be the reverse of lat-lon distance
//then map_size can be used as parameter (get max lat-lon from map_size) //then map_size can be used as parameter (get max lat-lon from map_size)
/*MapManager.prototype.latLonOffset = function (lat, lon, offset_in_mt) { /*MapManager.prototype.latLonOffset = function (lat, lon, offset_in_mt) {
var R = 6371e3, //Earth radius
lat_offset = offset_in_mt / R, lat_offset = offset_in_mt / R,
lon_offset = offset_in_mt / (R * Math.cos(Math.PI * lat / 180)); lon_offset = offset_in_mt / (R * Math.cos(Math.PI * lat / 180));
return [lat + lat_offset * 180 / Math.PI, return [lat + lat_offset * 180 / Math.PI,
lon + lon_offset * 180 / Math.PI]; lon + lon_offset * 180 / Math.PI];
};*/ };*/
MapManager.prototype.latLonDistance = function (c1, c2) { MapManager.prototype.latLonDistance = function (c1, c2) {
var q1 = c1[0] * Math.PI / 180, return this.mapUtils.latLonDistance(c1, c2);
q2 = c2[0] * Math.PI / 180, };
dq = (c2[0] - c1[0]) * Math.PI / 180, MapManager.prototype.longitudToX = function (lon) {
dl = (c2[1] - c1[1]) * Math.PI / 180, return this.mapUtils.longitudToX(lon);
a = Math.sin(dq / 2) * Math.sin(dq / 2) + };
Math.cos(q1) * Math.cos(q2) * MapManager.prototype.latitudeToY = function (lat) {
Math.sin(dl / 2) * Math.sin(dl / 2), return this.mapUtils.latitudeToY(lat);
c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
}; };
MapManager.prototype.convertToLocalCoordinates = MapManager.prototype.convertToLocalCoordinates =
function (latitude, longitude, altitude) { function (latitude, longitude, altitude) {
var map_info = this.map_info, return this.mapUtils.convertToLocalCoordinates(
x = this.longitudToX(longitude), latitude, longitude, altitude);
y = this.latitudeToY(latitude);
return {
x: ((x - map_info.min_x) / (map_info.max_x - map_info.min_x)) *
1000 - map_info.width / 2,
y: ((y - map_info.min_y) / (map_info.max_y - map_info.min_y)) *
1000 - map_info.depth / 2,
z: altitude
};
}; };
MapManager.prototype.convertToGeoCoordinates = function (x, y, z) { MapManager.prototype.convertToGeoCoordinates = function (x, y, z) {
var lon = x + this.map_info.width / 2, return this.mapUtils.convertToGeoCoordinates(x, y, z);
lat = y + this.map_info.depth / 2;
lon = lon / 1000;
lon = lon * (this.map_info.max_x - this.map_info.min_x) +
this.map_info.min_x;
lon = lon / (this.map_info.map_size / 360.0) - 180;
lat = lat / 1000;
lat = lat * (this.map_info.max_y - this.map_info.min_y) +
this.map_info.min_y;
lat = 90 - lat / (this.map_info.map_size / 180.0);
return {
x: lat,
y: lon,
z: z
};
}; };
return MapManager; return MapManager;
}()); }());
...@@ -701,8 +871,7 @@ var GameManager = /** @class */ (function () { ...@@ -701,8 +871,7 @@ var GameManager = /** @class */ (function () {
header_list = ["timestamp (ms)", "latitude (°)", "longitude (°)", header_list = ["timestamp (ms)", "latitude (°)", "longitude (°)",
"AMSL (m)", "rel altitude (m)", "yaw (°)", "AMSL (m)", "rel altitude (m)", "yaw (°)",
"ground speed (m/s)", "climb rate (m/s)"]; "ground speed (m/s)", "climb rate (m/s)"];
drone_count = GAMEPARAMETERS.map.drones.user.length + drone_count = GAMEPARAMETERS.drone.list.length;
GAMEPARAMETERS.map.drones.enemy.length;
for (drone = 0; drone < drone_count; drone += 1) { for (drone = 0; drone < drone_count; drone += 1) {
this._flight_log[drone] = []; this._flight_log[drone] = [];
this._flight_log[drone].push(header_list); this._flight_log[drone].push(header_list);
...@@ -801,7 +970,9 @@ var GameManager = /** @class */ (function () { ...@@ -801,7 +970,9 @@ var GameManager = /** @class */ (function () {
}; };
GameManager.prototype.logError = function (drone, error) { GameManager.prototype.logError = function (drone, error) {
if (drone._id < this._flight_log.length) { // don't log enemies
this._flight_log[drone._id].push(error.stack); this._flight_log[drone._id].push(error.stack);
}
}; };
GameManager.prototype._checkDroneOut = function (drone) { GameManager.prototype._checkDroneOut = function (drone) {
...@@ -854,8 +1025,13 @@ var GameManager = /** @class */ (function () { ...@@ -854,8 +1025,13 @@ var GameManager = /** @class */ (function () {
//there is not a proper collision //there is not a proper collision
if (distance(drone.position, flag.location) <= if (distance(drone.position, flag.location) <=
this._mapManager.getMapInfo().flag_distance_epsilon) { this._mapManager.getMapInfo().flag_distance_epsilon) {
if (!flag.drone_collider_list.includes(drone.id)) { drone._internal_crash(new Error('Drone ' + drone.id +
//TODO notify the drone somehow? Or the AI script is in charge? ' touched flag ' + flag.id));
if (flag.weight > 0) {
flag.weight -= 1;
drone.score += flag.score; // move score to a global place? GM, MM?
}
/*if (!flag.drone_collider_list.includes(drone.id)) {
//console.log("flag " + flag.id + " hit by drone " + drone.id); //console.log("flag " + flag.id + " hit by drone " + drone.id);
drone._internal_crash(new Error('Drone ' + drone.id + drone._internal_crash(new Error('Drone ' + drone.id +
' touched a flag.')); ' touched a flag.'));
...@@ -863,7 +1039,7 @@ var GameManager = /** @class */ (function () { ...@@ -863,7 +1039,7 @@ var GameManager = /** @class */ (function () {
drone.score++; drone.score++;
flag.drone_collider_list.push(drone.id); flag.drone_collider_list.push(drone.id);
} }
} }*/
} }
} }
}; };
...@@ -968,11 +1144,11 @@ var GameManager = /** @class */ (function () { ...@@ -968,11 +1144,11 @@ var GameManager = /** @class */ (function () {
_this._result_message += "ALL DRONES DOWN!"; _this._result_message += "ALL DRONES DOWN!";
return _this._finish(); return _this._finish();
} }
if (_this._allFlagsCaptured()) { /*if (_this._allFlagsCaptured()) {
console.log("ALL FLAGS CAPTURED"); console.log("ALL FLAGS CAPTURED");
_this._result_message += "ALL FLAGS CAPTURED!"; _this._result_message += "ALL FLAGS CAPTURED!";
return _this._finish(); return _this._finish();
} }*/
}); });
}; };
...@@ -1061,7 +1237,8 @@ var GameManager = /** @class */ (function () { ...@@ -1061,7 +1237,8 @@ var GameManager = /** @class */ (function () {
return finish; return finish;
}; };
GameManager.prototype._allFlagsCaptured = function () { //game ends due to timeout or all drones stopped/crashed
/*GameManager.prototype._allFlagsCaptured = function () {
var finish = true; var finish = true;
this._mapManager._flag_list.forEach(function (flag) { this._mapManager._flag_list.forEach(function (flag) {
//do not use flag weight for now, just 1 hit is enough //do not use flag weight for now, just 1 hit is enough
...@@ -1071,14 +1248,12 @@ var GameManager = /** @class */ (function () { ...@@ -1071,14 +1248,12 @@ var GameManager = /** @class */ (function () {
} }
}); });
return finish; return finish;
}; };*/
GameManager.prototype._calculateUserScore = function () { GameManager.prototype._calculateUserScore = function () {
var score = 0; var score = 0;
this._droneList_user.forEach(function (drone) { this._droneList_user.forEach(function (drone) {
//if (drone.can_play) {
score += drone.score; score += drone.score;
//}
}); });
return score; return score;
}; };
...@@ -1135,13 +1310,15 @@ var GameManager = /** @class */ (function () { ...@@ -1135,13 +1310,15 @@ var GameManager = /** @class */ (function () {
this._scene this._scene
); );
hemi_south.intensity = 0.75; hemi_south.intensity = 0.75;
cam_radius = (GAMEPARAMETERS.map.map_size * 1.10 < 6000) ? //HARDCODE camera to a hardcoded map_size
GAMEPARAMETERS.map.map_size * 1.10 : 6000; //skybox scene limit var map_size = 900; //GAMEPARAMETERS.map.map_size
//skybox scene limit
cam_radius = (map_size * 1.10 < 6000) ? map_size * 1.10 : 6000;
camera = new BABYLON.ArcRotateCamera("camera", 0, 1.25, cam_radius, camera = new BABYLON.ArcRotateCamera("camera", 0, 1.25, cam_radius,
BABYLON.Vector3.Zero(), this._scene); BABYLON.Vector3.Zero(), this._scene);
camera.wheelPrecision = 10; camera.wheelPrecision = 10;
//zoom out limit //zoom out limit
camera.upperRadiusLimit = GAMEPARAMETERS.map.map_size * 10; camera.upperRadiusLimit = map_size * 10;
//scene.activeCamera.upperRadiusLimit = max * 4; //scene.activeCamera.upperRadiusLimit = max * 4;
//changed for event handling //changed for event handling
//camera.attachControl(this._scene.getEngine().getRenderingCanvas()); //orig //camera.attachControl(this._scene.getEngine().getRenderingCanvas()); //orig
...@@ -1161,10 +1338,10 @@ var GameManager = /** @class */ (function () { ...@@ -1161,10 +1338,10 @@ var GameManager = /** @class */ (function () {
ctx._map_swapped = true; ctx._map_swapped = true;
} }
// Init the map // Init the map
_this._mapManager = new MapManager(ctx._scene); _this._mapManager = new MapManager(ctx._scene, GAMEPARAMETERS.map);
ctx._spawnDrones(_this._mapManager.getMapInfo().initial_position, ctx._spawnDrones(_this._mapManager.getMapInfo().initial_position,
GAMEPARAMETERS.map.drones.user, TEAM_USER, ctx); GAMEPARAMETERS.drone.list, TEAM_USER, ctx);
ctx._spawnDrones(null, GAMEPARAMETERS.map.drones.enemy, TEAM_ENEMY, ctx); ctx._spawnDrones(null, _this._mapManager.getMapInfo().enemy_list, TEAM_ENEMY, ctx);
// Hide the drone prefab // Hide the drone prefab
DroneManager.Prefab.isVisible = false; DroneManager.Prefab.isVisible = false;
//Hack to make advanced texture work //Hack to make advanced texture work
...@@ -1246,9 +1423,7 @@ var GameManager = /** @class */ (function () { ...@@ -1246,9 +1423,7 @@ var GameManager = /** @class */ (function () {
drone._tick = 0; drone._tick = 0;
promise_list.push(drone.internal_start()); promise_list.push(drone.internal_start());
}); });
start_msg = { start_msg = GAMEPARAMETERS.operator_init_msg;
'flag_positions': _this._mapManager.getMapInfo().geo_flag_list
};
promise_list.push(_this._droneList_user[0].sendMsg(start_msg)); promise_list.push(_this._droneList_user[0].sendMsg(start_msg));
_this._droneList_enemy.forEach(function (drone) { _this._droneList_enemy.forEach(function (drone) {
drone._tick = 0; drone._tick = 0;
...@@ -1321,15 +1496,14 @@ var GameManager = /** @class */ (function () { ...@@ -1321,15 +1496,14 @@ var GameManager = /** @class */ (function () {
return false; return false;
} }
function spawnDrone(x, y, z, index, drone_info, api, team) { function spawnDrone(x, y, z, index, drone_info, api, team) {
var default_drone_AI = api.getDroneAI(), code, base, code_eval, trim; var default_drone_AI = api.getDroneAI(), code, code_eval;
if (default_drone_AI) { if (default_drone_AI) {
code = default_drone_AI; code = default_drone_AI;
} else { } else {
code = drone_info.script_content; code = drone_info.script_content;
} }
trim = code.trim(); if (!code.includes("me.onStart")) {
if (!trim) { code = "me.onStart = function () { me.exit(); };";
code = "me.onStart = function () { forcedErrorEmptyScript };";
} }
code_eval = "let drone = new DroneManager(ctx._scene, " + code_eval = "let drone = new DroneManager(ctx._scene, " +
index + ', api, team);' + index + ', api, team);' +
...@@ -1349,17 +1523,18 @@ var GameManager = /** @class */ (function () { ...@@ -1349,17 +1523,18 @@ var GameManager = /** @class */ (function () {
if (x !== null && y !== null && z !== null) { if (x !== null && y !== null && z !== null) {
code_eval += "me.setStartingPosition(" + x + ", " + y + ", " + z + ");"; code_eval += "me.setStartingPosition(" + x + ", " + y + ", " + z + ");";
} }
base = code_eval; //base = code_eval;
code_eval += code + "}; droneMe(Date, drone, Math, {});"; code_eval += code + "}; droneMe(Date, drone, Math, {});";
base += "};ctx._droneList_" + team + ".push(drone)"; //base += "};ctx._droneList_" + team + ".push(drone)";
code_eval += "ctx._droneList_" + team + ".push(drone)"; code_eval += "ctx._droneList_" + team + ".push(drone)";
/*jslint evil: true*/ /*jslint evil: true*/
try { eval(code_eval);
/*jslint evil: false*/
/*try {
eval(code_eval); eval(code_eval);
} catch (error) { } catch (error) {
eval(base); eval(base);
} }*/
/*jslint evil: false*/
} }
function randomSpherePoint(x0, y0, z0, rx0, ry0, rz0) { function randomSpherePoint(x0, y0, z0, rx0, ry0, rz0) {
var u = Math.random(), v = Math.random(), var u = Math.random(), v = Math.random(),
...@@ -1388,7 +1563,7 @@ var GameManager = /** @class */ (function () { ...@@ -1388,7 +1563,7 @@ var GameManager = /** @class */ (function () {
position_list.push(position); position_list.push(position);
var id_offset = 0; var id_offset = 0;
if (team == TEAM_ENEMY) { if (team == TEAM_ENEMY) {
id_offset = GAMEPARAMETERS.map.drones.user.length; id_offset = GAMEPARAMETERS.drone.list.length;
} }
api = new this.APIs_dict[drone_list[i].type]( api = new this.APIs_dict[drone_list[i].type](
this, this,
......
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1010.23697.26501.43008</string> </value> <value> <string>1010.55458.31149.16742</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1691684378.73</float> <float>1693590015.02</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -10,6 +10,67 @@ ...@@ -10,6 +10,67 @@
<div class="documentation"> <div class="documentation">
<h1>Game specifications</h1>
<h3>Start message with information about the flags</h3>
<!-- Flag message -->
<h4 class="item-name" id="flag_msg"><span>msg.flag_positions</span><span>: list</span></h4>
<p class="item-descr">List containing an information dictionary for each flag in the map</p>
<div>
<h5 class="item-param-1">Flag info dictionary:</h5>
<p class="item-descr"></p>
</div>
<div>
<h5 class="item-param-1">Param</h5>
<h5 class="item-param-2">Description</h5>
</div>
<div>
<p class="item-param-1">id: Integer</p>
<p class="item-param-2">Flag id</p>
</div>
<div>
<p class="item-param-1">score: Integer</p>
<p class="item-param-2">Flag score for hit</p>
</div>
<div>
<p class="item-param-1">weight: Integer</p>
<p class="item-param-2">Flag weight, number of hits to be captured</p>
</div>
<div>
<p class="item-param-1">position: dictionary</p>
<p class="item-param-2">
{<br>
&nbsp;&nbsp;x: number, //latitude (in degrees)<br>
&nbsp;&nbsp;y: number, //longitude (in degrees)<br>
&nbsp;&nbsp;z: number //altitude (in meters)<br>
}<br>
</p>
</div>
<div class="line"></div>
<h3>Game scoring</h3>
<!-- Scoring -->
<h4 class="item-name" id="scoring"><span>Score</span></h4>
<p class="item-descr">Every flag has a score, every drone hit on the flag will give it that score value.</p>
<p class="item-descr">The number of hits on a flag is determined by its weight.</p>
<p class="item-descr">Once the number of hits is equal to the flag weight, no more score will be given on following hits.</p>
<p class="item-descr">Total score is the sum of all drones score when the game finishes.</p>
<h5 class="item-param-1">Example</h5>
<p class="item-example">A flag with score=3 and weight=2 will grant 3 score points on every drone hit, up to 2 hits.</p>
<div class="line"></div>
<h1>Fixed Wings Drone API</h1> <h1>Fixed Wings Drone API</h1>
<h3>API functions</h3> <h3>API functions</h3>
...@@ -442,7 +503,7 @@ ...@@ -442,7 +503,7 @@
<!-- id --> <!-- id -->
<h4 class="item-name" id="id"><span>id</span><span>: number</span></h4> <h4 class="item-name" id="id"><span>id</span><span>: number</span></h4>
<p class="item-descr">Drone unique numeric identifier: from 0 to 9.</p> <p class="item-descr">Drone unique numeric identifier.</p>
<h5 class="item-param-1">Example</h5> <h5 class="item-param-1">Example</h5>
......
...@@ -244,7 +244,7 @@ ...@@ -244,7 +244,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1010.23624.18144.48810</string> </value> <value> <string>1010.51249.55554.52258</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -264,7 +264,7 @@ ...@@ -264,7 +264,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1691679891.23</float> <float>1693418554.45</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
.import-export {
white-space: nowrap;
}
.import-export input {
display: none;
}
.import-export label {
border: 1px solid #ccc;
display: inline-block;
padding: 6px 12px;
cursor: pointer;
}
.item-label {
background-color: #F8F8F8;
padding: 8px;
margin: 8px 0;
font-size: 1.2em;
font-weight: bold;
}
.run-game {
margin-top: 0 !important;
}
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Web Style" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Access_contents_information_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Add_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Change_local_roles_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_View_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>content_md5</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>gadget_erp5_page_drone_capture_flag_script_page.css</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ojs_drone_capture_flag_script_page_css</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>short_title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Drone Capture Flag Script Page CSS</string> </value>
</item>
<item>
<key> <string>version</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>document_publication_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>edit_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>processing_status_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>publish_alive</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1693841614.38</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>published_alive</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>edit</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1010.62540.7060.5000</string> </value>
</item>
<item>
<key> <string>state</string> </key>
<value> <string>current</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1694015251.98</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="5" aka="AAAAAAAAAAU=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_processing_state</string> </key>
<value> <string>empty</string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>0.0.0.0</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1693841589.15</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<title>Drone Capture Flag Script Page</title> <title>Drone Capture Flag Script Page</title>
<link rel="http://www.renderjs.org/rel/interface" href="interface_page.html"> <link rel="http://www.renderjs.org/rel/interface" href="interface_page.html">
<link rel="stylesheet" type="text/css" href="gadget_erp5_page_drone_capture_flag_script_page.css">
<!-- renderjs --> <!-- renderjs -->
<script src="rsvp.js" type="text/javascript"></script> <script src="rsvp.js" type="text/javascript"></script>
...@@ -19,23 +20,51 @@ ...@@ -19,23 +20,51 @@
<script src="gadget_global.js" type="text/javascript"></script> <script src="gadget_global.js" type="text/javascript"></script>
<script src="domsugar.js" type="text/javascript"></script> <script src="domsugar.js" type="text/javascript"></script>
<script type="text/javascript" src="./libraries/seedrandom.min.js"></script> <script type="text/javascript" src="./libraries/seedrandom.min.js"></script>
<script type="text/javascript" src="./libraries/require.js"></script>
<script src="gadget_erp5_page_drone_capture_flag_script_page.js" type="text/javascript"></script> <script src="gadget_erp5_page_drone_capture_flag_script_page.js" type="text/javascript"></script>
</head> </head>
<body> <body>
<form> <form>
<!-- parameters input form -->
<label class="item-label">Game parameters</label>
<div data-gadget-url="gadget_erp5_form.html" <div data-gadget-url="gadget_erp5_form.html"
data-gadget-scope="form_view" data-gadget-scope="form_view"
data-gadget-sandbox="public"> data-gadget-sandbox="public">
</div> </div>
<input name="action_run" class="dialogconfirm" type="submit" value="Run" style="margin-bottom: 20pt;margin-top: 20pt;"> <!-- operator script editor -->
<a data-i18n="Storages"></a> <!-- for zelenium test common macro --> <label class="item-label">Operator script</label>
<div data-gadget-url="gadget_editor.html"
data-gadget-scope="operator-editor"
data-gadget-sandbox="">
</div>
<div class="import-export">
<label class="import">
<input type="file" id="import" >
Import
</label>
<label class="export">
<input type="button" id="export" >
Export
</label>
</div>
<!-- AI script editor -->
<label class="item-label">AI script</label>
<div data-gadget-url="gadget_editor.html"
data-gadget-scope="script-editor"
data-gadget-sandbox="">
</div>
<!-- Game -->
<label class="item-label">Game</label>
<input name="action_run" class="run-game" type="submit" value="Run">
<div class="simulator_div"></div> <div class="simulator_div"></div>
<div data-gadget-url="gadget_erp5_form.html" <div data-gadget-url="gadget_erp5_form.html"
data-gadget-scope="form_view_babylonjs" data-gadget-scope="form_view_babylonjs"
data-gadget-sandbox="public"> data-gadget-sandbox="public">
</div> </div>
<a data-i18n="Storages"></a> <!-- for zelenium test common macro -->
</form> </form>
</body> </body>
</html> </html>
\ No newline at end of file
...@@ -244,7 +244,7 @@ ...@@ -244,7 +244,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1008.22253.2281.60074</string> </value> <value> <string>1010.62539.25351.39680</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -264,7 +264,7 @@ ...@@ -264,7 +264,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1683820259.6</float> <float>1694014905.34</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
/*jslint indent: 2, maxlen: 100*/ /*jslint indent: 2, maxlen: 100*/
/*global window, rJS, domsugar, document, URLSearchParams, Blob*/ /*global window, rJS, domsugar, document, URLSearchParams, Blob, require, MapUtils*/
(function (window, rJS, domsugar, document, URLSearchParams, Blob) { (function (window, rJS, domsugar, document, URLSearchParams, Blob, require) {
"use strict"; "use strict";
//Drone default values - TODO: get them from the drone API //Drone default values - TODO: get them from the drone API
var SIMULATION_SPEED = 10, var SIMULATION_SPEED = 10,
SIMULATION_TIME = 270, SIMULATION_TIME = 270,
//HARDCODED map size: it is defined by min-max lat-lon distance //default square map
//this is done by the map manager (latLonDistance) MAP_HEIGHT = 700,
//but map_size is needed here for map randomization (location of objects) START_AMSL = 595,
//TODO refactor: or randomization is moved to map manager (seed as param) MIN_LAT = 45.6419,
//or randomization is done here but with geo-coordinates (not meters) MAX_LAT = 45.65,
MAP_SIZE = 900, MIN_LON = 14.265,
//square map MAX_LON = 14.2766,
min_lat = 45.6419, //SEED FORM PARAMETER IS BROKEN (used in randomization before user inputs)
max_lat = 45.65, // only way to set it and use it is via url parameter 'seed'
min_lon = 14.265, url_sp = new URLSearchParams(window.location.hash),
max_lon = 14.2766, url_seed = url_sp.get("seed"),
map_height = 700, SEED = url_seed ? url_seed : '6!',
start_AMSL = 595, MAP = {
"height": MAP_HEIGHT,
"start_AMSL": START_AMSL,
"map_seed": SEED,
"min_lat": MIN_LAT,
"max_lat": MAX_LAT,
"min_lon": MIN_LON,
"max_lon": MAX_LON
},
JSON_MAP,
DEFAULT_SPEED = 16, DEFAULT_SPEED = 16,
MAX_ACCELERATION = 6, MAX_ACCELERATION = 6,
MAX_DECELERATION = 1, MAX_DECELERATION = 1,
...@@ -30,8 +39,6 @@ ...@@ -30,8 +39,6 @@
MAX_CLIMB_RATE = 8, MAX_CLIMB_RATE = 8,
MAX_SINK_RATE = 3, MAX_SINK_RATE = 3,
NUMBER_OF_DRONES = 10, NUMBER_OF_DRONES = 10,
FLAG_WEIGHT = 5,
SEED = '6',
// Non-inputs parameters // Non-inputs parameters
DEFAULT_SCRIPT_CONTENT = DEFAULT_SCRIPT_CONTENT =
'var EPSILON = 15,\n' + 'var EPSILON = 15,\n' +
...@@ -57,7 +64,7 @@ ...@@ -57,7 +64,7 @@
'\n' + '\n' +
'me.onGetMsg = function (msg) {\n' + 'me.onGetMsg = function (msg) {\n' +
' if (msg && msg.flag_positions) {\n' + ' if (msg && msg.flag_positions) {\n' +
' me.flag_positions = msg.flag_positions\n' + ' me.flag_positions = msg.flag_positions;\n' +
' me.next_checkpoint = me.id % me.flag_positions.length;\n' + ' me.next_checkpoint = me.id % me.flag_positions.length;\n' +
' }\n' + ' }\n' +
'};\n' + '};\n' +
...@@ -79,9 +86,9 @@ ...@@ -79,9 +86,9 @@
' if (!me.direction_set) {\n' + ' if (!me.direction_set) {\n' +
' if (me.next_checkpoint < me.flag_positions.length) {\n' + ' if (me.next_checkpoint < me.flag_positions.length) {\n' +
' me.setTargetCoordinates(\n' + ' me.setTargetCoordinates(\n' +
' me.flag_positions[me.next_checkpoint].x,\n' + ' me.flag_positions[me.next_checkpoint].position.x,\n' +
' me.flag_positions[me.next_checkpoint].y,\n' + ' me.flag_positions[me.next_checkpoint].position.y,\n' +
' me.flag_positions[me.next_checkpoint].z + me.id\n' + ' me.flag_positions[me.next_checkpoint].position.z + me.id\n' +
' );\n' + ' );\n' +
//' console.log("[DEMO] Going to Checkpoint %d", me.next_checkpoint);\n' + //' console.log("[DEMO] Going to Checkpoint %d", me.next_checkpoint);\n' +
' }\n' + ' }\n' +
...@@ -98,7 +105,7 @@ ...@@ -98,7 +105,7 @@
' me.current_position = me.getCurrentPosition();\n' + ' me.current_position = me.getCurrentPosition();\n' +
' me.distance = distance(\n' + ' me.distance = distance(\n' +
' me.current_position,\n' + ' me.current_position,\n' +
' me.flag_positions[me.next_checkpoint]\n' + ' me.flag_positions[me.next_checkpoint].position\n' +
' );\n' + ' );\n' +
' if (me.distance <= EPSILON) {\n' + ' if (me.distance <= EPSILON) {\n' +
//' console.log("[DEMO] Reached Checkpoint %d", me.next_checkpoint);\n' + //' console.log("[DEMO] Reached Checkpoint %d", me.next_checkpoint);\n' +
...@@ -107,6 +114,12 @@ ...@@ -107,6 +114,12 @@
' }\n' + ' }\n' +
' return;\n' + ' return;\n' +
' }\n' + ' }\n' +
' if (me.next_checkpoint == me.flag_positions.length) {\n' +
' me.triggerParachute();\n' +
' }\n' +
' if (me.landed()) {\n' +
' me.exit();\n' +
' }\n' +
'};\n' + '};\n' +
'\n' + '\n' +
'me.onDroneViewInfo = function (drone_view) {\n' + 'me.onDroneViewInfo = function (drone_view) {\n' +
...@@ -115,7 +128,7 @@ ...@@ -115,7 +128,7 @@
' me.dodging = drone_view.obstacles[0];\n' + ' me.dodging = drone_view.obstacles[0];\n' +
' me.direction_set = false;\n' + ' me.direction_set = false;\n' +
' var random = Math.random() < 0.5, dodge_point = {};\n' + ' var random = Math.random() < 0.5, dodge_point = {};\n' +
' Object.assign(dodge_point, me.flag_positions[me.next_checkpoint]);\n' + ' Object.assign(dodge_point, me.flag_positions[me.next_checkpoint].position);\n' +
' if (random) {\n' + ' if (random) {\n' +
' dodge_point.x = dodge_point.x * -1;\n' + ' dodge_point.x = dodge_point.x * -1;\n' +
' } else {\n' + ' } else {\n' +
...@@ -132,9 +145,40 @@ ...@@ -132,9 +145,40 @@
LOGIC_FILE_LIST = [ LOGIC_FILE_LIST = [
'gadget_erp5_page_drone_capture_flag_logic.js', 'gadget_erp5_page_drone_capture_flag_logic.js',
'gadget_erp5_page_drone_capture_flag_fixedwingdrone.js', 'gadget_erp5_page_drone_capture_flag_fixedwingdrone.js',
'gadget_erp5_page_drone_capture_flag_enemydrone.js' 'gadget_erp5_page_drone_capture_flag_enemydrone.js',
'./libraries/seedrandom.min.js'
]; ];
function handleFileSelect(event, gadget, options) {
var reader = new FileReader()
reader.onload = (event) => handleFileLoad(event, gadget, options);
reader.readAsText(event.target.files[0]);
}
function handleFileLoad(event, gadget, options) {
options.operator_script = event.target.result;
return gadget.changeState(options);
}
function downloadFromTextContent(gadget, text_content, title) {
var element = gadget.element,
a = window.document.createElement("a"),
url = window.URL.createObjectURL(new Blob([text_content], {type: 'text/plain'})),
name_list = [title, "js"];
element.appendChild(a);
a.style = "display: none";
a.href = url;
a.download = name_list.join('.');
a.click();
element.removeChild(a);
window.URL.revokeObjectURL(url);
}
//Randomize map before render, so it's available on operator editor
require(['gadget_erp5_page_drone_capture_flag_logic.js'], function () {
JSON_MAP = new MapUtils(MAP).randomize();
});
rJS(window) rJS(window)
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// Acquired methods // Acquired methods
...@@ -151,19 +195,60 @@ ...@@ -151,19 +195,60 @@
}) })
.onEvent('submit', function () { .onEvent('submit', function () {
var gadget = this; var gadget = this, operator_init_msg, script_content;
return gadget.getDeclaredGadget('form_view') return gadget.getDeclaredGadget('operator-editor')
.push(function (operator_editor) {
return operator_editor.getContent();
})
.push(function (content) {
/*jslint evil: true*/
try {
operator_init_msg = new Function(content.operator_editor)();
} catch (error) {
operator_init_msg = {'error': error};
}
/*jslint evil: false*/
if (!operator_init_msg) operator_init_msg = {};
return gadget.getDeclaredGadget('script-editor');
})
.push(function (script_editor) {
return script_editor.getContent();
})
.push(function (content) {
script_content = content.script_editor;
return gadget.getDeclaredGadget('form_view');
})
.push(function (form_gadget) { .push(function (form_gadget) {
return form_gadget.getContent(); return form_gadget.getContent();
}) })
.push(function (input) { .push(function (input) {
input.operator_init_msg = operator_init_msg;
input.script = script_content;
gadget.runGame(input); gadget.runGame(input);
}); });
}) })
.declareMethod('render', function render() { .onEvent('click', function (evt) {
var gadget = this, url_sp = new URLSearchParams(window.location.hash), var gadget = this;
url_seed = url_sp.get("seed"); if (evt.target.id === "import") {
return;
}
if (evt.target.id === "export") {
return gadget.getDeclaredGadget('operator-editor')
.push(function (operator_editor) {
return operator_editor.getContent();
})
.push(function (content) {
downloadFromTextContent(gadget, content.operator_editor, 'operator_script');
});
}
}, false, false)
.declareMethod('render', function render(options) {
var gadget = this,
loadedFile = (event) => handleFileSelect(event, gadget, options);
gadget.element.querySelector('#import').addEventListener("change", loadedFile);
MAP.map_seed = SEED;
return gadget.getDeclaredGadget('form_view') return gadget.getDeclaredGadget('form_view')
.push(function (form_gadget) { .push(function (form_gadget) {
return form_gadget.render({ return form_gadget.render({
...@@ -301,28 +386,6 @@ ...@@ -301,28 +386,6 @@
"hidden": 0, "hidden": 0,
"type": "FloatField" "type": "FloatField"
}, },
/*"my_map_size": {
"description": "",
"title": "Map size",
"default": MAP_SIZE,
"css_class": "",
"required": 1,
"editable": 1,
"key": "map_size",
"hidden": 0,
"type": "FloatField"
},*/
"my_start_AMSL": {
"description": "",
"title": "Start AMSL",
"default": start_AMSL,
"css_class": "",
"required": 1,
"editable": 1,
"key": "start_AMSL",
"hidden": 0,
"type": "FloatField"
},
"my_map_seed": { "my_map_seed": {
"description": "Seed value to randomize the map", "description": "Seed value to randomize the map",
"title": "Seed value", "title": "Seed value",
...@@ -334,28 +397,6 @@ ...@@ -334,28 +397,6 @@
"hidden": 0, "hidden": 0,
"type": "StringField" "type": "StringField"
}, },
"my_map_height": {
"description": "",
"title": "Map Height",
"default": map_height,
"css_class": "",
"required": 1,
"editable": 1,
"key": "map_height",
"hidden": 0,
"type": "IntegerField"
},
/*"my_flag_weight": {
"description": "",
"title": "Flag Weight",
"default": FLAG_WEIGHT,
"css_class": "",
"required": 1,
"editable": 1,
"key": "flag_weight",
"hidden": 0,
"type": "IntegerField"
},*/
"my_number_of_drones": { "my_number_of_drones": {
"description": "", "description": "",
"title": "Number of drones", "title": "Number of drones",
...@@ -366,18 +407,6 @@ ...@@ -366,18 +407,6 @@
"key": "number_of_drones", "key": "number_of_drones",
"hidden": 0, "hidden": 0,
"type": "IntegerField" "type": "IntegerField"
},
"my_script": {
"default": DEFAULT_SCRIPT_CONTENT,
"css_class": "",
"required": 1,
"editable": 1,
"key": "script",
"hidden": 0,
"type": "GadgetField",
"renderjs_extra": '{"editor": "codemirror", "maximize": true}',
"url": "gadget_editor.html",
"sandbox": "public"
} }
}}, }},
"_links": { "_links": {
...@@ -389,22 +418,57 @@ ...@@ -389,22 +418,57 @@
form_definition: { form_definition: {
group_list: [[ group_list: [[
"left", "left",
[["my_simulation_speed"], ["my_simulation_time"], ["my_number_of_drones"], [["my_simulation_speed"], ["my_simulation_time"],
/*["my_map_size"], */["my_map_height"],// ["my_flag_weight"], ["my_number_of_drones"], ["my_map_seed"]]
["my_start_AMSL"], ["my_map_seed"]]
], [ ], [
"right", "right",
[["my_drone_min_speed"], ["my_drone_speed"], ["my_drone_max_speed"], [["my_drone_min_speed"], ["my_drone_speed"], ["my_drone_max_speed"],
["my_drone_max_acceleration"], ["my_drone_max_deceleration"], ["my_drone_max_acceleration"], ["my_drone_max_deceleration"],
["my_drone_max_roll"], ["my_drone_min_pitch"], ["my_drone_max_pitch"], ["my_drone_max_roll"], ["my_drone_min_pitch"], ["my_drone_max_pitch"],
["my_drone_max_sink_rate"], ["my_drone_max_climb_rate"]] ["my_drone_max_sink_rate"], ["my_drone_max_climb_rate"]]
], [
"bottom",
[["my_script"]]
]] ]]
} }
}); });
}) })
.push(function () {
return gadget.getDeclaredGadget("operator-editor");
})
.push(function (operator_editor) {
var operator_map = {}, DEFAULT_OPERATOR_SCRIPT_CONTENT;
Object.assign(operator_map, JSON_MAP);
delete operator_map.flag_list;
delete operator_map.obstacle_list;
delete operator_map.enemy_list;
delete operator_map.geo_obstacle_list;
delete operator_map.flag_distance_epsilon;
DEFAULT_OPERATOR_SCRIPT_CONTENT = 'var json_map = ' +
JSON.stringify(operator_map) + ';\n' +
'\n' +
'return {"flag_positions": json_map.geo_flag_list};\n';
return operator_editor.render({
"editor": "codemirror",
"maximize": true,
"portal_type": "Web Script",
"key": "operator_editor",
"value": DEFAULT_OPERATOR_SCRIPT_CONTENT,
"editable": 1,
"hidden": 0
});
})
.push(function () {
return gadget.getDeclaredGadget("script-editor");
})
.push(function (script_editor) {
return script_editor.render({
"editor": "codemirror",
"maximize": true,
"portal_type": "Web Script",
"key": "script_editor",
"value": DEFAULT_SCRIPT_CONTENT,
"editable": 1,
"hidden": 0
});
})
.push(function () { .push(function () {
return gadget.updateHeader({ return gadget.updateHeader({
page_title: 'Drone Capture Flag', page_title: 'Drone Capture Flag',
...@@ -413,11 +477,27 @@ ...@@ -413,11 +477,27 @@
}); });
}) })
.onStateChange(function (modification_dict) {
if (modification_dict.hasOwnProperty('operator_script')) {
return this.getDeclaredGadget('operator-editor')
.push(function (operator_editor) {
return operator_editor.render({
"editor": "codemirror",
"maximize": true,
"portal_type": "Web Script",
"key": "operator_editor",
"value": modification_dict.operator_script,
"editable": 1,
"hidden": 0
});
});
}
})
.declareJob('runGame', function runGame(options) { .declareJob('runGame', function runGame(options) {
var gadget = this, i, var gadget = this, i,
fragment = gadget.element.querySelector('.simulator_div'), fragment = gadget.element.querySelector('.simulator_div'),
game_parameters_json, map_json; game_parameters_json, map_json;
options.map_size = MAP_SIZE;
DRONE_LIST = []; DRONE_LIST = [];
fragment = domsugar(gadget.element.querySelector('.simulator_div'), fragment = domsugar(gadget.element.querySelector('.simulator_div'),
[domsugar('div')]).firstElementChild; [domsugar('div')]).firstElementChild;
...@@ -425,114 +505,6 @@ ...@@ -425,114 +505,6 @@
DRONE_LIST[i] = {"id": i, "type": "FixedWingDroneAPI", DRONE_LIST[i] = {"id": i, "type": "FixedWingDroneAPI",
"script_content": options.script}; "script_content": options.script};
} }
function randomizeMap(json_map) {
function randomIntFromInterval(min, max, random_seed) {
return Math.floor(random_seed.quick() * (max - min + 1) + min);
}
function randomPosition(random_seed, map_size) {
var sign_x = random_seed.quick() < 0.5 ? -1 : 1,
sign_y = random_seed.quick() < 0.5 ? -1 : 1,
pos_x = sign_x * random_seed.quick() * map_size / 2,
pos_y = sign_y * random_seed.quick() * map_size / 2;
return [pos_x, pos_y];
}
var seed_value = options.map_seed,
random_seed = new Math.seedrandom(seed_value), i,
n_enemies = randomIntFromInterval(5, 10, random_seed),
n_flags = randomIntFromInterval(5, 10, random_seed),
n_obstacles = randomIntFromInterval(5, 15, random_seed),
flag_list = [], obstacle_list = [], enemy_list = [], random_position,
obstacles_types = ["box"/*, "sphere"*/, "cylinder"], type,
obstacle_limit = [options.map_size / 6, options.map_size / 100,
options.map_size / 6, 30];
//enemies
for (i = 0; i < n_enemies; i += 1) {
random_position = randomPosition(random_seed, options.map_size);
enemy_list.push({
"id": i + parseInt(options.number_of_drones),
"type": "EnemyDroneAPI",
"position": {
"x": random_position[0],
"y": random_position[1],
"z": 15 //TODO random z?
}
});
}
//flags
for (i = 0; i < n_flags; i += 1) {
//avoid flags near the limits
random_position = randomPosition(random_seed, options.map_size * 0.75);
flag_list.push({
"position": {
"x": random_position[0],
"y": random_position[1],
"z": 10
}
});
}
function checkDistance(position, position_list) {
function distance(a, b) {
return Math.sqrt((a.x - b.x) ** 2 + (a.y - b.y) ** 2);
}
var el;
for (el = 0; el < position_list.length; el += 1) {
if (distance(position, position_list[el].position) < options.map_size / 6) {
return true;
}
}
return false;
}
//obstacles
for (i = 0; i < n_obstacles; i += 1) {
random_position = randomPosition(random_seed, options.map_size);
if (checkDistance({ 'x': random_position[0],
'y': random_position[1]}, flag_list)) {
i -= 1;
} else {
type = randomIntFromInterval(0, 2, random_seed);
obstacle_list.push({
"type": obstacles_types[type],
"position": {
"x": random_position[0],
"y": random_position[1],
"z": 15 //TODO random z?
},
"scale": {
"x": randomIntFromInterval(20, obstacle_limit[type], random_seed),
"y": randomIntFromInterval(20, obstacle_limit[type], random_seed),
"z": randomIntFromInterval(5, obstacle_limit[3], random_seed)
},
"rotation": {
"x": 0,
"y": 0,
"z": 0
}
});
}
}
json_map.obstacle_list = obstacle_list;
json_map.drones.enemy = enemy_list;
json_map.flag_list = flag_list;
return json_map;
}
map_json = {
"map_size": parseFloat(options.map_size),
"height": parseInt(options.map_height, 10),
"start_AMSL": parseFloat(options.start_AMSL),
"min_lat": parseFloat(min_lat),
"max_lat": parseFloat(max_lat),
"min_lon": parseFloat(min_lon),
"max_lon": parseFloat(max_lon),
"flag_list": [],
"obstacle_list" : [],
"drones": {
"user": DRONE_LIST,
"enemy": []
}
};
game_parameters_json = { game_parameters_json = {
"drone": { "drone": {
"maxAcceleration": parseInt(options.drone_max_acceleration, 10), "maxAcceleration": parseInt(options.drone_max_acceleration, 10),
...@@ -544,7 +516,8 @@ ...@@ -544,7 +516,8 @@
"minPitchAngle": parseFloat(options.drone_min_pitch), "minPitchAngle": parseFloat(options.drone_min_pitch),
"maxPitchAngle": parseFloat(options.drone_max_pitch), "maxPitchAngle": parseFloat(options.drone_max_pitch),
"maxSinkRate": parseFloat(options.drone_max_sink_rate), "maxSinkRate": parseFloat(options.drone_max_sink_rate),
"maxClimbRate": parseFloat(options.drone_max_climb_rate) "maxClimbRate": parseFloat(options.drone_max_climb_rate),
"list": DRONE_LIST
}, },
"gameTime": parseInt(options.simulation_time, 10), "gameTime": parseInt(options.simulation_time, 10),
"simulation_speed": parseInt(options.simulation_speed, 10), "simulation_speed": parseInt(options.simulation_speed, 10),
...@@ -552,7 +525,8 @@ ...@@ -552,7 +525,8 @@
"information": 0, "information": 0,
"communication": 0 "communication": 0
}, },
"map": randomizeMap(map_json), "map": JSON_MAP || MAP,
"operator_init_msg": options.operator_init_msg,
"draw_flight_path": DRAW, "draw_flight_path": DRAW,
"temp_flight_path": true, "temp_flight_path": true,
"log_drone_flight": LOG, "log_drone_flight": LOG,
...@@ -604,9 +578,12 @@ ...@@ -604,9 +578,12 @@
return form_gadget.getContent(); return form_gadget.getContent();
}) })
.push(function (result) { .push(function (result) {
var a, blob, div, key, log, log_content, aux; var a, blob, div, key, log, log_content, aux, label;
i = 0; i = 0;
div = domsugar('div', { text: result.message }); div = domsugar('div', { text: result.message });
label = domsugar('label', { text: "Results" });
label.classList.add("item-label");
document.querySelector('.container').parentNode.appendChild(label);
document.querySelector('.container').parentNode.appendChild(div); document.querySelector('.container').parentNode.appendChild(div);
for (key in result.content) { for (key in result.content) {
if (result.content.hasOwnProperty(key)) { if (result.content.hasOwnProperty(key)) {
...@@ -650,4 +627,4 @@ ...@@ -650,4 +627,4 @@
}); });
}); });
}(window, rJS, domsugar, document, URLSearchParams, Blob)); }(window, rJS, domsugar, document, URLSearchParams, Blob, require));
\ No newline at end of file \ No newline at end of file
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1010.23654.50890.20360</string> </value> <value> <string>1010.62683.28686.10205</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1691681704.91</float> <float>1694023525.57</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -277,7 +277,7 @@ ...@@ -277,7 +277,7 @@
</item> </item>
<item> <item>
<key> <string>configuration_content_security_policy</string> </key> <key> <string>configuration_content_security_policy</string> </key>
<value> <string>default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; connect-src \'self\' https://content.dropboxapi.com https://api.dropboxapi.com mail.tiolive.com data: *.host.vifib.net *.node.vifib.com *.erp5.net *.nexedi.net https://netdna.bootstrapcdn.com; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\'; font-src \'self\' netdna.bootstrapcdn.com; style-src \'self\' netdna.bootstrapcdn.com \'unsafe-inline\' data:; frame-src \'self\' data:</string> </value> <value> <string>default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; script-src \'self\' \'unsafe-eval\';</string> </value>
</item> </item>
<item> <item>
<key> <string>configuration_latest_document_version</string> </key> <key> <string>configuration_latest_document_version</string> </key>
...@@ -538,7 +538,7 @@ ...@@ -538,7 +538,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1007.63243.40091.31010</string> </value> <value> <string>1010.35278.59853.35635</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -558,7 +558,7 @@ ...@@ -558,7 +558,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1682433351.46</float> <float>1692976685.9</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>configuration_content_security_policy</string> </key> <key> <string>configuration_content_security_policy</string> </key>
<value> <string>default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; connect-src \'self\' https://content.dropboxapi.com https://api.dropboxapi.com mail.tiolive.com data: *.host.vifib.net *.node.vifib.com *.erp5.net *.nexedi.net https://netdna.bootstrapcdn.com; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\'; font-src \'self\' netdna.bootstrapcdn.com; style-src \'self\' netdna.bootstrapcdn.com \'unsafe-inline\' data:; frame-src \'self\' data:</string> </value> <value> <string>default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; script-src \'self\' \'unsafe-eval\';</string> </value>
</item> </item>
<item> <item>
<key> <string>configuration_default_view_action_reference</string> </key> <key> <string>configuration_default_view_action_reference</string> </key>
...@@ -502,7 +502,7 @@ WebSection_getDroneCaptureFlagPrecacheManifestList</string> </value> ...@@ -502,7 +502,7 @@ WebSection_getDroneCaptureFlagPrecacheManifestList</string> </value>
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1007.63247.30934.52258</string> </value> <value> <string>1010.35278.59853.35635</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -522,7 +522,7 @@ WebSection_getDroneCaptureFlagPrecacheManifestList</string> </value> ...@@ -522,7 +522,7 @@ WebSection_getDroneCaptureFlagPrecacheManifestList</string> </value>
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1682433685.5</float> <float>1692976699.18</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
/** vim: et:ts=4:sw=4:sts=4
* @license RequireJS 2.3.6 Copyright jQuery Foundation and other contributors.
* Released under MIT license, https://github.com/requirejs/requirejs/blob/master/LICENSE
*/
var requirejs,require,define;!function(global,setTimeout){var req,s,head,baseElement,dataMain,src,interactiveScript,currentlyAddingScript,mainScript,subPath,version="2.3.6",commentRegExp=/\/\*[\s\S]*?\*\/|([^:"'=]|^)\/\/.*$/gm,cjsRequireRegExp=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,jsSuffixRegExp=/\.js$/,currDirRegExp=/^\.\//,op=Object.prototype,ostring=op.toString,hasOwn=op.hasOwnProperty,isBrowser=!("undefined"==typeof window||"undefined"==typeof navigator||!window.document),isWebWorker=!isBrowser&&"undefined"!=typeof importScripts,readyRegExp=isBrowser&&"PLAYSTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/,defContextName="_",isOpera="undefined"!=typeof opera&&"[object Opera]"===opera.toString(),contexts={},cfg={},globalDefQueue=[],useInteractive=!1;function commentReplace(e,t){return t||""}function isFunction(e){return"[object Function]"===ostring.call(e)}function isArray(e){return"[object Array]"===ostring.call(e)}function each(e,t){var i;if(e)for(i=0;i<e.length&&(!e[i]||!t(e[i],i,e));i+=1);}function eachReverse(e,t){var i;if(e)for(i=e.length-1;-1<i&&(!e[i]||!t(e[i],i,e));i-=1);}function hasProp(e,t){return hasOwn.call(e,t)}function getOwn(e,t){return hasProp(e,t)&&e[t]}function eachProp(e,t){var i;for(i in e)if(hasProp(e,i)&&t(e[i],i))break}function mixin(i,e,r,n){return e&&eachProp(e,function(e,t){!r&&hasProp(i,t)||(!n||"object"!=typeof e||!e||isArray(e)||isFunction(e)||e instanceof RegExp?i[t]=e:(i[t]||(i[t]={}),mixin(i[t],e,r,n)))}),i}function bind(e,t){return function(){return t.apply(e,arguments)}}function scripts(){return document.getElementsByTagName("script")}function defaultOnError(e){throw e}function getGlobal(e){if(!e)return e;var t=global;return each(e.split("."),function(e){t=t[e]}),t}function makeError(e,t,i,r){var n=new Error(t+"\nhttps://requirejs.org/docs/errors.html#"+e);return n.requireType=e,n.requireModules=r,i&&(n.originalError=i),n}if(void 0===define){if(void 0!==requirejs){if(isFunction(requirejs))return;cfg=requirejs,requirejs=void 0}void 0===require||isFunction(require)||(cfg=require,require=void 0),req=requirejs=function(e,t,i,r){var n,o,a=defContextName;return isArray(e)||"string"==typeof e||(o=e,isArray(t)?(e=t,t=i,i=r):e=[]),o&&o.context&&(a=o.context),(n=getOwn(contexts,a))||(n=contexts[a]=req.s.newContext(a)),o&&n.configure(o),n.require(e,t,i)},req.config=function(e){return req(e)},req.nextTick=void 0!==setTimeout?function(e){setTimeout(e,4)}:function(e){e()},require||(require=req),req.version=version,req.jsExtRegExp=/^\/|:|\?|\.js$/,req.isBrowser=isBrowser,s=req.s={contexts:contexts,newContext:newContext},req({}),each(["toUrl","undef","defined","specified"],function(t){req[t]=function(){var e=contexts[defContextName];return e.require[t].apply(e,arguments)}}),isBrowser&&(head=s.head=document.getElementsByTagName("head")[0],baseElement=document.getElementsByTagName("base")[0],baseElement&&(head=s.head=baseElement.parentNode)),req.onError=defaultOnError,req.createNode=function(e,t,i){var r=e.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script");return r.type=e.scriptType||"text/javascript",r.charset="utf-8",r.async=!0,r},req.load=function(t,i,r){var e,n=t&&t.config||{};if(isBrowser)return(e=req.createNode(n,i,r)).setAttribute("data-requirecontext",t.contextName),e.setAttribute("data-requiremodule",i),!e.attachEvent||e.attachEvent.toString&&e.attachEvent.toString().indexOf("[native code")<0||isOpera?(e.addEventListener("load",t.onScriptLoad,!1),e.addEventListener("error",t.onScriptError,!1)):(useInteractive=!0,e.attachEvent("onreadystatechange",t.onScriptLoad)),e.src=r,n.onNodeCreated&&n.onNodeCreated(e,n,i,r),currentlyAddingScript=e,baseElement?head.insertBefore(e,baseElement):head.appendChild(e),currentlyAddingScript=null,e;if(isWebWorker)try{setTimeout(function(){},0),importScripts(r),t.completeLoad(i)}catch(e){t.onError(makeError("importscripts","importScripts failed for "+i+" at "+r,e,[i]))}},isBrowser&&!cfg.skipDataMain&&eachReverse(scripts(),function(e){if(head||(head=e.parentNode),dataMain=e.getAttribute("data-main"))return mainScript=dataMain,cfg.baseUrl||-1!==mainScript.indexOf("!")||(mainScript=(src=mainScript.split("/")).pop(),subPath=src.length?src.join("/")+"/":"./",cfg.baseUrl=subPath),mainScript=mainScript.replace(jsSuffixRegExp,""),req.jsExtRegExp.test(mainScript)&&(mainScript=dataMain),cfg.deps=cfg.deps?cfg.deps.concat(mainScript):[mainScript],!0}),define=function(e,i,t){var r,n;"string"!=typeof e&&(t=i,i=e,e=null),isArray(i)||(t=i,i=null),!i&&isFunction(t)&&(i=[],t.length&&(t.toString().replace(commentRegExp,commentReplace).replace(cjsRequireRegExp,function(e,t){i.push(t)}),i=(1===t.length?["require"]:["require","exports","module"]).concat(i))),useInteractive&&(r=currentlyAddingScript||getInteractiveScript())&&(e||(e=r.getAttribute("data-requiremodule")),n=contexts[r.getAttribute("data-requirecontext")]),n?(n.defQueue.push([e,i,t]),n.defQueueMap[e]=!0):globalDefQueue.push([e,i,t])},define.amd={jQuery:!0},req.exec=function(text){return eval(text)},req(cfg)}function newContext(u){var i,e,l,c,d,g={waitSeconds:7,baseUrl:"./",paths:{},bundles:{},pkgs:{},shim:{},config:{}},p={},f={},r={},h=[],m={},n={},v={},x=1,b=1;function q(e,t,i){var r,n,o,a,s,u,c,d,p,f,l=t&&t.split("/"),h=g.map,m=h&&h["*"];if(e&&(u=(e=e.split("/")).length-1,g.nodeIdCompat&&jsSuffixRegExp.test(e[u])&&(e[u]=e[u].replace(jsSuffixRegExp,"")),"."===e[0].charAt(0)&&l&&(e=l.slice(0,l.length-1).concat(e)),function(e){var t,i;for(t=0;t<e.length;t++)if("."===(i=e[t]))e.splice(t,1),t-=1;else if(".."===i){if(0===t||1===t&&".."===e[2]||".."===e[t-1])continue;0<t&&(e.splice(t-1,2),t-=2)}}(e),e=e.join("/")),i&&h&&(l||m)){e:for(o=(n=e.split("/")).length;0<o;o-=1){if(s=n.slice(0,o).join("/"),l)for(a=l.length;0<a;a-=1)if((r=getOwn(h,l.slice(0,a).join("/")))&&(r=getOwn(r,s))){c=r,d=o;break e}!p&&m&&getOwn(m,s)&&(p=getOwn(m,s),f=o)}!c&&p&&(c=p,d=f),c&&(n.splice(0,d,c),e=n.join("/"))}return getOwn(g.pkgs,e)||e}function E(t){isBrowser&&each(scripts(),function(e){if(e.getAttribute("data-requiremodule")===t&&e.getAttribute("data-requirecontext")===l.contextName)return e.parentNode.removeChild(e),!0})}function w(e){var t=getOwn(g.paths,e);if(t&&isArray(t)&&1<t.length)return t.shift(),l.require.undef(e),l.makeRequire(null,{skipMap:!0})([e]),!0}function y(e){var t,i=e?e.indexOf("!"):-1;return-1<i&&(t=e.substring(0,i),e=e.substring(i+1,e.length)),[t,e]}function S(e,t,i,r){var n,o,a,s,u=null,c=t?t.name:null,d=e,p=!0,f="";return e||(p=!1,e="_@r"+(x+=1)),u=(s=y(e))[0],e=s[1],u&&(u=q(u,c,r),o=getOwn(m,u)),e&&(u?f=i?e:o&&o.normalize?o.normalize(e,function(e){return q(e,c,r)}):-1===e.indexOf("!")?q(e,c,r):e:(u=(s=y(f=q(e,c,r)))[0],f=s[1],i=!0,n=l.nameToUrl(f))),{prefix:u,name:f,parentMap:t,unnormalized:!!(a=!u||o||i?"":"_unnormalized"+(b+=1)),url:n,originalName:d,isDefine:p,id:(u?u+"!"+f:f)+a}}function k(e){var t=e.id,i=getOwn(p,t);return i||(i=p[t]=new l.Module(e)),i}function M(e,t,i){var r=e.id,n=getOwn(p,r);!hasProp(m,r)||n&&!n.defineEmitComplete?(n=k(e)).error&&"error"===t?i(n.error):n.on(t,i):"defined"===t&&i(m[r])}function O(i,e){var t=i.requireModules,r=!1;e?e(i):(each(t,function(e){var t=getOwn(p,e);t&&(t.error=i,t.events.error&&(r=!0,t.emit("error",i)))}),r||req.onError(i))}function j(){globalDefQueue.length&&(each(globalDefQueue,function(e){var t=e[0];"string"==typeof t&&(l.defQueueMap[t]=!0),h.push(e)}),globalDefQueue=[])}function P(e){delete p[e],delete f[e]}function R(){var e,r,t=1e3*g.waitSeconds,n=t&&l.startTime+t<(new Date).getTime(),o=[],a=[],s=!1,u=!0;if(!i){if(i=!0,eachProp(f,function(e){var t=e.map,i=t.id;if(e.enabled&&(t.isDefine||a.push(e),!e.error))if(!e.inited&&n)w(i)?s=r=!0:(o.push(i),E(i));else if(!e.inited&&e.fetched&&t.isDefine&&(s=!0,!t.prefix))return u=!1}),n&&o.length)return(e=makeError("timeout","Load timeout for modules: "+o,null,o)).contextName=l.contextName,O(e);u&&each(a,function(e){!function n(o,a,s){var e=o.map.id;o.error?o.emit("error",o.error):(a[e]=!0,each(o.depMaps,function(e,t){var i=e.id,r=getOwn(p,i);!r||o.depMatched[t]||s[i]||(getOwn(a,i)?(o.defineDep(t,m[i]),o.check()):n(r,a,s))}),s[e]=!0)}(e,{},{})}),n&&!r||!s||!isBrowser&&!isWebWorker||d||(d=setTimeout(function(){d=0,R()},50)),i=!1}}function a(e){hasProp(m,e[0])||k(S(e[0],null,!0)).init(e[1],e[2])}function o(e,t,i,r){e.detachEvent&&!isOpera?r&&e.detachEvent(r,t):e.removeEventListener(i,t,!1)}function s(e){var t=e.currentTarget||e.srcElement;return o(t,l.onScriptLoad,"load","onreadystatechange"),o(t,l.onScriptError,"error"),{node:t,id:t&&t.getAttribute("data-requiremodule")}}function T(){var e;for(j();h.length;){if(null===(e=h.shift())[0])return O(makeError("mismatch","Mismatched anonymous define() module: "+e[e.length-1]));a(e)}l.defQueueMap={}}return c={require:function(e){return e.require?e.require:e.require=l.makeRequire(e.map)},exports:function(e){if(e.usingExports=!0,e.map.isDefine)return e.exports?m[e.map.id]=e.exports:e.exports=m[e.map.id]={}},module:function(e){return e.module?e.module:e.module={id:e.map.id,uri:e.map.url,config:function(){return getOwn(g.config,e.map.id)||{}},exports:e.exports||(e.exports={})}}},(e=function(e){this.events=getOwn(r,e.id)||{},this.map=e,this.shim=getOwn(g.shim,e.id),this.depExports=[],this.depMaps=[],this.depMatched=[],this.pluginMaps={},this.depCount=0}).prototype={init:function(e,t,i,r){r=r||{},this.inited||(this.factory=t,i?this.on("error",i):this.events.error&&(i=bind(this,function(e){this.emit("error",e)})),this.depMaps=e&&e.slice(0),this.errback=i,this.inited=!0,this.ignore=r.ignore,r.enabled||this.enabled?this.enable():this.check())},defineDep:function(e,t){this.depMatched[e]||(this.depMatched[e]=!0,this.depCount-=1,this.depExports[e]=t)},fetch:function(){if(!this.fetched){this.fetched=!0,l.startTime=(new Date).getTime();var e=this.map;if(!this.shim)return e.prefix?this.callPlugin():this.load();l.makeRequire(this.map,{enableBuildCallback:!0})(this.shim.deps||[],bind(this,function(){return e.prefix?this.callPlugin():this.load()}))}},load:function(){var e=this.map.url;n[e]||(n[e]=!0,l.load(this.map.id,e))},check:function(){if(this.enabled&&!this.enabling){var t,e,i=this.map.id,r=this.depExports,n=this.exports,o=this.factory;if(this.inited){if(this.error)this.emit("error",this.error);else if(!this.defining){if(this.defining=!0,this.depCount<1&&!this.defined){if(isFunction(o)){if(this.events.error&&this.map.isDefine||req.onError!==defaultOnError)try{n=l.execCb(i,o,r,n)}catch(e){t=e}else n=l.execCb(i,o,r,n);if(this.map.isDefine&&void 0===n&&((e=this.module)?n=e.exports:this.usingExports&&(n=this.exports)),t)return t.requireMap=this.map,t.requireModules=this.map.isDefine?[this.map.id]:null,t.requireType=this.map.isDefine?"define":"require",O(this.error=t)}else n=o;if(this.exports=n,this.map.isDefine&&!this.ignore&&(m[i]=n,req.onResourceLoad)){var a=[];each(this.depMaps,function(e){a.push(e.normalizedMap||e)}),req.onResourceLoad(l,this.map,a)}P(i),this.defined=!0}this.defining=!1,this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else hasProp(l.defQueueMap,i)||this.fetch()}},callPlugin:function(){var u=this.map,c=u.id,e=S(u.prefix);this.depMaps.push(e),M(e,"defined",bind(this,function(e){var o,t,i,r=getOwn(v,this.map.id),n=this.map.name,a=this.map.parentMap?this.map.parentMap.name:null,s=l.makeRequire(u.parentMap,{enableBuildCallback:!0});return this.map.unnormalized?(e.normalize&&(n=e.normalize(n,function(e){return q(e,a,!0)})||""),M(t=S(u.prefix+"!"+n,this.map.parentMap,!0),"defined",bind(this,function(e){this.map.normalizedMap=t,this.init([],function(){return e},null,{enabled:!0,ignore:!0})})),void((i=getOwn(p,t.id))&&(this.depMaps.push(t),this.events.error&&i.on("error",bind(this,function(e){this.emit("error",e)})),i.enable()))):r?(this.map.url=l.nameToUrl(r),void this.load()):((o=bind(this,function(e){this.init([],function(){return e},null,{enabled:!0})})).error=bind(this,function(e){this.inited=!0,(this.error=e).requireModules=[c],eachProp(p,function(e){0===e.map.id.indexOf(c+"_unnormalized")&&P(e.map.id)}),O(e)}),o.fromText=bind(this,function(e,t){var i=u.name,r=S(i),n=useInteractive;t&&(e=t),n&&(useInteractive=!1),k(r),hasProp(g.config,c)&&(g.config[i]=g.config[c]);try{req.exec(e)}catch(e){return O(makeError("fromtexteval","fromText eval for "+c+" failed: "+e,e,[c]))}n&&(useInteractive=!0),this.depMaps.push(r),l.completeLoad(i),s([i],o)}),void e.load(u.name,s,o,g))})),l.enable(e,this),this.pluginMaps[e.id]=e},enable:function(){(f[this.map.id]=this).enabled=!0,this.enabling=!0,each(this.depMaps,bind(this,function(e,t){var i,r,n;if("string"==typeof e){if(e=S(e,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap),this.depMaps[t]=e,n=getOwn(c,e.id))return void(this.depExports[t]=n(this));this.depCount+=1,M(e,"defined",bind(this,function(e){this.undefed||(this.defineDep(t,e),this.check())})),this.errback?M(e,"error",bind(this,this.errback)):this.events.error&&M(e,"error",bind(this,function(e){this.emit("error",e)}))}i=e.id,r=p[i],hasProp(c,i)||!r||r.enabled||l.enable(e,this)})),eachProp(this.pluginMaps,bind(this,function(e){var t=getOwn(p,e.id);t&&!t.enabled&&l.enable(e,this)})),this.enabling=!1,this.check()},on:function(e,t){var i=this.events[e];i||(i=this.events[e]=[]),i.push(t)},emit:function(e,t){each(this.events[e],function(e){e(t)}),"error"===e&&delete this.events[e]}},(l={config:g,contextName:u,registry:p,defined:m,urlFetched:n,defQueue:h,defQueueMap:{},Module:e,makeModuleMap:S,nextTick:req.nextTick,onError:O,configure:function(e){if(e.baseUrl&&"/"!==e.baseUrl.charAt(e.baseUrl.length-1)&&(e.baseUrl+="/"),"string"==typeof e.urlArgs){var i=e.urlArgs;e.urlArgs=function(e,t){return(-1===t.indexOf("?")?"?":"&")+i}}var r=g.shim,n={paths:!0,bundles:!0,config:!0,map:!0};eachProp(e,function(e,t){n[t]?(g[t]||(g[t]={}),mixin(g[t],e,!0,!0)):g[t]=e}),e.bundles&&eachProp(e.bundles,function(e,t){each(e,function(e){e!==t&&(v[e]=t)})}),e.shim&&(eachProp(e.shim,function(e,t){isArray(e)&&(e={deps:e}),!e.exports&&!e.init||e.exportsFn||(e.exportsFn=l.makeShimExports(e)),r[t]=e}),g.shim=r),e.packages&&each(e.packages,function(e){var t;t=(e="string"==typeof e?{name:e}:e).name,e.location&&(g.paths[t]=e.location),g.pkgs[t]=e.name+"/"+(e.main||"main").replace(currDirRegExp,"").replace(jsSuffixRegExp,"")}),eachProp(p,function(e,t){e.inited||e.map.unnormalized||(e.map=S(t,null,!0))}),(e.deps||e.callback)&&l.require(e.deps||[],e.callback)},makeShimExports:function(t){return function(){var e;return t.init&&(e=t.init.apply(global,arguments)),e||t.exports&&getGlobal(t.exports)}},makeRequire:function(o,a){function s(e,t,i){var r,n;return a.enableBuildCallback&&t&&isFunction(t)&&(t.__requireJsBuild=!0),"string"==typeof e?isFunction(t)?O(makeError("requireargs","Invalid require call"),i):o&&hasProp(c,e)?c[e](p[o.id]):req.get?req.get(l,e,o,s):(r=S(e,o,!1,!0).id,hasProp(m,r)?m[r]:O(makeError("notloaded",'Module name "'+r+'" has not been loaded yet for context: '+u+(o?"":". Use require([])")))):(T(),l.nextTick(function(){T(),(n=k(S(null,o))).skipMap=a.skipMap,n.init(e,t,i,{enabled:!0}),R()}),s)}return a=a||{},mixin(s,{isBrowser:isBrowser,toUrl:function(e){var t,i=e.lastIndexOf("."),r=e.split("/")[0];return-1!==i&&(!("."===r||".."===r)||1<i)&&(t=e.substring(i,e.length),e=e.substring(0,i)),l.nameToUrl(q(e,o&&o.id,!0),t,!0)},defined:function(e){return hasProp(m,S(e,o,!1,!0).id)},specified:function(e){return e=S(e,o,!1,!0).id,hasProp(m,e)||hasProp(p,e)}}),o||(s.undef=function(i){j();var e=S(i,o,!0),t=getOwn(p,i);t.undefed=!0,E(i),delete m[i],delete n[e.url],delete r[i],eachReverse(h,function(e,t){e[0]===i&&h.splice(t,1)}),delete l.defQueueMap[i],t&&(t.events.defined&&(r[i]=t.events),P(i))}),s},enable:function(e){getOwn(p,e.id)&&k(e).enable()},completeLoad:function(e){var t,i,r,n=getOwn(g.shim,e)||{},o=n.exports;for(j();h.length;){if(null===(i=h.shift())[0]){if(i[0]=e,t)break;t=!0}else i[0]===e&&(t=!0);a(i)}if(l.defQueueMap={},r=getOwn(p,e),!t&&!hasProp(m,e)&&r&&!r.inited){if(!(!g.enforceDefine||o&&getGlobal(o)))return w(e)?void 0:O(makeError("nodefine","No define call for "+e,null,[e]));a([e,n.deps||[],n.exportsFn])}R()},nameToUrl:function(e,t,i){var r,n,o,a,s,u,c=getOwn(g.pkgs,e);if(c&&(e=c),u=getOwn(v,e))return l.nameToUrl(u,t,i);if(req.jsExtRegExp.test(e))a=e+(t||"");else{for(r=g.paths,o=(n=e.split("/")).length;0<o;o-=1)if(s=getOwn(r,n.slice(0,o).join("/"))){isArray(s)&&(s=s[0]),n.splice(0,o,s);break}a=n.join("/"),a=("/"===(a+=t||(/^data\:|^blob\:|\?/.test(a)||i?"":".js")).charAt(0)||a.match(/^[\w\+\.\-]+:/)?"":g.baseUrl)+a}return g.urlArgs&&!/^blob\:/.test(a)?a+g.urlArgs(e,a):a},load:function(e,t){req.load(l,e,t)},execCb:function(e,t,i,r){return t.apply(r,i)},onScriptLoad:function(e){if("load"===e.type||readyRegExp.test((e.currentTarget||e.srcElement).readyState)){interactiveScript=null;var t=s(e);l.completeLoad(t.id)}},onScriptError:function(e){var i=s(e);if(!w(i.id)){var r=[];return eachProp(p,function(e,t){0!==t.indexOf("_@r")&&each(e.depMaps,function(e){if(e.id===i.id)return r.push(t),!0})}),O(makeError("scripterror",'Script error for "'+i.id+(r.length?'", needed by: '+r.join(", "):'"'),e,[i.id]))}}}).require=l.makeRequire(),l}function getInteractiveScript(){return interactiveScript&&"interactive"===interactiveScript.readyState||eachReverse(scripts(),function(e){if("interactive"===e.readyState)return interactiveScript=e}),interactiveScript}}(this,"undefined"==typeof setTimeout?void 0:setTimeout);
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>__name__</string> </key>
<value> <string>require.js</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/javascript</string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment