Best JavaScript code snippet using mocha
parse-xviz-message-sync.spec.js
Source:parse-xviz-message-sync.spec.js
1// Copyright (c) 2019 Uber Technologies, Inc.2//3// Licensed under the Apache License, Version 2.0 (the "License");4// you may not use this file except in compliance with the License.5// You may obtain a copy of the License at6//7// http://www.apache.org/licenses/LICENSE-2.08//9// Unless required by applicable law or agreed to in writing, software10// distributed under the License is distributed on an "AS IS" BASIS,11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12// See the License for the specific language governing permissions and13// limitations under the License.14/* eslint-disable max-statements */15import {16 setXVIZConfig,17 getXVIZConfig,18 parseXVIZMessageSync,19 isEnvelope,20 isXVIZMessage,21 getXVIZMessageType,22 getDataFormat,23 unpackEnvelope,24 parseXVIZData,25 XVIZ_MESSAGE_TYPE26} from '@xviz/parser';27import {XVIZValidator} from '@xviz/schema';28import tape from 'tape-catch';29import clone from 'clone';30import TestMetadataMessageV2 from 'test-data/sample-metadata-message';31import TestMetadataMessageV1 from 'test-data/sample-metadata-message-v1';32import TestFuturesMessageV1 from 'test-data/sample-frame-futures-v1';33import MinimalBinaryMetadata from 'test-data/minimal-metadata';34import MinimalBinaryStateUpdate from 'test-data/minimal-state-update';35import {resetXVIZConfigAndSettings} from '../config/config-utils';36import {TextEncoder} from '@xviz/parser/utils/text-encoding';37const schemaValidator = new XVIZValidator();38// xviz data uses snake_case39/* eslint-disable camelcase */40// Metadata missing normal start_time and end_time41// but with the full log timing fields42const metadataWithLogStartEnd = {43 version: '2.0.0',44 log_info: {45 log_start_time: 1194278450.6,46 log_end_time: 1194278451.647 },48 streams: {},49 videos: {},50 map_info: {51 map: {52 name: 'phx',53 entry_point: '6b9d0916d69943c9d88d2703e72021f5'54 }55 }56};57// TODO replace with second message in stream58// NOTE: the timestamp in 'primtives' is not required to match that of 'vehicle_pose'59const TestTimesliceMessageV1 = {60 timestamp: 1001.1,61 state_updates: [62 {63 variables: null,64 primitives: {65 '/test/stream': [66 {67 color: [255, 255, 255],68 id: 1234,69 radius: 0.01,70 type: 'points3d',71 vertices: [[1000, 1000, 200]]72 }73 ]74 }75 }76 ],77 vehicle_pose: {78 continuous: {},79 map_relative: {80 map_index: 'should-be-a-guid'81 },82 time: 1001.283 }84};85const TestTimesliceMessageV2 = {86 update_type: 'COMPLETE_STATE',87 updates: [88 {89 timestamp: 1001.0,90 poses: {91 '/vehicle_pose': {92 timestamp: 1001.0,93 map_origin: {longitude: 11.2, latitude: 33.4, altitude: 55.6},94 position: [1.1, 2.2, 3.3],95 orientation: [0.1, 0.2, 0.3]96 }97 },98 variables: {},99 primitives: {100 '/test/stream': {101 points: [102 {103 base: {104 object_id: '1234',105 style: {106 fill_color: [255, 255, 255]107 }108 },109 points: [[1000, 1000, 200]]110 }111 ]112 }113 }114 }115 ]116};117tape('isEnvelope', t => {118 t.ok(isEnvelope({type: 'foo', data: {a: 42}}), 'Detected XVIZ envelope');119 t.notok(isEnvelope(TestTimesliceMessageV1), 'V1 data not in envelope');120 t.notok(isEnvelope(TestTimesliceMessageV2), 'V2 data not in envelope');121 t.end();122});123tape('unpackEnvelope name parsing', t => {124 const notype = unpackEnvelope({type: 'foo', data: {a: 42}});125 t.equals(notype.namespace, 'foo');126 t.equals(notype.type, '');127 const empty = unpackEnvelope({type: '', data: {a: 42}});128 t.equals(empty.namespace, '');129 t.equals(empty.type, '');130 const nonXVIZ = unpackEnvelope({type: 'foo/bar', data: {a: 42}});131 t.equals(nonXVIZ.namespace, 'foo');132 t.equals(nonXVIZ.type, 'bar');133 const leadingSlash = unpackEnvelope({type: '/foo/bar', data: {a: 42}});134 t.equals(leadingSlash.namespace, '');135 t.equals(leadingSlash.type, 'foo/bar');136 t.end();137});138tape('unpackEnvelope xviz', t => {139 const enveloped = {140 type: 'xviz/state_update',141 data: {a: 42}142 };143 const expected = {144 namespace: 'xviz',145 type: 'state_update',146 data: enveloped.data147 };148 t.deepEquals(unpackEnvelope(enveloped), expected);149 t.end();150});151// TODO: blacklisted streams in xviz common152tape('parseXVIZData metadata', t => {153 resetXVIZConfigAndSettings();154 const metaMessage = parseXVIZData(TestMetadataMessageV2, {v2Type: 'metadata'});155 t.equals(metaMessage.type, XVIZ_MESSAGE_TYPE.METADATA, 'Metadata type set');156 t.equals(157 getXVIZConfig().currentMajorVersion,158 2,159 'Metadata currentMajorVersion set after parsing'160 );161 t.equals(162 metaMessage.eventStartTime,163 TestMetadataMessageV2.log_info.start_time,164 'Metadata eventStartTime set'165 );166 t.equals(167 metaMessage.eventEndTime,168 TestMetadataMessageV2.log_info.end_time,169 'Metadata eventEndTime set'170 );171 t.end();172});173tape('parseXVIZData metadata v1', t => {174 resetXVIZConfigAndSettings();175 setXVIZConfig({supportedVersions: [1]});176 const metaMessage = parseXVIZData(TestMetadataMessageV1);177 t.equals(metaMessage.type, XVIZ_MESSAGE_TYPE.METADATA, 'Metadata type set');178 t.equals(179 getXVIZConfig().currentMajorVersion,180 1,181 'Metadata currentMajorVersion set after parsing'182 );183 t.equals(184 metaMessage.eventStartTime,185 TestMetadataMessageV2.log_info.start_time,186 'Metadata eventStartTime set'187 );188 t.equals(189 metaMessage.eventEndTime,190 TestMetadataMessageV2.log_info.end_time,191 'Metadata eventEndTime set'192 );193 t.end();194});195tape('parseXVIZData unsupported version v1', t => {196 resetXVIZConfigAndSettings();197 setXVIZConfig({supportedVersions: [2]});198 t.throws(199 () => parseXVIZData(TestMetadataMessageV1),200 /XVIZ version 1 is not supported/,201 'Throws if supportedVersions does not match currentMajorVersion'202 );203 t.end();204});205tape('parseXVIZData unsupported version v2', t => {206 resetXVIZConfigAndSettings();207 setXVIZConfig({supportedVersions: [1]});208 t.throws(209 () => parseXVIZData(TestMetadataMessageV2, {v2Type: 'metadata'}),210 /XVIZ version 2 is not supported/,211 'Throws if supportedVersions does not match currentMajorVersion'212 );213 t.end();214});215tape('parseXVIZData undetectable version', t => {216 resetXVIZConfigAndSettings();217 setXVIZConfig({supportedVersions: [2]});218 t.throws(219 () => parseXVIZData({...TestMetadataMessageV2, version: 'abc'}, {v2Type: 'metadata'}),220 /Unable to detect the XVIZ version/,221 'Throws if version exists but cannot parse major version'222 );223 t.end();224});225tape('parseXVIZData metadata with full log time only', t => {226 resetXVIZConfigAndSettings();227 const metaMessage = parseXVIZData(metadataWithLogStartEnd, {v2Type: 'metadata'});228 t.equals(metaMessage.type, XVIZ_MESSAGE_TYPE.METADATA, 'Metadata type set');229 t.equals(230 getXVIZConfig().currentMajorVersion,231 2,232 'Metadata currentMajorVersion set after parsing'233 );234 t.equals(235 metaMessage.logStartTime,236 metadataWithLogStartEnd.log_info.log_start_time,237 'Metadata logStartTime set'238 );239 t.equals(240 metaMessage.logEndTime,241 metadataWithLogStartEnd.log_info.log_end_time,242 'Metadata logEndTime set'243 );244 t.end();245});246tape('parseXVIZData validate test data', t => {247 schemaValidator.validate('session/state_update', TestTimesliceMessageV2);248 t.end();249});250tape('parseXVIZData validate result when missing updates', t => {251 resetXVIZConfigAndSettings();252 setXVIZConfig({currentMajorVersion: 2});253 const metaMessage = parseXVIZData(254 {255 update_type: 'COMPLETE_STATE'256 },257 {v2Type: 'state_update'}258 );259 t.equals(metaMessage.type, XVIZ_MESSAGE_TYPE.INCOMPLETE, 'Type after parse set to error');260 t.ok(/Missing required/.test(metaMessage.message), 'Message details on what is missing');261 t.end();262});263tape('parseXVIZData validate result when updates is empty', t => {264 resetXVIZConfigAndSettings();265 setXVIZConfig({currentMajorVersion: 2});266 const metaMessage = parseXVIZData(267 {268 update_type: 'COMPLETE_STATE',269 updates: []270 },271 {v2Type: 'state_update'}272 );273 t.equals(metaMessage.type, XVIZ_MESSAGE_TYPE.INCOMPLETE, 'Type after parse set to error');274 t.comment(metaMessage.message);275 t.ok(/"updates" has length of 0/.test(metaMessage.message), 'Message details length is 0');276 t.end();277});278tape('parseXVIZData validate result when missing timestamp in updates', t => {279 resetXVIZConfigAndSettings();280 setXVIZConfig({currentMajorVersion: 2});281 const metaMessage = parseXVIZData(282 {283 update_type: 'COMPLETE_STATE',284 updates: [{}]285 },286 {v2Type: 'state_update'}287 );288 t.equals(metaMessage.type, XVIZ_MESSAGE_TYPE.INCOMPLETE, 'Type after parse set to error');289 t.ok(290 /Missing timestamp in "updates"/.test(metaMessage.message),291 'Message details missing timestamp'292 );293 t.end();294});295tape('parseXVIZData error', t => {296 resetXVIZConfigAndSettings();297 setXVIZConfig({currentMajorVersion: 2});298 const metaMessage = parseXVIZData({message: 'my message'}, {v2Type: 'error'});299 t.equals(metaMessage.type, XVIZ_MESSAGE_TYPE.ERROR, 'Metadata type set to error');300 t.end();301});302tape('parseXVIZData timeslice INCOMPLETE', t => {303 resetXVIZConfigAndSettings();304 setXVIZConfig({currentMajorVersion: 2});305 // NOTE: no explicit type for this message yet.306 let metaMessage = parseXVIZData(307 {308 ...TestTimesliceMessageV2,309 timestamp: null310 },311 {v2Type: 'state_update'}312 );313 t.equals(metaMessage.type, XVIZ_MESSAGE_TYPE.TIMESLICE, 'Missing timestamp is ok');314 metaMessage = parseXVIZData(315 {316 ...TestTimesliceMessageV2,317 updates: [{updates: null}]318 },319 {v2Type: 'state_update'}320 );321 t.equals(metaMessage.type, XVIZ_MESSAGE_TYPE.INCOMPLETE, 'Missing updates incomplete');322 metaMessage = parseXVIZData(323 {324 ...TestTimesliceMessageV2,325 updates: [326 {327 poses: {328 '/vehicle_pose': {329 map_origin: {longitude: 11.2, latitude: 33.4, altitude: 55.6}330 }331 }332 }333 ]334 },335 {v2Type: 'state_update'}336 );337 t.equals(metaMessage.type, XVIZ_MESSAGE_TYPE.INCOMPLETE, 'Missing updates is incomplete');338 metaMessage = parseXVIZData(339 {340 ...TestTimesliceMessageV2,341 updates: [342 {343 timestamp: null344 }345 ]346 },347 {v2Type: 'state_update'}348 );349 t.equals(metaMessage.type, XVIZ_MESSAGE_TYPE.INCOMPLETE, 'Missing timestamp is incomplete');350 t.end();351});352tape('parseXVIZData timeslice', t => {353 resetXVIZConfigAndSettings();354 setXVIZConfig({currentMajorVersion: 2});355 // NOTE: no explicit type for this message yet.356 let result = parseXVIZData({...TestTimesliceMessageV2}, {v2Type: 'state_update'});357 t.equals(result.type, XVIZ_MESSAGE_TYPE.TIMESLICE, 'Message type set for timeslice');358 t.equal(result.updateType, 'COMPLETE', 'XVIZ update type is parsed');359 t.equals(360 result.timestamp,361 TestTimesliceMessageV2.updates[0].poses['/vehicle_pose'].timestamp,362 'Message timestamp set from vehicle_pose'363 );364 // Incremental update365 result = parseXVIZData(366 {...TestTimesliceMessageV2, update_type: 'INCREMENTAL'},367 {v2Type: 'state_update'}368 );369 t.equals(result.type, XVIZ_MESSAGE_TYPE.TIMESLICE, 'Message type set for timeslice');370 t.equal(result.updateType, 'INCREMENTAL', 'XVIZ update type is parsed');371 // Deprecated 'snapshot' update type372 result = parseXVIZData(373 {...TestTimesliceMessageV2, update_type: 'SNAPSHOT'},374 {v2Type: 'state_update'}375 );376 t.equals(result.type, XVIZ_MESSAGE_TYPE.TIMESLICE, 'Message type set for timeslice');377 t.equal(result.updateType, 'INCREMENTAL', 'XVIZ update type is parsed');378 // Unknown update type379 result = parseXVIZData({...TestTimesliceMessageV2, update_type: ''}, {v2Type: 'state_update'});380 t.equals(381 result.type,382 XVIZ_MESSAGE_TYPE.INCOMPLETE,383 'Should not parse timeslice of unsupported update type'384 );385 t.end();386});387tape('parseXVIZData timeslice without parsing metadata (v1)', t => {388 // NOTE: this is the the teleassist case where they don't have metadata389 // before they start sending log data390 resetXVIZConfigAndSettings();391 setXVIZConfig({PRIMARY_POSE_STREAM: '/vehicle_pose'});392 setXVIZConfig({currentMajorVersion: 1});393 // NOTE: no explicit type for this message yet.394 const metaMessage = parseXVIZData({...TestTimesliceMessageV1});395 t.equals(metaMessage.type, XVIZ_MESSAGE_TYPE.TIMESLICE, 'Message type set for timeslice');396 t.equals(397 metaMessage.timestamp,398 TestTimesliceMessageV1.vehicle_pose.time,399 'Message timestamp set from timeslice'400 );401 t.ok(402 metaMessage.streams['/test/stream'].pointCloud,403 'v1 pointCloud is parsed even if metadata was not seen'404 );405 t.is(406 metaMessage.streams['/test/stream'].features[0].type,407 'points3d',408 'pointCloud exposed in features'409 );410 t.deepEquals(metaMessage.streams['/test/stream'].pointCloud.ids, [1234], 'v1 ids are populated');411 t.end();412});413tape('parseXVIZData preProcessPrimitive type change', t => {414 let calledPreProcess = false;415 resetXVIZConfigAndSettings();416 setXVIZConfig({currentMajorVersion: 1});417 setXVIZConfig({418 PRIMARY_POSE_STREAM: '/vehicle_pose',419 preProcessPrimitive: ({primitive, streamName, time}) => {420 calledPreProcess = true;421 primitive.type = 'circle2d';422 }423 });424 // NOTE: no explicit type for this message yet.425 const metaMessage = parseXVIZData({...TestTimesliceMessageV1});426 t.ok(calledPreProcess, 'Called preProcessPrimitive callback');427 t.equals(428 metaMessage.streams['/test/stream'].pointCloud,429 null,430 'There are no pointClouds in parsed object'431 );432 t.end();433});434tape('parseXVIZData pointCloud timeslice', t => {435 resetXVIZConfigAndSettings();436 setXVIZConfig({currentMajorVersion: 2});437 const PointCloudTestTimesliceMessage = TestTimesliceMessageV2;438 // NOTE: no explicit type for this message yet.439 const slice = parseXVIZData({...PointCloudTestTimesliceMessage});440 t.equals(slice.type, XVIZ_MESSAGE_TYPE.TIMESLICE, 'Message type set for timeslice');441 const pointCloud = slice.streams['/test/stream'].pointCloud;442 const feature = slice.streams['/test/stream'].features[0];443 t.ok(pointCloud, 'has a point cloud');444 t.is(feature.type, 'point', 'pointCloud exposed in features');445 t.equals(pointCloud.numInstances, 1, 'Has 1 instance');446 t.equals(pointCloud.positions.length, 3, 'Has 3 values in positions');447 t.equals(pointCloud.positions, feature.points, 'Feature has points');448 t.equals(pointCloud.colors, feature.colors, 'Feature has colors');449 t.end();450});451tape('parseXVIZData polyline flat', t => {452 resetXVIZConfigAndSettings();453 setXVIZConfig({currentMajorVersion: 2});454 const TestTimeslice = clone(TestTimesliceMessageV2);455 TestTimeslice.updates[0].primitives['/test/stream'] = {456 polylines: [457 {458 base: {459 object_id: '1234',460 style: {461 fill_color: [255, 255, 255]462 }463 },464 vertices: [1000, 1000, 200, 1000, 1000, 250]465 }466 ]467 };468 // NOTE: no explicit type for this message yet.469 const slice = parseXVIZData({...TestTimeslice});470 t.equals(slice.type, XVIZ_MESSAGE_TYPE.TIMESLICE, 'Message type set for timeslice');471 const features = slice.streams['/test/stream'].features;472 t.equals(features.length, 1, 'has has object');473 t.equals(features[0].type, 'polyline', 'type is polyline');474 t.deepEquals(475 features[0].vertices,476 [1000, 1000, 200, 1000, 1000, 250],477 'flat vertices array is returned'478 );479 t.end();480});481tape('parseXVIZData polygon flat', t => {482 resetXVIZConfigAndSettings();483 setXVIZConfig({currentMajorVersion: 2});484 const TestTimeslice = clone(TestTimesliceMessageV2);485 TestTimeslice.updates[0].primitives['/test/stream'] = {486 polygons: [487 {488 base: {489 object_id: '1234',490 style: {491 fill_color: [255, 255, 255]492 }493 },494 vertices: [1000, 1000, 200, 1000, 1000, 250, 1000, 1000, 300]495 }496 ]497 };498 // NOTE: no explicit type for this message yet.499 const slice = parseXVIZData({...TestTimeslice});500 t.equals(slice.type, XVIZ_MESSAGE_TYPE.TIMESLICE, 'Message type set for timeslice');501 const features = slice.streams['/test/stream'].features;502 t.equals(features.length, 1, 'has has object');503 t.equals(features[0].type, 'polygon', 'type is polygon');504 t.deepEquals(505 features[0].vertices,506 // We automatically close loops...507 [1000, 1000, 200, 1000, 1000, 250, 1000, 1000, 300],508 'flat vertices array is returned'509 );510 t.end();511});512tape('parseXVIZData flat JSON pointCloud', t => {513 resetXVIZConfigAndSettings();514 setXVIZConfig({currentMajorVersion: 2});515 const PointCloudTestTimesliceMessage = clone(TestTimesliceMessageV2);516 const stream = PointCloudTestTimesliceMessage.updates[0].primitives['/test/stream'];517 // NOTE: no explicit type for this message yet.518 let slice = parseXVIZData({...PointCloudTestTimesliceMessage});519 t.equals(slice.type, XVIZ_MESSAGE_TYPE.TIMESLICE, 'Message type set for timeslice');520 let pointCloud = slice.streams['/test/stream'].pointCloud;521 const feature = slice.streams['/test/stream'].features[0];522 t.ok(pointCloud, 'has a point cloud');523 t.is(feature.type, 'point', 'pointCloud exposed in features');524 t.equals(pointCloud.numInstances, 1, 'Has 1 instance');525 t.deepEquals(pointCloud.positions, [1000, 1000, 200], 'Has correct values in positions');526 t.deepEquals(pointCloud.colors, null, 'Does not contain colors');527 t.equals(pointCloud.positions, feature.points, 'Feature has points');528 t.equals(pointCloud.colors, feature.colors, 'Feature has colors');529 // v1 inline color530 stream.points[0].color = [0, 0, 255];531 slice = parseXVIZData({...PointCloudTestTimesliceMessage});532 pointCloud = slice.streams['/test/stream'].pointCloud;533 t.deepEquals(pointCloud.colors, [0, 0, 255], 'Has correct values in colors');534 // flattened colors stride = 3535 stream.points[0].colors = [[0, 0, 255]];536 slice = parseXVIZData({...PointCloudTestTimesliceMessage});537 pointCloud = slice.streams['/test/stream'].pointCloud;538 t.deepEquals(pointCloud.colors, [0, 0, 255], 'Has correct values in colors');539 // flattened colors stride = 4540 stream.points[0].colors = [[0, 0, 255, 255]];541 slice = parseXVIZData({...PointCloudTestTimesliceMessage});542 pointCloud = slice.streams['/test/stream'].pointCloud;543 t.deepEquals(pointCloud.colors, [0, 0, 255, 255], 'Has correct values in colors');544 t.end();545});546tape('parseXVIZData pointCloud timeslice TypedArray', t => {547 resetXVIZConfigAndSettings();548 setXVIZConfig({currentMajorVersion: 2});549 const PointCloudTestTimesliceMessage = clone(TestTimesliceMessageV2);550 const stream = PointCloudTestTimesliceMessage.updates[0].primitives['/test/stream'];551 stream.points[0].points = new Float32Array([500, 500, 200]);552 // NOTE: no explicit type for this message yet.553 let slice = parseXVIZData({...PointCloudTestTimesliceMessage});554 t.equals(slice.type, XVIZ_MESSAGE_TYPE.TIMESLICE, 'Message type set for timeslice');555 t.ok(slice.streams['/test/stream'].pointCloud, 'has a point cloud');556 let pointCloud = slice.streams['/test/stream'].pointCloud;557 t.equals(pointCloud.numInstances, 1, 'Has 1 instance');558 t.deepEquals(pointCloud.positions, [500, 500, 200], 'Has correct values in positions');559 t.deepEquals(pointCloud.colors, null, 'Does not contain colors');560 // flattened colors stride = 3561 stream.points[0].colors = new Uint8Array([0, 0, 255]);562 slice = parseXVIZData({...PointCloudTestTimesliceMessage});563 pointCloud = slice.streams['/test/stream'].pointCloud;564 t.deepEquals(pointCloud.colors, [0, 0, 255], 'Has correct values in colors');565 // flattened colors stride = 4566 stream.points[0].colors = new Uint8Array([0, 0, 255, 255]);567 slice = parseXVIZData({...PointCloudTestTimesliceMessage});568 pointCloud = slice.streams['/test/stream'].pointCloud;569 t.deepEquals(pointCloud.colors, [0, 0, 255, 255], 'Has correct values in colors');570 t.end();571});572tape('parseXVIZData pointCloud timeslice', t => {573 resetXVIZConfigAndSettings();574 setXVIZConfig({currentMajorVersion: 2});575 const PointCloudTestTimesliceMessage = clone(TestTimesliceMessageV2);576 PointCloudTestTimesliceMessage.updates[0].primitives['/test/stream'].points.push({577 base: {578 object_id: '1235',579 style: {580 fill_color: [255, 255, 255]581 }582 },583 points: new Float32Array([1000, 1000, 200])584 });585 // NOTE: no explicit type for this message yet.586 const slice = parseXVIZData({...PointCloudTestTimesliceMessage});587 t.equals(slice.type, XVIZ_MESSAGE_TYPE.TIMESLICE, 'Message type set for timeslice');588 const pointCloud = slice.streams['/test/stream'].pointCloud;589 const feature = slice.streams['/test/stream'].features[0];590 t.ok(pointCloud, 'has a point cloud');591 t.is(feature.type, 'point', 'pointCloud exposed in features');592 t.equals(pointCloud.numInstances, 2, 'Has 2 instance');593 t.equals(pointCloud.positions.length, 6, 'Has 6 values in positions');594 t.equals(pointCloud.ids.length, 2, 'Has 2 values in ids');595 t.equals(pointCloud.positions, feature.points, 'Feature has points');596 t.equals(pointCloud.colors, feature.colors, 'Feature has colors');597 t.end();598});599tape('parseXVIZData variable timeslice', t => {600 resetXVIZConfigAndSettings();601 setXVIZConfig({currentMajorVersion: 2});602 const VariableTestTimesliceMessage = {603 update_type: 'COMPLETE_STATE',604 updates: [605 {606 timestamp: 1001.0,607 poses: {608 '/vehicle_pose': {609 timestamp: 1001.0,610 map_origin: [11.2, 33.4, 55.6],611 position: [1.1, 2.2, 3.3],612 orientation: [0.1, 0.2, 0.3]613 }614 },615 variables: {616 '/foo': {617 variables: [618 {619 base: {620 object_id: 'A'621 },622 values: {doubles: [300, 400]}623 },624 {625 values: {doubles: [100, 200]}626 }627 ]628 }629 }630 }631 ]632 };633 // NOTE: no explicit type for this message yet.634 const slice = parseXVIZData({...VariableTestTimesliceMessage});635 t.equals(slice.type, XVIZ_MESSAGE_TYPE.TIMESLICE, 'Message type set for timeslice');636 t.ok(slice.streams['/foo'].variable, 'has variable');637 const variable = slice.streams['/foo'].variable;638 t.equals(variable.length, 2, 'Has 2 instances');639 t.equals(variable[0].id, 'A', 'Has correct id');640 t.deepEquals(variable[0].values, [300, 400], 'Has correct values');641 t.end();642});643tape('parseXVIZData futures timeslice v1', t => {644 resetXVIZConfigAndSettings();645 setXVIZConfig({currentMajorVersion: 1});646 const slice = parseXVIZData({...TestFuturesMessageV1});647 t.equals(slice.type, XVIZ_MESSAGE_TYPE.TIMESLICE, 'Message type set for timeslice');648 t.ok(slice.streams['/test/polygon'].lookAheads, 'has lookAheads field');649 const lookAheads = slice.streams['/test/polygon'].lookAheads;650 t.equals(lookAheads.length, 2, 'Has 2 primitive sets in lookAheads');651 t.end();652});653tape('parseXVIZData state_update, PERSISTENT', t => {654 resetXVIZConfigAndSettings();655 setXVIZConfig({currentMajorVersion: 2, ALLOW_MISSING_PRIMARY_POSE: true});656 const persistentMsg = {...TestTimesliceMessageV2};657 persistentMsg.update_type = 'PERSISTENT';658 const result = parseXVIZData(persistentMsg, {v2Type: 'state_update'});659 t.equals(result.type, XVIZ_MESSAGE_TYPE.TIMESLICE, 'Message type set for timeslice');660 t.equal(result.updateType, 'PERSISTENT', 'XVIZ update type is parsed');661 t.equals(result.timestamp, TestTimesliceMessageV2.updates[0].timestamp, 'Message timestamp set');662 const feature = result.streams['/test/stream'].features[0];663 t.equal(feature.type, 'point', 'feature has type point');664 t.deepEquals(Array.from(feature.points), [1000, 1000, 200], 'feature has type point');665 t.end();666});667tape('parseXVIZData state_update, no_data_streams', t => {668 resetXVIZConfigAndSettings();669 setXVIZConfig({currentMajorVersion: 2, ALLOW_MISSING_PRIMARY_POSE: true});670 const noDataStreamMsg = {...TestTimesliceMessageV2};671 noDataStreamMsg.updates[0].no_data_streams = ['/no-data-stream'];672 const result = parseXVIZData(noDataStreamMsg, {v2Type: 'state_update'});673 t.equals(result.type, XVIZ_MESSAGE_TYPE.TIMESLICE, 'Message type set for timeslice');674 t.equal(result.updateType, 'COMPLETE', 'XVIZ update type is parsed');675 t.equals(result.timestamp, TestTimesliceMessageV2.updates[0].timestamp, 'Message timestamp set');676 t.equal(result.streams['/no-data-stream'], null, 'no_data_stream marked as null');677 t.end();678});679tape('parseXVIZMessageSync', t => {680 resetXVIZConfigAndSettings();681 setXVIZConfig({currentMajorVersion: 2});682 const samples = [683 {684 name: 'bare',685 message: {...TestTimesliceMessageV2}686 },687 {688 name: 'enveloped',689 message: {690 type: 'xviz/state_update',691 data: {...TestTimesliceMessageV2}692 }693 }694 ];695 const testCases = [];696 for (const sample of samples) {697 const jsonString = JSON.stringify(sample.message);698 const binary = new TextEncoder().encode(jsonString);699 testCases.push(700 {701 title: `${sample.name} - plain JSON object`,702 message: sample.message703 },704 {705 title: `${sample.name} - JSON string`,706 message: jsonString707 },708 {709 title: `${sample.name} - Uint8Array`,710 message: binary711 },712 {713 title: `${sample.name} - ArrayBuffer`,714 message: binary.buffer715 }716 );717 }718 for (const testCase of testCases) {719 t.comment(testCase.title);720 let result;721 let error;722 const opts = {};723 parseXVIZMessageSync(724 testCase.message,725 newResult => {726 result = newResult;727 },728 newError => {729 error = newError;730 },731 opts732 );733 t.equals(undefined, error, 'No errors received while parsing');734 t.equals(result.type, XVIZ_MESSAGE_TYPE.TIMESLICE, 'Message type set for timeslice');735 t.equals(736 result.timestamp,737 TestTimesliceMessageV2.updates[0].poses['/vehicle_pose'].timestamp,738 'Message timestamp set from vehicle_pose'739 );740 }741 t.end();742});743tape('parseXVIZMessageSync#enveloped#metadata', t => {744 resetXVIZConfigAndSettings();745 setXVIZConfig({currentMajorVersion: 2});746 const enveloped = {747 type: 'xviz/metadata',748 data: {version: '2.0.0'}749 };750 let result;751 let error;752 const opts = {};753 parseXVIZMessageSync(754 enveloped,755 newResult => {756 result = newResult;757 },758 newError => {759 error = newError;760 },761 opts762 );763 t.equals(undefined, error, 'No errors received while parsing');764 t.notEquals(undefined, result, 'Update units');765 t.equals(result.type, XVIZ_MESSAGE_TYPE.METADATA, 'Message type set for metadata');766 t.equals(result.version, enveloped.data.version);767 t.end();768});769tape('parseXVIZMessageSync#enveloped#transform_log_done', t => {770 resetXVIZConfigAndSettings();771 setXVIZConfig({currentMajorVersion: 2});772 const enveloped = {773 type: 'xviz/transform_log_done',774 data: {id: 'foo'}775 };776 let result;777 let error;778 const opts = {};779 parseXVIZMessageSync(780 enveloped,781 newResult => {782 result = newResult;783 },784 newError => {785 error = newError;786 },787 opts788 );789 t.equals(undefined, error, 'No errors received while parsing');790 t.notEquals(undefined, result, 'Update units');791 t.equals(result.type, XVIZ_MESSAGE_TYPE.DONE, 'Message type set to done');792 t.equals(result.id, enveloped.data.id);793 t.end();794});795tape('parseXVIZMessageSync enveloped not xviz', t => {796 resetXVIZConfigAndSettings();797 setXVIZConfig({currentMajorVersion: 2});798 const enveloped = {799 type: 'bar/foo',800 data: {a: 42}801 };802 let result;803 let error;804 const opts = {};805 parseXVIZMessageSync(806 enveloped,807 newResult => {808 result = newResult;809 },810 newError => {811 error = newError;812 },813 opts814 );815 t.equals(undefined, error, 'No errors received while parsing');816 t.equals(undefined, result, 'No data parsed, unknown type');817 t.end();818});819tape('isXVIZMessage & getXVIZMessageType', t => {820 const testCases = [821 {822 title: 'type at start',823 isValid: true,824 message: {825 type: 'xviz/state_update',826 data: {...TestTimesliceMessageV2}827 }828 },829 {830 title: 'type at end',831 isValid: true,832 message: {833 data: {...TestMetadataMessageV2},834 type: 'xviz/metadata'835 }836 },837 {838 title: 'not enveloped',839 isValid: false,840 message: {...TestTimesliceMessageV2}841 },842 {843 title: 'unknown namespace',844 isValid: false,845 message: {846 type: 'foo/bar'847 }848 },849 {850 title: 'empty',851 isValid: false,852 message: null853 }854 ];855 const validateMessageType = (tt, testcase, msg) => {856 if (testcase.isValid) {857 const type = testcase.isBinary ? testcase.expectedType : testcase.message.type;858 tt.is(getXVIZMessageType(msg), type, 'XVIZ type matches');859 } else {860 tt.is(getXVIZMessageType(msg), null, 'XVIZ type correctly null');861 }862 };863 for (const testCase of testCases) {864 t.comment(testCase.title);865 t.is(isXVIZMessage(testCase.message), testCase.isValid, 'plain JSON object');866 validateMessageType(t, testCase, testCase.message);867 const jsonString = JSON.stringify(testCase.message);868 t.is(isXVIZMessage(jsonString), testCase.isValid, 'JSON string');869 validateMessageType(t, testCase, jsonString);870 const binary = new TextEncoder().encode(jsonString);871 t.is(isXVIZMessage(binary), testCase.isValid, 'Uint8Array');872 t.is(isXVIZMessage(binary.buffer), testCase.isValid, 'ArrayBuffer');873 validateMessageType(t, testCase, binary);874 validateMessageType(t, testCase, binary.buffer);875 }876 t.end();877});878tape('isXVIZMessage & getXVIZMessageType with Binary XVIZ', t => {879 const testCases = [880 {881 title: 'binary metadata',882 isValid: true,883 expectedType: 'xviz/metadata',884 message: MinimalBinaryMetadata885 },886 {887 title: 'binary state_update',888 isValid: true,889 expectedType: 'xviz/state_update',890 message: MinimalBinaryStateUpdate891 }892 // TODO: add non XVIZ test cases893 ];894 const validateMessageType = (tt, testcase, msg) => {895 if (testcase.isValid) {896 tt.is(getXVIZMessageType(msg), testcase.expectedType, 'XVIZ type matches');897 } else {898 tt.is(getXVIZMessageType(msg), null, 'XVIZ Type correctly null');899 }900 };901 for (const testCase of testCases) {902 t.comment(testCase.title);903 t.is(isXVIZMessage(testCase.message), testCase.isValid, 'binary JSON object');904 validateMessageType(t, testCase, testCase.message);905 }906 t.end();907});908tape('getDataFormat', t => {909 const XVIZUpdateObject = {type: 'xviz/state_update', data: TestTimesliceMessageV2};910 const XVIZUpdateString = JSON.stringify(XVIZUpdateObject);911 const testCases = [912 {913 title: 'binary format',914 expectedFormat: 'binary',915 message: MinimalBinaryMetadata916 },917 {918 title: 'object format',919 expectedFormat: 'object',920 message: XVIZUpdateObject921 },922 {923 title: 'format',924 expectedFormat: 'string',925 message: XVIZUpdateString926 }927 ];928 for (const testCase of testCases) {929 t.comment(testCase.title);930 t.is(getDataFormat(testCase.message), testCase.expectedFormat, 'format matches');931 }932 t.end();933});934tape('parseXVIZData timeslice with link', t => {935 resetXVIZConfigAndSettings();936 setXVIZConfig({currentMajorVersion: 2});937 const testData = {938 update_type: 'COMPLETE_STATE',939 updates: [940 {941 timestamp: 1001.0,942 poses: {943 '/vehicle_pose': {944 timestamp: 1001.0,945 map_origin: {longitude: 11.2, latitude: 33.4, altitude: 55.6},946 position: [1.1, 2.2, 3.3],947 orientation: [0.1, 0.2, 0.3]948 }949 },950 links: {951 '/vehicle_pose/lidar': {952 target_pose: '/vehicle_pose'953 }954 },955 primitives: {956 '/vehicle_pose/lidar': {957 points: [958 {959 points: [[1000, 1000, 200]]960 }961 ]962 }963 }964 }965 ]966 };967 const result = parseXVIZData({...testData}, {v2Type: 'state_update'});968 t.ok(result.links, 'Has links entry');969 t.equal(Object.keys(result.links).length, 1, 'Has 1 entry in links object');970 const link = result.links['/vehicle_pose/lidar'];971 t.ok(link, 'lidar link entry defined');972 t.equal(link.target_pose, '/vehicle_pose', 'link has correct target_pose');973 t.ok(result.poses, 'Has poses entry');974 t.equal(Object.keys(result.poses).length, 1, 'Has 1 entry in poses object');975 t.ok(result.streams, 'Has streams entry');976 t.equal(Object.keys(result.streams).length, 1, 'Has 1 entry in streams object');977 t.end();...
xviz-stream-buffer.js
Source:xviz-stream-buffer.js
1// Copyright (c) 2019 Uber Technologies, Inc.2//3// Licensed under the Apache License, Version 2.0 (the "License");4// you may not use this file except in compliance with the License.5// You may obtain a copy of the License at6//7// http://www.apache.org/licenses/LICENSE-2.08//9// Unless required by applicable law or agreed to in writing, software10// distributed under the License is distributed on an "AS IS" BASIS,11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12// See the License for the specific language governing permissions and13// limitations under the License.14import XVIZObject from '../objects/xviz-object';15import assert from '../utils/assert';16import {findInsertPos, INSERT_POSITION} from '../utils/search';17// Insert positions18const LEFT = INSERT_POSITION.LEFT;19const RIGHT = INSERT_POSITION.RIGHT;20// Buffer types21const UNLIMITED = 0;22const OFFSET = 1;23const FIXED = 2;24export default class XVIZStreamBuffer {25 /**26 * constructor27 * @param {object} options28 * @param {number} options.startOffset - desired start of buffer to keep in memory29 * relative to the current time.30 * @param {number} options.endOffset - desired end of buffer to keep in memory31 * relative to the current time.32 */33 constructor({startOffset = null, endOffset = null, maxLength = null} = {}) {34 if (Number.isFinite(startOffset) && Number.isFinite(endOffset)) {35 assert(startOffset <= 0 && endOffset >= 0, 'Steam buffer offset');36 this.bufferType = OFFSET;37 } else {38 this.bufferType = UNLIMITED;39 }40 this.options = {41 startOffset,42 endOffset,43 maxLength44 };45 /* Desired buffer range, in timestamps */46 this.bufferStart = null;47 this.bufferEnd = null;48 /* Sorted timeslices */49 this.timeslices = [];50 this.persistent = []; // like timeslices, but never pruned51 /* Sorted values by stream */52 this.streams = {};53 this.videos = {};54 this.persistentStreams = {};55 /* Update counter */56 this.lastUpdate = 0;57 /* Track the number of unique streams */58 this.streamCount = 0;59 this.hasBuffer = this.hasBuffer.bind(this);60 }61 /**62 * @property {number} the count of timeslices in buffer63 */64 get size() {65 return this.timeslices.length + this.persistent.length;66 }67 /**68 * updates the fixed buffer range, capping it to maxLength if set69 * @param {number} start - desired fixed start time of buffer to keep in memory70 * @param {number} end - desired fixed end time of buffer to keep in memory71 * @returns {start: number, end: number, oldStart: number, oldEnd: number} - the old and new buffer ranges72 */73 updateFixedBuffer(start, end) {74 const {75 bufferStart,76 bufferEnd,77 options: {maxLength}78 } = this;79 assert(start < end, 'updateFixedBuffer start / end');80 assert(81 this.bufferType === UNLIMITED || this.bufferType === FIXED,82 'updateFixedBuffer multiple buffer types'83 );84 this.bufferType = FIXED;85 if (!maxLength) {86 // If we have no limits on buffer size, just use the new provided values87 this.bufferStart = start;88 this.bufferEnd = end;89 } else if (90 !Number.isFinite(bufferStart) ||91 start > bufferEnd + maxLength ||92 start < bufferStart - maxLength93 ) {94 // If we have a limit but this is our first range definition, or this is so far before the existing95 // buffer that there's no overlap, use the provided start and determine end based on max buffer length96 this.bufferStart = start;97 this.bufferEnd = Math.min(end, start + maxLength);98 } else if (start < bufferStart) {99 // If this is before the existing buffer but close enough to have overlap, use the provided start100 // and determine the end based on max buffer length and the existing buffer end101 this.bufferStart = start;102 this.bufferEnd = Math.min(bufferEnd, start + maxLength);103 } else {104 // Otherwise, we're past the end of the existing buffer and either extend the existing buffer105 // or start a new buffer based on maxLength106 this.bufferStart = Math.min(bufferEnd, end - maxLength);107 this.bufferEnd = Math.min(this.bufferStart + maxLength, end);108 }109 this._pruneBuffer();110 return {start: this.bufferStart, end: this.bufferEnd, oldStart: bufferStart, oldEnd: bufferEnd};111 }112 /**113 * Gets the time range that the buffer is accepting data for114 * @returns {object} - {start | null, end | null} timestamps if any timeslice is loaded115 */116 getBufferRange() {117 if (this.bufferType !== UNLIMITED) {118 const {bufferStart, bufferEnd} = this;119 if (Number.isFinite(bufferStart)) {120 // buffer range should be ignored if setCurrentTime has not been called121 return {start: bufferStart, end: bufferEnd};122 }123 }124 return {start: null, end: null};125 }126 /**127 * Gets the buffered time range128 * @returns {object | null} - {start, end} timestamps if any timeslice is loaded129 */130 getLoadedTimeRange() {131 // TODO what about persistent?132 const {timeslices} = this;133 const len = timeslices.length;134 if (len > 0) {135 return {136 start: timeslices[0].timestamp,137 end: timeslices[len - 1].timestamp138 };139 }140 return null;141 }142 /**143 * Gets timeslices within a given time range.144 * @params {number, optional} start - start timestamp (inclusive)145 * @params {number, optional} end - end timestamp (inclusive)146 * @returns {array} - loaded timeslices within range147 */148 getTimeslices({start, end} = {}) {149 const {timeslices, persistent} = this;150 const startIndex = Number.isFinite(start) ? this._indexOf(start, LEFT) : 0;151 const endIndex = Number.isFinite(end) ? this._indexOf(end, RIGHT) : timeslices.length;152 const persistentEndIndex = Number.isFinite(end)153 ? findInsertPos(persistent, end, RIGHT)154 : persistent.length;155 return persistent.slice(0, persistentEndIndex).concat(timeslices.slice(startIndex, endIndex));156 }157 /**158 * Deprecated for perf reasons159 * Gets loaded stream slices within the current buffer160 */161 getStreams() {162 const {streams} = this;163 const result = {};164 for (const streamName in streams) {165 result[streamName] = streams[streamName].filter(value => value !== undefined);166 }167 return result;168 }169 /**170 * Gets loaded video frames within the current buffer171 */172 getVideos() {173 const {videos} = this;174 const result = {};175 for (const streamName in videos) {176 result[streamName] = videos[streamName].filter(value => value !== undefined);177 }178 return result;179 }180 /**181 * Get vehicle poses within the current buffer182 */183 getVehiclePoses() {184 return this.timeslices.map(t => t.vehiclePose).filter(Boolean);185 }186 /**187 * Add a new timeslice object into the timeline188 * @params {object} timeslice - timeslice object from XVIZ stream189 */190 // eslint-disable-next-line complexity, max-statements191 insert(timeslice) {192 const {timestamp, updateType} = timeslice;193 if (!this.isInBufferRange(timestamp)) {194 return false;195 }196 // backwards compatibility - normalize time slice197 timeslice.streams = timeslice.streams || {};198 timeslice.videos = timeslice.videos || {};199 timeslice.links = timeslice.links || {};200 timeslice.poses = timeslice.poses || {};201 const {timeslices, streams, videos} = this;202 if (updateType === 'PERSISTENT') {203 this._insertPersistentSlice(timeslice);204 this.lastUpdate++;205 return true;206 }207 // Note: if stream is not present in a timeslice, that index in the list holds undefined208 // This avoids repeatedly allocating new arrays for each stream, and lowers the cost of209 // insertion/deletion, which can be a significant perf hit depending on frame rate and210 // buffer size.211 for (const streamName in timeslice.streams) {212 if (!streams[streamName]) {213 streams[streamName] = new Array(timeslices.length);214 this.streamCount++;215 }216 }217 for (const streamName in timeslice.videos) {218 if (!videos[streamName]) {219 videos[streamName] = new Array(timeslices.length);220 }221 }222 const insertPosition = this._indexOf(timestamp, LEFT);223 const timesliceAtInsertPosition = timeslices[insertPosition];224 if (timesliceAtInsertPosition && timesliceAtInsertPosition.timestamp === timestamp) {225 // Same timestamp226 if (updateType === 'COMPLETE') {227 // Replace if it's a complete state228 this._insertTimesliceAt(insertPosition, 1, timeslice);229 } else {230 // Merge if it's an incremental update (default)231 this._mergeTimesliceAt(insertPosition, timeslice);232 }233 } else {234 this._insertTimesliceAt(insertPosition, 0, timeslice);235 }236 this.lastUpdate++;237 return true;238 }239 /**240 * Set the current timestamp241 * May drop timeslices that are not in range242 * @params {number} timestamp - timestamp of the playhead243 */244 setCurrentTime(timestamp) {245 if (this.bufferType === OFFSET) {246 const {247 options: {startOffset, endOffset}248 } = this;249 this.bufferStart = timestamp + startOffset;250 this.bufferEnd = timestamp + endOffset;251 this._pruneBuffer();252 }253 }254 /**255 * Override Object.prototype.valueOf256 * This is used to trigger a selector update without creating a new XVIZStreamBuffer instance257 */258 valueOf() {259 return this.lastUpdate;260 }261 /**262 * Provide interface for video-synchronizer to test for valid gps-based time range data.263 *264 * @params {number} fromTime is the gps time start of data265 * @params {number} toTime is the gps time end of data266 * @returns {bool} If we have no data, always return true, else true is returned267 * if the time range is satisfied268 */269 hasBuffer(fromTime, toTime) {270 // TODO: persistent271 if (!this.timeslices.length) {272 return true;273 }274 const {start, end} = this.getLoadedTimeRange();275 return fromTime >= start && toTime <= end;276 }277 /**278 * Check if a timestamp is inside the desired buffer range279 * @params {number} timestamp280 * @returns {bool}281 */282 isInBufferRange(timestamp) {283 const {bufferStart, bufferEnd, bufferType} = this;284 if (bufferType !== UNLIMITED && Number.isFinite(bufferStart)) {285 return timestamp >= bufferStart && timestamp <= bufferEnd;286 }287 return true;288 }289 /* eslint-disable complexity, no-unused-expressions */290 _pruneBuffer() {291 const {timeslices, streams, videos} = this;292 if (timeslices.length) {293 const startIndex = this._indexOf(this.bufferStart, LEFT);294 const endIndex = this._indexOf(this.bufferEnd, RIGHT);295 XVIZObject.prune(this.bufferStart, this.bufferEnd);296 const trimStart = startIndex > 0;297 const trimEnd = endIndex < timeslices.length;298 if (trimStart || trimEnd) {299 // Drop frames that are outside of the buffer300 trimEnd && timeslices.splice(endIndex);301 trimStart && timeslices.splice(0, startIndex);302 for (const streamName in streams) {303 const stream = streams[streamName];304 trimEnd && stream.splice(endIndex);305 trimStart && stream.splice(0, startIndex);306 }307 for (const streamName in videos) {308 const stream = videos[streamName];309 trimEnd && stream.splice(endIndex);310 trimStart && stream.splice(0, startIndex);311 }312 this.lastUpdate++;313 }314 }315 }316 /* eslint-enable complexity, no-unused-expressions */317 _insertPersistentSlice(persistentSlice) {318 const {persistent, persistentStreams} = this;319 const {timestamp, streams, links, poses} = persistentSlice;320 const index = findInsertPos(persistent, timestamp, LEFT);321 const timesliceAtInsertPosition = persistent[index];322 if (timesliceAtInsertPosition && timesliceAtInsertPosition.timestamp === timestamp) {323 // merge324 Object.assign(timesliceAtInsertPosition, persistentSlice, {325 streams: Object.assign(timesliceAtInsertPosition.streams, streams),326 links: Object.assign(timesliceAtInsertPosition.links, links),327 poses: Object.assign(timesliceAtInsertPosition.poses, poses)328 });329 } else {330 // insert331 persistent.splice(index, 0, persistentSlice);332 }333 for (const streamName in streams) {334 if (!(streamName in persistentStreams)) {335 persistentStreams[streamName] = true;336 this.streamCount++;337 }338 }339 }340 _mergeTimesliceAt(index, timeslice) {341 const {timeslices, streams, videos} = this;342 const timesliceAtInsertPosition = timeslices[index];343 Object.assign(timesliceAtInsertPosition, timeslice, {344 streams: Object.assign(timesliceAtInsertPosition.streams, timeslice.streams),345 links: Object.assign(timesliceAtInsertPosition.links, timeslice.links),346 poses: Object.assign(timesliceAtInsertPosition.poses, timeslice.poses),347 videos: Object.assign(timesliceAtInsertPosition.videos, timeslice.videos)348 });349 for (const streamName in timeslice.streams) {350 const value = timeslice.streams[streamName];351 streams[streamName][index] = value;352 }353 for (const streamName in timeslice.videos) {354 videos[streamName][index] = timeslice.videos[streamName];355 }356 }357 _insertTimesliceAt(index, deleteCount, timeslice) {358 const {timeslices, streams, videos} = this;359 timeslices.splice(index, deleteCount, timeslice);360 for (const streamName in streams) {361 streams[streamName].splice(index, deleteCount, timeslice.streams[streamName]);362 }363 for (const streamName in videos) {364 videos[streamName].splice(index, deleteCount, timeslice.videos[streamName]);365 }366 }367 /**368 * Return insert position for timeslice data given a timestamp369 * @params {number} timestamp370 * @params {number} insertPosition - insert to the left or right of the equal element.371 * @returns {number} index of insert position372 */373 _indexOf(timestamp, insertPosition = LEFT) {374 const {timeslices} = this;375 return findInsertPos(timeslices, timestamp, insertPosition);376 }...
lbc-transaction-reports.js
Source:lbc-transaction-reports.js
1var co = require('co')2var config = require(__dirname + '/config/options.js')3// todo guarded function console.log(__dirname + '/config/options.js')4var request = require('co-request')5var nonce = require('nonce') ()6var crypto = require("crypto")7var thepayload = new Array()8var moment = require('moment')9var fs = require('fs')10function round(value, decimals) {11 return Number(Math.round(value+'e'+decimals)+'e-'+decimals);12}13function getAssetMeta ( asset_symbol ) {14 assetMeta = {}15 switch(asset_symbol) {16 case 'USD':17 assetMeta.symbol = 'USD'18 assetMeta.label = 'US Dollar'19 assetMeta.label_plural = 'US Dollars'20 assetMeta.atom_label = 'penny'21 assetMeta.atom_label_plural = 'pennies'22 assetMeta.atoms_per_unit = parseInt(100)23 break24 case 'BTC':25 assetMeta.symbol = 'BTC'26 assetMeta.label = 'bitcoin'27 assetMeta.label_plural = 'bitcoins'28 assetMeta.atom_label = 'satoshi'29 assetMeta.atom_label_plural = 'satoshis'30 assetMeta.atoms_per_unit = parseInt(100000000)31 break32 }33 return assetMeta34}35function reportVolumeTimeslice ( transaction_list, time_format_string ) {36 var result = [].concat.apply(37 [], transaction_list.map(function(transaction) {38 txn = {}39 txn.timeslice = time_format_string40 txn.released_at_timeslice = moment.utc(transaction.released_at_utc).format(time_format_string)41 txn.asset_in = transaction.asset_in42 txn.number_in = transaction.number_in43 txn.asset_out = transaction.asset_out44 txn.number_out = transaction.number_out45 txn.timeslice_asset_in_asset_out = moment.utc(transaction.released_at_utc).format(time_format_string) + transaction.asset_in.toString() + transaction.asset_out.toString()46 return txn47 })48 .reduce(function(res, obj) {49 if(!(obj.timeslice_asset_in_asset_out in res))50 res.__array.push(res[obj.timeslice_asset_in_asset_out] = obj)51 else {52 res[obj.timeslice_asset_in_asset_out].timeslice = obj.timeslice53 res[obj.timeslice_asset_in_asset_out].asset_in = obj.asset_in54 res[obj.timeslice_asset_in_asset_out].number_in += obj.number_in55 res[obj.timeslice_asset_in_asset_out].asset_out = obj.asset_out56 res[obj.timeslice_asset_in_asset_out].number_out += obj.number_out57 res[obj.timeslice_asset_in_asset_out].timeslice_asset_in_asset_out = obj.timeslice_asset_in_asset_out58 }59 return res60 }, {__array:[]} ).__array61 .map(function(timeslice_summary){62 var timeslice_smry = {}63 timeslice_smry.timeslice_label = timeslice_summary.timeslice64 timeslice_smry.released_at_timeslice = timeslice_summary.released_at_timeslice65 timeslice_smry.asset_in_label_plural = getAssetMeta(timeslice_summary.asset_in).label_plural66 timeslice_smry.amount_in_display = round(parseFloat(67 timeslice_summary.number_in / getAssetMeta(timeslice_summary.asset_in).atoms_per_unit)68 , 2)69 timeslice_smry.asset_out_label_plural = getAssetMeta(timeslice_summary.asset_out).label_plural70 timeslice_smry.amount_out_display = round(parseFloat(71 timeslice_summary.number_out / getAssetMeta(timeslice_summary.asset_out).atoms_per_unit)72 , 2)73 return timeslice_smry74 })75 )76 return result77}78function reportVolumeUser ( transaction_list ) {79 var result = [].concat.apply(80 [], transaction_list.map(function(transaction) {81 txn = {}82 txn.asset_in = transaction.asset_in83 txn.number_in = transaction.number_in84 txn.asset_out = transaction.asset_out85 txn.number_out = transaction.number_out86 txn.released_at = moment.utc(transaction.released_at_utc)87 txn.buyer = transaction.buyer88 txn.txn_count = 189 return txn90 })91 .reduce(function(res, obj) {92 if(!(obj.buyer in res))93 res.__array.push(res[obj.buyer] = obj)94 else {95 res[obj.buyer].buyer= obj.buyer96 res[obj.buyer].asset_in = obj.asset_in97 res[obj.buyer].number_in += obj.number_in98 res[obj.buyer].asset_out = obj.asset_out99 res[obj.buyer].number_out += obj.number_out100 res[obj.buyer].txn_count += obj.txn_count101 res[obj.buyer].buyer = obj.buyer102 }103 return res104 }, {__array:[]} ).__array105 .map(function(user_summary){106 var user_smry = {}107 user_smry.buyer = user_summary.buyer108 user_smry.asset_in_label_plural = getAssetMeta(user_summary.asset_in).label_plural109 user_smry.amount_in_display = round(parseFloat(110 user_summary.number_in / getAssetMeta(user_summary.asset_in).atoms_per_unit)111 , 2)112 user_smry.asset_out_label_plural = getAssetMeta(user_summary.asset_out).label_plural113 user_smry.amount_out_display = round(parseFloat(114 user_summary.number_out / getAssetMeta(user_summary.asset_out).atoms_per_unit)115 , 2)116 return user_smry117 }) 118 .filter(function(user_summary) {119 return user_summary.amount_in_display > 2000120 })121 )122 return result123}124function reportSuspiciousActivity ( time_period_days, pennies_amt, transaction_list ) {125 var result = [].concat.apply(126 [], transaction_list.map(function(transaction) {127 txn = {}128 txn.asset_in = transaction.asset_in129 txn.number_in = transaction.number_in130 txn.asset_out = transaction.asset_out131 txn.number_out = transaction.number_out132 txn.released_at = moment.utc(transaction.released_at_utc)133 txn.buyer = transaction.buyer134 txn.txn_count = 0135 return txn136 })137 .sort(function(a,b) { return a.released_at - b.released_at })138 .reduce(function(buyers, txn) {139 txn.buyerindex = txn.buyer140 141 if (!(txn.buyerindex in buyers)){142 txn.previous_released_at = txn.released_at143 txn.previous_structuresize = 0144 buyers.__array.push(buyers[txn.buyerindex] = txn)145 buyers[txn.buyerindex].maxstructuresize = 0146 }147 else148 {149 txn.previous_released_at = buyers[txn.buyerindex].released_at150 txn.previous_structuresize = buyers[txn.buyerindex].structuresize151 }152 buyers[txn.buyerindex].released_at = txn.released_at153 buyers[txn.buyerindex].previous_released_at = txn.previous_released_at154 buyers[txn.buyerindex].previous_structuresize = txn.previous_structuresize155 buyers[txn.buyerindex].days_since = moment.duration(txn.released_at.diff(txn.previous_released_at)).asDays()156 if(moment.duration(txn.released_at.diff(txn.previous_released_at)).asDays() < time_period_days )157 {158 buyers[txn.buyerindex].structuresize = txn.previous_structuresize + txn.number_in159 }160 else {161 buyers[txn.buyerindex].structuresize = txn.number_in162 }163 164 if(buyers[txn.buyerindex].structuresize > buyers[txn.buyerindex].maxstructuresize) {165 buyers[txn.buyerindex].maxstructuresize = buyers[txn.buyerindex].structuresize166 buyers[txn.buyerindex].maxstructureenddate = txn.released_at167 }168 return buyers169 }, {__array:[]} ).__array)170 .filter(function(user_summary) {171 return user_summary.maxstructuresize > pennies_amt172 })173 return result174}175function reportTransactionList ( transactions_json )176{177 // navigate to transaction level178 var result = [].concat.apply(179 [], transactions_json.map(180 function(dlpage){181 return dlpage.data['contact_list'].map(182 function(contact_list){183 return contact_list.data184 })185 })186 )187 // row level business logic188 .map(function(transaction){189 var txn = {}190 txn.released_at_utc = moment(transaction.released_at).valueOf()191 txn.asset_in = getAssetMeta(transaction.currency).symbol192 txn.number_in = parseInt(parseFloat(transaction.amount) * getAssetMeta(transaction.currency).atoms_per_unit)193 txn.asset_out = getAssetMeta('BTC').symbol194 txn.number_out = parseInt(parseFloat(transaction.amount_btc) * getAssetMeta('BTC').atoms_per_unit)195 txn.buyer = transaction.buyer.username196 return txn197 })198 return result199}200function* generateHmac (message, secretkey, algorithm, encoding) {201 return crypto.createHmac(algorithm, secretkey).update(message).digest(encoding)202}203function* buildHmacMessage (the_nonce, api_key, pathname, query) {204 query = query || ''205 var message = the_nonce + api_key + pathname + query206 return message207}208function* buildOptions ( api_key, the_nonce, target_url, api_secret, algorithm, encoding) {209 var url = require("url");210 var urlobj = url.parse(target_url)211 var pathname = urlobj.pathname212 var query = urlobj.query213 return {214 url: target_url,215 "headers": {216 "Apiauth-Key": api_key,217 "Apiauth-Nonce": the_nonce,218 "Apiauth-Signature": yield generateHmac ( yield buildHmacMessage(the_nonce, api_key, pathname, query), api_secret, algorithm, encoding)219 },220 "form": {221 }222 }223}224//// download paginated transactions from localbitcoins.com225co(function* () { //author doesn't know if "co" non-blocking something-or-other is helping226 console.log('please wait: downloading all transactions from localbitcoins')227 // obtain read only api key from your localbitcoins account and put it in ./config/options.js228 var api_key = config.lbc_readonly_api_key229 var api_secret = config.lbc_readonly_api_secret230 var target_url = 'https://localbitcoins.com/api/dashboard/released/'231 232 var algorithm = 'sha256'233 var encoding = 'hex'234 while (target_url != null) {235 var the_nonce = nonce() * 10236 var options = yield buildOptions( api_key, the_nonce, target_url, api_secret, algorithm, encoding)237 var result = yield request(options)238 var response = result239 var next_page = yield JSON.parse( response.body ).pagination240 if ( next_page.next != '') {241 target_url = next_page.next242 thepayload.push(JSON.parse(response.body))243 }244 else245 {246 thepayload.push(JSON.parse(response.body))247 console.log(response.body)248 }249 }250 251 // or grab from local for testing252// var fs = require('fs');253// thepayload = yield JSON.parse(fs.readFileSync('transactions.json', 'utf8'))254// 255 // monthlyreport =256 // reportVolumeTimeslice(257 // reportTransactionList(thepayload)258 // ,"YYYYMM"259 // )260 // console.log(JSON.stringify(monthlyreport, null, 2))261 //262 //263 // weeklyreport = reportVolumeTimeslice(264 // reportTransactionList(thepayload)265 // ,"YYYYww"266 // )267 // console.log(JSON.stringify(weeklyreport, null, 2))268 //269 // dailyreport = reportVolumeTimeslice(270 // reportTransactionList(thepayload)271 // ,"YYYYMMDD"272 // )273 // console.log(JSON.stringify(dailyreport, null, 2))274 // userreport =275 // reportVolumeUser(276 // reportTransactionList(thepayload)277 // )278 // console.log(JSON.stringify(userreport, null, 2))279 suspiciousactivityreport_day =280 reportSuspiciousActivity(timeperioddays=1, pennies_amt=200000,281 reportTransactionList(thepayload)282 )283 console.log("SAR 2,000 in one day")284 console.log(JSON.stringify(suspiciousactivityreport_day, null, 2))285 suspiciousactivityreport_week =286 reportSuspiciousActivity(timeperioddays=7, pennies_amt=500000,287 reportTransactionList(thepayload)288 )289 console.log("SAR 5,000 in one week")290 console.log(JSON.stringify(suspiciousactivityreport_week, null, 2))291 suspiciousactivityreport_month =292 reportSuspiciousActivity(timeperioddays=30, pennies_amt=1000000,293 reportTransactionList(thepayload)294 )295 console.log("SAR 10,000 in one month")296 console.log(JSON.stringify(suspiciousactivityreport_month, null, 2))...
EditorTimeClipping.js
Source:EditorTimeClipping.js
1function Timeslice() {2 var tagMap = [3 {key: TAG_TIMESLICE_START, value: JS_TIMESLICE_START},4 {key: TAG_TIMESLICE_END, value: JS_TIMESLICE_END}5 ];6 7 var fieldMap = [8 {key: FIELD_TIMESLICE_START, value: JS_TIMESLICE_START},9 {key: FIELD_TIMESLICE_END, value: JS_TIMESLICE_END}10 ];11 12 var validatorMap = [13 {selector: JS_TIMESLICE_START, type: VALIDATOR_TYPE_HMSM, param: {recommend: "0:0:0:0"} },14 {selector: JS_TIMESLICE_END, type: VALIDATOR_TYPE_HMSM, param: {recommend: "0:0:0:0"} }15 ];16 17 this.prefixField = "";18 this.myField = FIELD_TIMESLICES;19 this.fieldIndex = null;20 21 this.dom = null;22 this.timeClipping = null;23 this.SetDOM = function(dom) {24 this.dom = dom;25 };26 this.Create = function(domParent, timesliceTmpl) {27 if(timesliceTmpl == null) {28 timesliceTmpl = JS_TIMESLICE_TEMPLATE;29 }30 var $tmp = $(timesliceTmpl);31 if($tmp.length == 0) return null;32 33 var $ts = $tmp.clone();34 $ts.attr("id", "");35 $(domParent).append($ts.get(0));36 37 this.Init($ts.get(0));38 return this.dom;39 };40 41 this.Init = function(dom) {42 this.SetDOM(dom);43 this.Bind();44 };45 46 this.Delete = function() {47 $(this.dom).remove();48 this.dom = null;49 };50 51 this.Bind = function() {52 if(this.dom == null) return;53 var context = this;54 var $timeslice = $(this.dom);55 $timeslice.find(JS_DELETE_CLIP_TRIGGER).click(function() {56 if(context.timeClipping != null) {57 context.timeClipping.DeleteTimeslice(context);58 }59 });60 61 $('input', this.dom).focus(function() {62 g_Focus = this;63 });64 65 $('input', this.dom).blur(function() {66 g_Focus = null;67 });68 69 $('select', this.dom).focus(function() {70 g_Focus = this;71 });72 73 $('select', this.dom).blur(function() {74 g_Focus = null;75 });76 77 ValidatorBindArray(this.dom, validatorMap);78 };79 80 this.SetTimeClipping = function(timeClipping) {81 this.timeClipping = timeClipping;82 };83 84 //o: {startTimeText: "hh:mm:ss:ff", endTimeText: "hh:mm:ss:ff"}85 this.SetTime = function(o) {86 if(this.dom == null) return;87 var $ts = $(this.dom);88 $ts.find(JS_TIMESLICE_START).val(o.startTimeText);89 $ts.find(JS_TIMESLICE_END).val(o.endTimeText);90 };91 92 this.GetTime = function() {93 if(this.dom == null) return null;94 var $ts = $(this.dom);95 var o = {};96 97 o.startTimeText = $ts.find(JS_TIMESLICE_START).val();98 var timeObj = uTimeText2Object(o.startTimeText);99 o.startTime = timeObj.ms;100 if(isNaN(o.startTime)) o.startTime = 0;101 102 o.endTimeText = $ts.find(JS_TIMESLICE_END).val();103 timeObj = uTimeText2Object(o.endTimeText);104 o.endTime = timeObj.ms;105 if(isNaN(o.endTime)) o.endTime = 0;106 107 return o;108 };109 110 this.GetValueByJS = function(selector) {111 return $(this.dom).find(selector).val();112 };113 114 /** xml : XMLWriter object**/115 this.XML = function(xml) {116 if(this.dom == null) return;117 var value = "";118 119 xml.BeginNode(TAG_TIMESLICE);120 121 for(var i = 0; i < tagMap.length; i++) {122 value = this.GetValueByJS(tagMap[i].value);123 xml.Node(tagMap[i].key, value);124 }125 126 xml.EndNode();127 };128 129 /* Field operate */130 this.SetPrefixField = function(prefix) {131 this.prefixField = prefix;132 };133 134 this.SetFieldIndex = function(i) {135 this.fieldIndex = i;136 };137 138 this.GetFullField = function() {139 var field = "";140 if(this.fieldIndex == null) {141 field = this.prefixField + this.myField + ".";142 } else {143 field = this.prefixField + this.myField + "[" + this.fieldIndex + "].";144 }145 return field;146 };147 148 this.UpdateElementName = function() {149 if(this.dom == null) return;150 var len = fieldMap.length;151 var fullField = this.GetFullField();152 for(var i = 0; i < len; i++) {153 var $sel = $(fieldMap[i].value, this.dom);154 var elName = fullField + fieldMap[i].key;155 $sel.attr("name", elName);156 };157 this.UpdateSubElement();158 };159 160 this.UpdateSubElement = function() {161 };162 /* Field operate end */163}164function EditorTimeClipping() {165 var defaultData = {enable: ENABLE_FALSE, mode: ENABLE_TRUE};166 167 var fieldMap = [168 {key: FIELD_TIMECLIPPING_ENABLE, value: JS_TIMECLIPPING_ENABLE},169 {key: FIELD_TIMECLIPPING_TRIMMED, value: JS_TIMECLIPPING_MODE}170 ];171 172 this.prefixField = "";173 this.myField = FIELD_TIMECLIPPING;174 this.fieldIndex = null;175 176 this.dom = null;177 this.timesliceArray = [];178 this.timesliceTmpl = null;179 this.fnNew = null;180 this.fnDelete = null;181 this.support = true;182 this.Init = function(dom, timesliceTmpl) {183 this.timesliceTmpl = timesliceTmpl;184 this.SetDOM(dom);185 this.LicenseControl();186 this.UpdateTrimmed();187 this.Bind();188 this.InitSub();189 this.SortTimeSlices();190 };191 192 this.LicenseControl = function() {193 if(GetLicense(license.VIDEO_EDITING_TIMELINE_CUT_TRIM) != license.ENABLED) {194 $(this.dom).remove();195 this.dom = null;196 }197 };198 199 this.SetDOM = function(dom) {200 this.dom = dom;201 };202 203 this.Bind = function() {204 if(this.dom == null) return;205 var context = this;206 var $timeClipping = $(this.dom);207 $timeClipping.find(JS_NEW_CLIP_TRIGGER).click(function() {208 context.NewTimeslice();209 });210 211 $('input', this.dom).focus(function() {212 g_Focus = this;213 });214 215 $('input', this.dom).blur(function() {216 g_Focus = null;217 });218 219 $('select', this.dom).focus(function() {220 g_Focus = this;221 });222 223 $('select', this.dom).blur(function() {224 g_Focus = null;225 });226 };227 228 this.InitSub = function() {229 if(this.dom == null) return;230 var context = this;231 var $timeClipping = $(this.dom);232 $timeClipping.find(JS_TIMESLICE).each(function() {233 var timeslice = new Timeslice();234 timeslice.Init(this);235 timeslice.SetTimeClipping(context);236 context.timesliceArray.push(timeslice);237 });238 };239 240 this.UpdateTrimmed = function() {241 var trimmed = $(JS_TIMECLIPPING_TRIMMED, this.dom).val();242 var value = "true";243 if(trimmed == "0") {244 value = "false";245 }246 247 $(JS_TIMECLIPPING_MODE, this.dom).each(function() {248 if(value == this.value) {249 this.checked = true;250 } else {251 this.checked = false;252 }253 });254 };255 256 this.SetFnNew = function(fn) {257 this.fnNew = fn;258 };259 260 /*used in cloud transcoder, cannot delete*/261 this.SetFnDelete = function(fn) {262 this.fnDelete = fn;263 };264 265 this.SetSupport = function(bSupport) {266 if(this.dom == null) return;267 if(bSupport) {268 $(JS_SUPPORT, this.dom).show();269 $(JS_UNSUPPORT, this.dom).hide();270 } else {271 $(JS_SUPPORT, this.dom).hide();272 $(JS_UNSUPPORT, this.dom).show();273 }274 this.support = bSupport;275 };276 277 this.NewTimeslice = function() {278 var timeslice = new Timeslice();279 timeslice.Create($(this.dom).find(JS_CLIP_CONTAINER).get(0), this.timesliceTmpl);280 timeslice.SetTimeClipping(this);281 this.timesliceArray.push(timeslice);282 this.SortTimeSlices();283 if($.isFunction(this.fnNew)) {284 this.fnNew(timeslice.dom);285 }286 };287 288 this.DeleteTimeslice = function(timeslice) {289 var bFound = false;290 var len = this.timesliceArray.length;291 for(var i = 0; i < len; i++) {292 if(bFound) {293 this.timesliceArray[i-1] = this.timesliceArray[i];294 } else {295 if(this.timesliceArray[i] == timeslice) {296 timeslice.Delete();297 bFound = true;298 }299 }300 }301 if(bFound) {302 this.timesliceArray.length--;303 }304 this.SortTimeSlices();305 if($.isFunction(this.fnDelete)) {306 this.fnDelete();307 }308 };309 310 this.ClearTimeslice = function() {311 if(this.dom == null) return;312 var len = this.timesliceArray.length;313 for(var i = 0; i < len; i++) {314 var timeslice = this.timesliceArray[i];315 timeslice.Delete();316 }317 this.timesliceArray.length = 0;318 this.SortTimeSlices();319 };320 321 this.SortTimeSlices = function() {322 var $dom = $(this.dom);323 var $tsArr = $dom.find(JS_CLIP_INDEX);324 $tsArr.each(function(i) {325 $(this).text(i+1);326 });327 if($tsArr.length >= MAX_COUNT_TIME_SLICES) {328 $dom.find(JS_NEW_CLIP_TRIGGER).hide();329 } else {330 $dom.find(JS_NEW_CLIP_TRIGGER).show();331 }332 };333 334 this.GetTimeClippingInfo = function() {335 if(this.dom == null) return null;336 var o = {};337 o.enable = this.GetValueByJS(JS_TIMECLIPPING_ENABLE);338 o.mode = this.GetValueByJS(JS_TIMECLIPPING_MODE);339 return o;340 };341 342 this.SetTimeClippingInfo = function(o) {343 if(this.dom == null) return;344 var $timeClipping = $(this.dom);345 if(o.enable == ENABLE_TRUE) {346 $timeClipping.find(JS_TIMECLIPPING_ENABLE).get(0).checked = true;347 } else {348 $timeClipping.find(JS_TIMECLIPPING_ENABLE).get(0).checked = false;349 }350 351 $timeClipping.find(JS_TIMECLIPPING_MODE).each(function() {352 if(o.mode == this.value) {353 this.checked = true;354 } else {355 this.checked = false;356 }357 });358 };359 360 this.GetTimesliceList = function() {361 if(this.dom == null) return null;362 var array = [];363 for(var i = 0; i < this.timesliceArray.length; i++) {364 var timeslice = this.timesliceArray[i];365 var o = timeslice.GetTime();366 array[i] = o;367 }368 return array;369 };370 371 //array: [{startTimeText: "hh:mm:ss:ff", endTimeText: "hh:mm:ss:ff"}, {...}]372 this.SetTimesliceList = function(array) {373 if(this.dom == null) return;374 this.ClearTimeslice();375 for(var i = 0; i < array.length; i++) {376 var timeslice = new Timeslice();377 timeslice.Create($(this.dom).find(JS_CLIP_CONTAINER).get(0), this.timesliceTmpl);378 timeslice.SetTime(array[i]);379 timeslice.SetTimeClipping(this);380 this.timesliceArray.push(timeslice);381 if($.isFunction(this.fnNew)) {382 this.fnNew(timeslice.dom);383 }384 }385 this.SortTimeSlices();386 };387 388 this.RestoreTimeClipping = function() {389 if(this.dom == null) return;390 this.SetTimeClippingInfo(defaultData);391 var arr = [];392 this.SetTimesliceList(arr);393 };394 395 this.GetValueByJS = function(jsSelect) {396 var value = null;397 var $sel = $(this.dom).find(jsSelect);398 if($sel.attr('type') == "checkbox") {399 if($sel.get(0).checked) {400 value = ENABLE_TRUE;401 } 402 else {403 value = ENABLE_FALSE;404 }405 } else if($sel.attr('type') == "radio") {406 $sel.each(function(){407 if(this.checked) {408 value = this.value;409 }410 });411 }412 else {413 value = $sel.val();414 }415 return value;416 };417 418 this.XML = function(xml) {419 if(this.dom == null) return;420 if(!this.support) return;421 422 xml.BeginNode(TAG_TIMECLIPPING);423 var o = this.GetTimeClippingInfo();424 xml.Node(TAG_ENABLED, o.enable);425 xml.Node(TAG_TIMECLIPPING_TRIMMED, o.mode);426 427 for(var i = 0; i < this.timesliceArray.length; i++) {428 var timeslice = this.timesliceArray[i];429 timeslice.XML(xml);430 }431 432 xml.EndNode();433 };434 435 /* Field operate */436 this.SetPrefixField = function(prefix) {437 this.prefixField = prefix;438 };439 440 this.SetFieldIndex = function(i) {441 this.fieldIndex = i;442 };443 444 this.GetFullField = function() {445 var field = "";446 if(this.fieldIndex == null) {447 field = this.prefixField + this.myField + ".";448 } else {449 field = this.prefixField + this.myField + "[" + this.fieldIndex + "].";450 }451 return field;452 };453 454 this.UpdateElementName = function() {455 if(this.dom == null) return;456 if(!this.support) return;457 458 var len = fieldMap.length;459 var fullField = this.GetFullField();460 for(var i = 0; i < len; i++) {461 var $sel = $(fieldMap[i].value, this.dom);462 var elName = fullField + fieldMap[i].key;463 $sel.attr("name", elName);464 };465 this.UpdateSubElement();466 };467 468 this.UpdateSubElement = function() {469 var fullField = this.GetFullField();470 471 //timeslice472 for(var i = 0; i < this.timesliceArray.length; i++) {473 var timeslice = this.timesliceArray[i];474 timeslice.SetPrefixField(fullField);475 timeslice.SetFieldIndex(i);476 timeslice.UpdateElementName();477 }478 };479 /* Field operate end */...
timeoutCallbackTest.js
Source:timeoutCallbackTest.js
1/*2 * Copyright (C) 2013 salesforce.com, inc.3 *4 * Licensed under the Apache License, Version 2.0 (the "License");5 * you may not use this file except in compliance with the License.6 * You may obtain a copy of the License at7 *8 * http://www.apache.org/licenses/LICENSE-2.09 *10 * Unless required by applicable law or agreed to in writing, software11 * distributed under the License is distributed on an "AS IS" BASIS,12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13 * See the License for the specific language governing permissions and14 * limitations under the License.15 */16({17 timeSlice : 120,18 /**19 * Just sanity check a simple usage.20 */21 testBasicWait : {22 test : function(cmp) {23 var self = this;24 var invoked = false;25 var start = new Date();26 var cb = function() {27 invoked = true;28 var delta = new Date() - start;29 $A.test.assertTrue(delta >= self.timeSlice);30 };31 var timeoutCallback = $A.util.createTimeoutCallback(cb, self.timeSlice);32 timeoutCallback();33 $A.test.addWaitFor(true, function() {34 return invoked;35 });36 }37 },38 /**39 * Make sure that repeated invocations of the timeout callback within the40 * period only cause one invocation of the user function.41 */42 testRepeatedInvoke : {43 test : function(cmp) {44 var self = this;45 var finished = false;46 var count = 0;47 var start = new Date();48 var cb = function() {49 count += 1;50 };51 var timeoutCallback = $A.util.createTimeoutCallback(cb, self.timeSlice);52 // Invoke several tijmes53 timeoutCallback();54 timeoutCallback();55 // Invoke async too.56 setTimeout(timeoutCallback, self.timeSlice/4);57 setTimeout(timeoutCallback, self.timeSlice/2);58 // Finish the test some time after we might expect an erroneous59 // second invocation.60 setTimeout(function() {61 $A.test.assertEquals(1, count,62 "callback should have only been invoked once");63 finished = true;64 }, self.timeSlice * 4);65 $A.test.addWaitFor(true, function() {66 return finished;67 });68 }69 },70 /**71 * Make sure that an invocation in the middle of the period does not extend72 * the scheduler too much. An invocation halfway through the period should73 * only delay the invocation from the start time by approximately 1/2 of the74 * period.75 */76 testPeriodReset : {77 test : function(cmp) {78 var self = this;79 var invoked = false;80 var start = new Date();81 var halfway = null;82 var cb = function() {83 invoked = true;84 var now = new Date();85 $A.test.assertTrue(halfway != null);86 var secondPeriod = now - halfway;87 $A.test.assertTrue(secondPeriod >= self.timeSlice,88 "timeout should have waited at least " + self.timeSlice);89 // window.setTimeout guarantees it will wait at least as long as90 // we ask. Historically, javascript timers have had ~15ms91 // resolution. So, allow the secondPeriod to be a bit more than92 // the original time but assume anything more than 15ms overage93 // is a scheduling bug.94 $A.test.assertTrue(secondPeriod < self.timeSlice * 1.5,95 "timeout window was unnecessarily expanded");96 };97 var timeoutCallback = $A.util.createTimeoutCallback(cb, self.timeSlice);98 timeoutCallback();99 setTimeout(function() {100 // now invoke halfway through the period.101 halfway = new Date();102 timeoutCallback();103 }, self.timeSlice / 2);104 $A.test.addWaitFor(true, function() {105 return invoked;106 });107 }108 }...
time-slices-tests.js
Source:time-slices-tests.js
1import assert from "assert";2import TimeSlices from "./../src/js/time-slices.mjs";3import TimeSlice from "./../src/js/time-slice.mjs";4describe('TimeSlices tests', function() {5 var timeSlices;6 beforeEach(function() {7 timeSlices = new TimeSlices();8 });9 it('Has one complete slice initially', function() {10 assert.deepEqual(timeSlices.getSlices(), [new TimeSlice(0, undefined)]);11 });12 it('Splits time slices correctly', function() {13 timeSlices.split(1);14 timeSlices.split(3);15 timeSlices.split(2);16 assert.deepEqual(timeSlices.getSlices(), [new TimeSlice(0, 1), new TimeSlice(2, 2), new TimeSlice(3, 3), new TimeSlice(4, undefined)]);17 });18 it('Cuts off time slices correctly', function() {19 timeSlices.split(1);20 timeSlices.split(3);21 timeSlices.cutTail(2);22 assert.deepEqual(timeSlices.getSlices(), [new TimeSlice(0, 1), new TimeSlice(2, 2)]);23 });24 it('Concatenates initial time slices correctly', function() {25 timeSlices.split(1);26 timeSlices.split(2);27 timeSlices.split(3);28 timeSlices.split(4);29 timeSlices.concatHead(3);30 assert.deepEqual(timeSlices.getSlices(), [new TimeSlice(0, 3), new TimeSlice(4, 4), new TimeSlice(5, undefined)]);31 });32 it('Gets valid time slices correctly', function() {33 timeSlices.split(1);34 timeSlices.split(2);35 timeSlices.split(3);36 timeSlices.split(4);37 assert.deepEqual(timeSlices.getValidSlices(3), [new TimeSlice(3, 3), new TimeSlice(4, 4), new TimeSlice(5, undefined)]);38 });39 it('Merges time slices correctly', function() {40 var otherTimeSlices = new TimeSlices();41 timeSlices.split(1);42 timeSlices.split(3);43 timeSlices.split(5);44 otherTimeSlices.split(2);45 otherTimeSlices.split(4);46 otherTimeSlices.split(6);47 timeSlices.merge(otherTimeSlices);48 assert.deepEqual(timeSlices.getSlices(), [new TimeSlice(0, 1), new TimeSlice(2, 2), new TimeSlice(3, 3), new TimeSlice(4, 4), new TimeSlice(5, 5), new TimeSlice(6, 6), new TimeSlice(7, undefined)]);49 });50 it('Merge after merges time slices correctly', function() {51 var otherTimeSlices = new TimeSlices();52 timeSlices.cutTail(1);53 timeSlices.split(3);54 timeSlices.split(5);55 otherTimeSlices.split(2);56 otherTimeSlices.split(4);57 otherTimeSlices.split(6);58 otherTimeSlices.split(7);59 timeSlices.mergeAfter(otherTimeSlices);60 assert.deepEqual(timeSlices.getSlices(), [new TimeSlice(0, 1), new TimeSlice(2, 3), new TimeSlice(4, 5), new TimeSlice(6, 6), new TimeSlice(7, 7), new TimeSlice(8, undefined)]);61 });...
xviz-stream-buffer.bench.js
Source:xviz-stream-buffer.bench.js
1// Copyright (c) 2019 Uber Technologies, Inc.2//3// Licensed under the Apache License, Version 2.0 (the "License");4// you may not use this file except in compliance with the License.5// You may obtain a copy of the License at6//7// http://www.apache.org/licenses/LICENSE-2.08//9// Unless required by applicable law or agreed to in writing, software10// distributed under the License is distributed on an "AS IS" BASIS,11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12// See the License for the specific language governing permissions and13// limitations under the License.14/* eslint-disable camelcase */15import {XVIZStreamBuffer} from '@xviz/parser';16export default function xvizBench(bench) {17 return bench18 .group('XVIZ STREAM BUFFER')19 .add('XVIZStreamBuffer#insert 1000 frames into unlimited buffer', () => {20 const timeslice = generateTimeslice(50);21 let timestamp = 1;22 const TIMESLICE_COUNT = 1000;23 const streamBuffer = new XVIZStreamBuffer();24 for (let i = 0; i < TIMESLICE_COUNT; i++) {25 streamBuffer.insert({...timeslice, timestamp});26 timestamp++;27 }28 })29 .add('XVIZStreamBuffer#insert 1000 frames into limited buffer', () => {30 const timeslice = generateTimeslice(50);31 let timestamp = 1;32 const TIMESLICE_COUNT = 1000;33 const streamBuffer = new XVIZStreamBuffer({startOffset: -150, endOffset: 10});34 for (let i = 0; i < TIMESLICE_COUNT; i++) {35 streamBuffer.setCurrentTime(timestamp);36 streamBuffer.insert({...timeslice, timestamp});37 timestamp++;38 }39 })40 .add('XVIZStreamBuffer#insert 1000 frames into limited buffer + getStreams', () => {41 const timeslice = generateTimeslice(50);42 let timestamp = 1;43 const TIMESLICE_COUNT = 1000;44 const streamBuffer = new XVIZStreamBuffer({startOffset: -150, endOffset: 10});45 for (let i = 0; i < TIMESLICE_COUNT; i++) {46 streamBuffer.setCurrentTime(timestamp);47 streamBuffer.insert({...timeslice, timestamp});48 streamBuffer.getStreams();49 timestamp++;50 }51 });52}53function generateTimeslice(streamsCount) {54 const streams = {};55 for (let i = 0; i < streamsCount; i++) {56 const streamName = `stream-${i}`;57 streams[streamName] = {};58 }59 return {60 vehiclePose: {longitude: 0, latitude: 0, x: 0, y: 0, z: 0},61 streams62 };...
quartile.js
Source:quartile.js
1// Extra functions related to drawing quartile regions on the timeseries chart2function quartileInit(svg) {3 var quartilePlot = svg.select("g.quartiles");4// .attr("clip-path", "url(#plotclip)")5 $data.dispatch.on("quartileSelect.timeseries", function() {6 if ($data.selectedQuartile == "arithmetic")7 data = $data.timeslices.map(function(timeslice) {8 return { "y0": timeslice.mean + (z75 * timeslice.stddev),9 "y1": timeslice.mean - (z75 * timeslice.stddev),10 "mid": timeslice.mean,11 "style": "arithmetic"}12 });13 else if ($data.selectedQuartile == "geometric") 14 data = $data.timeslices.map(function(timeslice) {15 return { "y0": timeslice.g_mean * Math.pow(timeslice.g_stddev, z75),16 "y1": timeslice.g_mean / Math.pow(timeslice.g_stddev, z75),17 "mid": timeslice.g_mean,18 "style": "geometric"}19 });20 else data = []21 quartilePlot.selectAll("rect").data(data).call(boxplot);22 });23 function boxplot(v) {24 var obj = svg.node(),25 x = obj.xScale,26 y = obj.yScale,27 numCols = Math.floor($data.density * ($data.width / $data.height)),28 colWidth = $data.width / (numCols - 1 );29 v.enter()30 .append("rect")31 v32 .attr("transform", function(d, i) {33 return "translate(" + (( i - 0.5) * colWidth) + ","+y(d.y0)+")";34 })35 .attr("class", $data.selectedQuartile)36 .attr("width", colWidth - 1)37 .attr("height", function(d) { return y(d.y1) - y(d.y0) })38 v.exit()39 .remove();40 }...
Using AI Code Generation
1var Mocha = require('mocha'),2 fs = require('fs'),3 path = require('path');4var mocha = new Mocha();5var testDir = 'test';6fs.readdirSync(testDir).filter(function(file){7 return file.substr(-3) === '.js';8}).forEach(function(file){9 mocha.addFile(10 path.join(testDir, file)11 );12});13mocha.run(function(failures){14 process.on('exit', function () {15 });16});
Using AI Code Generation
1var Mocha = require('mocha');2var mocha = new Mocha();3mocha.addFile('test.js');4mocha.run(function(failures){5 process.on('exit', function () {6 });7});8var Mocha = require('mocha');9var mocha = new Mocha();10mocha.addFile('test.js');11mocha.run(function(failures){12 process.on('exit', function () {13 });14});15var Mocha = require('mocha');16var mocha = new Mocha();17mocha.addFile('test.js');18mocha.run(function(failures){19 process.on('exit', function () {20 });21});22var Mocha = require('mocha');23var mocha = new Mocha();24mocha.addFile('test.js');25mocha.run(function(failures){26 process.on('exit', function () {27 });28});29var Mocha = require('mocha');30var mocha = new Mocha();31mocha.addFile('test.js');32mocha.run(function(failures){33 process.on('exit', function () {34 });35});36var Mocha = require('mocha');37var mocha = new Mocha();38mocha.addFile('test.js');39mocha.run(function(failures){40 process.on('exit', function () {41 });42});43var Mocha = require('mocha');
Using AI Code Generation
1var Mocha = require('mocha'),2 fs = require('fs'),3 path = require('path');4var mocha = new Mocha;5var testDir = 'test';6fs.readdirSync(testDir).filter(function(file){7 return file.substr(-3) === '.js';8}).forEach(function(file){9 mocha.addFile(10 path.join(testDir, file)11 );12});13mocha.run(function(failures){14 process.on('exit', function () {15 });16});17{18 "scripts": {19 },20 "devDependencies": {21 }22}
Using AI Code Generation
1describe('Array', function() {2 describe('#indexOf()', function() {3 it('should return -1 when the value is not present', function(done) {4 this.timeout(10000);5 var i = 0;6 var interval = setInterval(function() {7 i++;8 if (i === 100) {9 clearInterval(interval);10 done();11 }12 }, 100);13 });14 });15});
Using AI Code Generation
1var slice = Array.prototype.slice;2function timeslice(fn) {3 return function() {4 var args = slice.call(arguments);5 var done = args.pop();6 fn.apply(this, args.concat([done]));7 };8}9var slice = Array.prototype.slice;10function timeslice(fn) {11 return function() {12 var args = slice.call(arguments);13 var done = args.pop();14 fn.apply(this, args.concat([done]));15 };16}17describe('test', function() {18 it('should pass', function(done) {19 done();20 });21 it('should pass', timeslice(function(done) {22 setTimeout(done, 100);23 }));24 it('should pass', function(done) {25 setTimeout(done, 100);26 });27});28var slice = Array.prototype.slice;29function timeslice(fn) {30 return function() {31 var args = slice.call(arguments);32 var done = args.pop();33 fn.apply(this, args.concat([done]));34 };35}36describe('test', function() {37 it('should pass', function(done) {38 done();39 });40 it('should pass', timeslice(function(done) {41 setTimeout(done, 100);42 }));43 it('should pass', function(done) {44 setTimeout(done, 100);45 });46});47var slice = Array.prototype.slice;48function timeslice(fn) {49 return function() {50 var args = slice.call(arguments);51 var done = args.pop();52 fn.apply(this, args.concat([done]));53 };54}55describe('test', function() {56 it('should pass', function(done) {57 done();58 });59 it('should pass', timeslice(function(done) {60 setTimeout(done, 100);61 }));62 it('should pass', function(done) {63 setTimeout(done, 100);64 });65});66var slice = Array.prototype.slice;67function timeslice(fn) {68 return function() {69 var args = slice.call(arguments);70 var done = args.pop();71 fn.apply(this, args.concat([done]));72 };73}
Using AI Code Generation
1var mocha = require('mocha');2var fs = require('fs');3var path = require('path');4var timeslice = require('timeslice');5var assert = require('assert');6var test = new mocha({7});8test.addFile(path.join(__dirname, 'test.js'));9test.run(function(failures) {10 process.on('exit', function() {11 process.exit(failures);12 });13});14var count = 0;15var timer = setInterval(function() {16 count++;17 if (count > 10) {18 clearInterval(timer);19 }20}, 100);21timeslice(function(done) {22 assert.equal(count, 1);23 done();24});
Using AI Code Generation
1var assert = require('assert');2var request = require('request');3var fs = require('fs');4var path = require('path');5var http = require('http');6var https = require('https');7var test = require('timeslice').test;8var express = require('express');9var app = express();10var server = require('http').createServer(app);11var io = require('socket.io').listen(server);12var spawn = require('child_process').spawn;13var exec = require('child_process').exec;14var config = require('../config.js');15var exec = require('child_process').exec;16var config = require('../config.js');17var client = require('socket.io-client');18var options = {19};20var options = {21};22var user1 = {
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!