Merge pull request #1600 from nasa/imagery-updates

[Imagery] Update metadata for images
This commit is contained in:
Victor Woeltjen 2017-06-13 16:30:33 -05:00 committed by GitHub
commit e75d1f62ec
13 changed files with 267 additions and 433 deletions

1
API.md
View File

@ -372,6 +372,7 @@ Known hints:
* `domain`: Indicates that the value represents the "input" of a datum. Values with a `domain` hint will be used for the x-axis of a plot, and tables will render columns for these values first.
* `range`: Indicates that the value is the "output" of a datum. Values with a `range` hint will be used as the y-axis on a plot, and tables will render columns for these values after the `domain` values.
* `image`: Indicates that the value may be interpreted as the URL to an image file, in which case appropriate views will be made available.
##### The Time Conductor and Telemetry

View File

@ -1,80 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
define([
"./src/ImageTelemetryProvider",
'legacyRegistry'
], function (
ImageTelemetryProvider,
legacyRegistry
) {
"use strict";
legacyRegistry.register("example/imagery", {
"name": "Imagery",
"description": "Example of a component that produces image telemetry.",
"extensions": {
"components": [
{
"implementation": ImageTelemetryProvider,
"type": "provider",
"provides": "telemetryService",
"depends": [
"$q",
"$timeout"
]
}
],
"types": [
{
"key": "imagery",
"name": "Example Imagery",
"cssClass": "icon-image",
"features": "creation",
"description": "For development use. Creates example imagery data that mimics a live imagery stream.",
"priority": 10,
"model": {
"telemetry": {}
},
"telemetry": {
"source": "imagery",
"domains": [
{
"name": "Time",
"key": "time",
"format": "utc"
}
],
"ranges": [
{
"name": "Image",
"key": "url",
"format": "imageUrl"
}
]
}
}
]
}
});
});

View File

@ -19,18 +19,15 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise*/
/**
* Module defining ImageTelemetry. Created by vwoeltje on 06/22/15.
*/
define(
[],
function () {
"use strict";
define([
var firstObservedTime = Date.now(),
images = [
], function(
) {
function ImageryPlugin() {
var IMAGE_SAMPLES = [
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18731.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18732.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18733.jpg",
@ -49,33 +46,67 @@ define(
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18746.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18747.jpg",
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18748.jpg"
];
].map(function (url, index) {
return {
timestamp: firstObservedTime + 1000 * index,
url: url
};
return function install(openmct) {
openmct.types.addType('example.imagery', {
key: 'example.imagery',
name: 'Example Imagery',
cssClass: 'icon-image',
description: 'For development use. Creates example imagery ' +
'data that mimics a live imagery stream.',
creatable: true,
initialize: function (object) {
object.telemetry = {
values: [
{
name: 'Time',
key: 'utc',
format: 'utc',
hints: {
domain: 1
}
},
{
name: 'Image',
key: 'url',
format: 'image',
hints: {
image: 1
}
}
]
}
}
});
openmct.telemetry.addProvider({
supportsSubscribe: function (domainObject) {
return domainObject.type === 'example.imagery';
},
subscribe: function (domainObject, callback) {
var index = 0,
end = IMAGE_SAMPLES.length,
interval;
/**
*
* @constructor
*/
function ImageTelemetry() {
return {
getPointCount: function () {
return Math.floor((Date.now() - firstObservedTime) / 1000);
},
getDomainValue: function (i, domain) {
return images[i % images.length].timestamp;
},
getRangeValue: function (i, range) {
return images[i % images.length].url;
interval = setInterval(function () {
if (index >= end) {
index = 0;
}
callback({
utc: Date.now(),
url: IMAGE_SAMPLES[index]
});
index += 1;
}, 1000);
return function (interval) {
clearInterval(interval);
};
}
};
}
return ImageTelemetry;
});
};
}
);
return ImageryPlugin;
});

View File

@ -1,115 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise*/
/**
* Module defining ImageTelemetryProvider. Created by vwoeltje on 06/22/15.
*/
define(
["./ImageTelemetry"],
function (ImageTelemetry) {
"use strict";
/**
*
* @constructor
*/
function ImageTelemetryProvider($q, $timeout) {
var subscriptions = [];
//
function matchesSource(request) {
return request.source === "imagery";
}
// Used internally; this will be repacked by doPackage
function generateData(request) {
return {
key: request.key,
telemetry: new ImageTelemetry()
};
}
//
function doPackage(results) {
var packaged = {};
results.forEach(function (result) {
packaged[result.key] = result.telemetry;
});
// Format as expected (sources -> keys -> telemetry)
return { imagery: packaged };
}
function requestTelemetry(requests) {
return $timeout(function () {
return doPackage(requests.filter(matchesSource).map(generateData));
}, 0);
}
function handleSubscriptions() {
subscriptions.forEach(function (subscription) {
var requests = subscription.requests;
subscription.callback(doPackage(
requests.filter(matchesSource).map(generateData)
));
});
}
function startGenerating() {
$timeout(function () {
handleSubscriptions();
if (subscriptions.length > 0) {
startGenerating();
}
}, 1000);
}
function subscribe(callback, requests) {
var subscription = {
callback: callback,
requests: requests
};
function unsubscribe() {
subscriptions = subscriptions.filter(function (s) {
return s !== subscription;
});
}
subscriptions.push(subscription);
if (subscriptions.length === 1) {
startGenerating();
}
return unsubscribe;
}
return {
requestTelemetry: requestTelemetry,
subscribe: subscribe
};
}
return ImageTelemetryProvider;
}
);

View File

@ -32,7 +32,6 @@
require(['openmct'], function (openmct) {
[
'example/imagery',
'example/eventGenerator',
'example/styleguide'
].forEach(
@ -42,6 +41,7 @@
openmct.install(openmct.plugins.LocalStorage());
openmct.install(openmct.plugins.Espresso());
openmct.install(openmct.plugins.Generator());
openmct.install(openmct.plugins.ExampleImagery());
openmct.install(openmct.plugins.UTCTimeSystem());
openmct.time.clock('local', {start: -THIRTY_MINUTES, end: 0});
openmct.time.timeSystem('utc');

View File

@ -53,7 +53,10 @@ define([
"policies": [
{
"category": "view",
"implementation": ImageryViewPolicy
"implementation": ImageryViewPolicy,
"depends": [
"openmct"
]
}
],
"controllers": [
@ -62,7 +65,7 @@ define([
"implementation": ImageryController,
"depends": [
"$scope",
"telemetryHandler"
"openmct"
]
}
],

View File

@ -34,10 +34,8 @@
<div class="l-image-main-controlbar flex-elem l-flex-row">
<div class="left flex-elem grows">
<a class="s-button show-thumbs sm hidden icon-thumbs-strip"
ng-click="showThumbsBubble = (showThumbsBubble)? false:true"></a>
<span class="l-timezone">{{imagery.getZone()}}</span>
ng-click="showThumbsBubble = (showThumbsBubble) ? false:true"></a>
<span class="l-time">{{imagery.getTime()}}</span>
<span class="l-date">{{imagery.getDate()}}</span>
</div>
<div class="right flex-elem">
<a class="s-button pause-play"

View File

@ -28,74 +28,74 @@ define(
['moment'],
function (moment) {
var DATE_FORMAT = "YYYY-MM-DD",
TIME_FORMAT = "HH:mm:ss.SSS";
/**
* Controller for the "Imagery" view of a domain object which
* provides image telemetry.
* @constructor
* @memberof platform/features/imagery
*/
function ImageryController($scope, telemetryHandler) {
var self = this;
function ImageryController($scope, openmct) {
this.$scope = $scope;
this.openmct = openmct;
this.date = "";
this.time = "";
this.zone = "";
this.imageUrl = "";
function releaseSubscription() {
if (self.handle) {
self.handle.unsubscribe();
self.handle = undefined;
}
}
function updateValuesCallback() {
return self.updateValues();
}
// Create a new subscription; telemetrySubscriber gets
// to do the meaningful work here.
function subscribe(domainObject) {
releaseSubscription();
self.date = "";
self.time = "";
self.zone = "";
self.imageUrl = "";
self.handle = domainObject && telemetryHandler.handle(
domainObject,
updateValuesCallback,
true // Lossless
);
}
$scope.filters = {
this.$scope.filters = {
brightness: 100,
contrast: 100
};
this.subscribe = this.subscribe.bind(this);
this.stopListening = this.stopListening.bind(this);
this.updateValues = this.updateValues.bind(this);
// Subscribe to telemetry when a domain object becomes available
$scope.$watch('domainObject', subscribe);
this.subscribe(this.$scope.domainObject);
// Unsubscribe when the plot is destroyed
$scope.$on("$destroy", releaseSubscription);
this.$scope.$on("$destroy", this.stopListening);
}
// Update displayable values to reflect latest image telemetry
ImageryController.prototype.updateValues = function () {
var imageObject =
this.handle && this.handle.getTelemetryObjects()[0],
timestamp,
m;
if (imageObject && !this.isPaused) {
timestamp = this.handle.getDomainValue(imageObject);
m = timestamp !== undefined ?
moment.utc(timestamp) :
undefined;
this.date = m ? m.format(DATE_FORMAT) : "";
this.time = m ? m.format(TIME_FORMAT) : "";
this.zone = m ? "UTC" : "";
this.imageUrl = this.handle.getRangeValue(imageObject);
ImageryController.prototype.subscribe = function (domainObject) {
this.date = "";
this.imageUrl = "";
this.openmct.objects.get(domainObject.getId())
.then(function (object) {
this.domainObject = object;
var metadata = this.openmct
.telemetry
.getMetadata(this.domainObject);
var timeKey = this.openmct.time.timeSystem().key;
this.timeFormat = this.openmct
.telemetry
.getValueFormatter(metadata.value(timeKey));
this.imageFormat = this.openmct
.telemetry
.getValueFormatter(metadata.valuesForHints(['image'])[0]);
this.unsubscribe = this.openmct.telemetry
.subscribe(this.domainObject, this.updateValues);
}.bind(this));
};
ImageryController.prototype.stopListening = function () {
if (this.unsubscribe) {
this.unsubscribe();
delete this.unsubscribe;
}
};
// Update displayable values to reflect latest image telemetry
ImageryController.prototype.updateValues = function (datum) {
if (this.isPaused) {
this.nextDatum = datum;
return;
}
this.time = this.timeFormat.format(datum);
this.imageUrl = this.imageFormat.format(datum);
};
/**
* Get the time portion (hours, minutes, seconds) of the
* timestamp associated with the incoming image telemetry.
@ -105,25 +105,6 @@ define(
return this.time;
};
/**
* Get the date portion (month, year) of the
* timestamp associated with the incoming image telemetry.
* @returns {string} the date
*/
ImageryController.prototype.getDate = function () {
return this.date;
};
/**
* Get the time zone for the displayed time/date corresponding
* to the timestamp associated with the incoming image
* telemetry.
* @returns {string} the time
*/
ImageryController.prototype.getZone = function () {
return this.zone;
};
/**
* Get the URL of the image telemetry to display.
* @returns {string} URL for telemetry image
@ -141,8 +122,10 @@ define(
ImageryController.prototype.paused = function (state) {
if (arguments.length > 0 && state !== this.isPaused) {
this.isPaused = state;
// Switch to latest image
this.updateValues();
if (this.nextDatum) {
this.updateValues(this.nextDatum);
delete this.nextDatum;
}
}
return this.isPaused;
};

View File

@ -20,39 +20,40 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
function () {
/**
* Policy preventing the Imagery view from being made available for
* domain objects which do not have associated image telemetry.
* @implements {Policy.<View, DomainObject>}
* @constructor
*/
function ImageryViewPolicy() {
}
function hasImageTelemetry(domainObject) {
var telemetry = domainObject &&
domainObject.getCapability('telemetry'),
metadata = telemetry ? telemetry.getMetadata() : {},
ranges = metadata.ranges || [];
return ranges.some(function (range) {
return range.format === 'imageUrl' ||
range.format === 'image';
});
}
ImageryViewPolicy.prototype.allow = function (view, domainObject) {
if (view.key === 'imagery') {
return hasImageTelemetry(domainObject);
}
return true;
};
return ImageryViewPolicy;
define([
'../../../../../src/api/objects/object-utils'
], function (
objectUtils
) {
/**
* Policy preventing the Imagery view from being made available for
* domain objects which do not have associated image telemetry.
* @implements {Policy.<View, DomainObject>}
* @constructor
*/
function ImageryViewPolicy(openmct) {
this.openmct = openmct;
}
);
ImageryViewPolicy.prototype.hasImageTelemetry = function (domainObject) {
var newDO = objectUtils.toNewFormat(
domainObject.getModel(),
domainObject.getId()
);
var metadata = this.openmct.telemetry.getMetadata(newDO);
var values = metadata.valuesForHints(['image']);
return values.length >= 1;
};
ImageryViewPolicy.prototype.allow = function (view, domainObject) {
if (view.key === 'imagery') {
return this.hasImageTelemetry(domainObject);
}
return true;
};
return ImageryViewPolicy;
});

View File

@ -25,60 +25,92 @@ define(
function (ImageryController) {
describe("The Imagery controller", function () {
var mockScope,
mockTelemetryHandler,
mockHandle,
mockDomainObject,
var $scope,
openmct,
oldDomainObject,
newDomainObject,
unsubscribe,
callback,
metadata,
prefix,
controller;
function invokeWatch(expr, value) {
mockScope.$watch.calls.forEach(function (call) {
if (call.args[0] === expr) {
call.args[1](value);
}
});
}
beforeEach(function () {
mockScope = jasmine.createSpyObj('$scope', ['$on', '$watch']);
mockTelemetryHandler = jasmine.createSpyObj(
'telemetryHandler',
['handle']
);
mockHandle = jasmine.createSpyObj(
'handle',
[
'getDomainValue',
'getRangeValue',
'getTelemetryObjects',
'unsubscribe'
]
);
mockDomainObject = jasmine.createSpyObj(
$scope = jasmine.createSpyObj('$scope', ['$on', '$watch']);
oldDomainObject = jasmine.createSpyObj(
'domainObject',
['getId', 'getModel', 'getCapability']
['getId']
);
newDomainObject = { name: 'foo' };
mockTelemetryHandler.handle.andReturn(mockHandle);
mockHandle.getTelemetryObjects.andReturn([mockDomainObject]);
oldDomainObject.getId.andReturn('testID');
openmct = {
objects: jasmine.createSpyObj('objectAPI', [
'get'
]),
time: jasmine.createSpyObj('timeAPI', [
'timeSystem'
]),
telemetry: jasmine.createSpyObj('telemetryAPI', [
'subscribe',
'getValueFormatter',
'getMetadata'
])
};
metadata = jasmine.createSpyObj('metadata', [
'value',
'valuesForHints'
]);
prefix = "formatted ";
unsubscribe = jasmine.createSpy('unsubscribe');
openmct.telemetry.subscribe.andReturn(unsubscribe);
openmct.time.timeSystem.andReturn({
key: 'testKey'
});
$scope.domainObject = oldDomainObject;
openmct.objects.get.andReturn(Promise.resolve(newDomainObject));
openmct.telemetry.getMetadata.andReturn(metadata);
openmct.telemetry.getValueFormatter.andCallFake(function (property) {
var formatter =
jasmine.createSpyObj("formatter-" + property, ['format']);
var isTime = (property === "timestamp");
formatter.format.andCallFake(function (datum) {
return (isTime ? prefix : "") + datum[property];
});
return formatter;
});
metadata.value.andReturn("timestamp");
metadata.valuesForHints.andReturn(["value"]);
controller = new ImageryController(
mockScope,
mockTelemetryHandler
controller = new ImageryController($scope, openmct);
waitsFor(function () {
return openmct.telemetry.subscribe.calls.length > 0;
}, 100);
runs(function () {
callback =
openmct.telemetry.subscribe.mostRecentCall.args[1];
});
});
it("subscribes to telemetry", function () {
expect(openmct.telemetry.subscribe).toHaveBeenCalledWith(
newDomainObject,
jasmine.any(Function)
);
invokeWatch('domainObject', mockDomainObject);
});
it("unsubscribes when scope is destroyed", function () {
expect(mockHandle.unsubscribe).not.toHaveBeenCalled();
expect(unsubscribe).not.toHaveBeenCalled();
// Find the $destroy listener and call it
mockScope.$on.calls.forEach(function (call) {
$scope.$on.calls.forEach(function (call) {
if (call.args[0] === '$destroy') {
call.args[1]();
}
});
expect(mockHandle.unsubscribe).toHaveBeenCalled();
expect(unsubscribe).toHaveBeenCalled();
});
it("exposes the latest telemetry values", function () {
@ -88,24 +120,15 @@ define(
nextTimestamp = 1434600259456, // 4:05.456
nextUrl = "some/other/url";
mockHandle.getDomainValue.andReturn(testTimestamp);
mockHandle.getRangeValue.andReturn(testUrl);
// Call back with telemetry data
callback({ timestamp: testTimestamp, value: testUrl });
// Call the subscription listener
mockTelemetryHandler.handle.mostRecentCall.args[1]();
expect(controller.getTime()).toEqual("04:04:18.123");
expect(controller.getDate()).toEqual("2015-06-18");
expect(controller.getZone()).toEqual("UTC");
expect(controller.getTime()).toEqual(prefix + testTimestamp);
expect(controller.getImageUrl()).toEqual(testUrl);
mockHandle.getDomainValue.andReturn(nextTimestamp);
mockHandle.getRangeValue.andReturn(nextUrl);
mockTelemetryHandler.handle.mostRecentCall.args[1]();
callback({ timestamp: nextTimestamp, value: nextUrl });
expect(controller.getTime()).toEqual("04:04:19.456");
expect(controller.getDate()).toEqual("2015-06-18");
expect(controller.getZone()).toEqual("UTC");
expect(controller.getTime()).toEqual(prefix + nextTimestamp);
expect(controller.getImageUrl()).toEqual(nextUrl);
});
@ -116,46 +139,26 @@ define(
nextTimestamp = 1434600259456, // 4:05.456
nextUrl = "some/other/url";
// As above, but pause in between. Expect details
// not to change this time
// Call back with telemetry data
callback({ timestamp: testTimestamp, value: testUrl });
mockHandle.getDomainValue.andReturn(testTimestamp);
mockHandle.getRangeValue.andReturn(testUrl);
// Call the subscription listener
mockTelemetryHandler.handle.mostRecentCall.args[1]();
expect(controller.getTime()).toEqual("04:04:18.123");
expect(controller.getDate()).toEqual("2015-06-18");
expect(controller.getZone()).toEqual("UTC");
expect(controller.getTime()).toEqual(prefix + testTimestamp);
expect(controller.getImageUrl()).toEqual(testUrl);
expect(controller.paused()).toBeFalsy();
controller.paused(true); // Pause!
expect(controller.paused()).toBeTruthy();
mockHandle.getDomainValue.andReturn(nextTimestamp);
mockHandle.getRangeValue.andReturn(nextUrl);
mockTelemetryHandler.handle.mostRecentCall.args[1]();
callback({ timestamp: nextTimestamp, value: nextUrl });
expect(controller.getTime()).toEqual("04:04:18.123");
expect(controller.getDate()).toEqual("2015-06-18");
expect(controller.getZone()).toEqual("UTC");
expect(controller.getTime()).toEqual(prefix + testTimestamp);
expect(controller.getImageUrl()).toEqual(testUrl);
});
it("initially shows an empty string for date/time", function () {
// Call the subscription listener while domain/range
// values are still undefined
mockHandle.getDomainValue.andReturn(undefined);
mockHandle.getRangeValue.andReturn(undefined);
mockTelemetryHandler.handle.mostRecentCall.args[1]();
// Should have empty strings for date/time/zone
// Do not invoke callback...
expect(controller.getTime()).toEqual("");
expect(controller.getDate()).toEqual("");
expect(controller.getZone()).toEqual("");
expect(controller.getImageUrl()).toBeUndefined();
expect(controller.getImageUrl()).toEqual("");
});
});
}

View File

@ -26,14 +26,17 @@ define(
describe("Imagery view policy", function () {
var testView,
openmct,
mockDomainObject,
mockTelemetry,
testMetadata,
mockMetadata,
policy;
beforeEach(function () {
testView = { key: "imagery" };
testMetadata = {};
mockMetadata = jasmine.createSpyObj('metadata', [
"valuesForHints"
]);
mockDomainObject = jasmine.createSpyObj(
'domainObject',
['getId', 'getModel', 'getCapability']
@ -45,30 +48,33 @@ define(
mockDomainObject.getCapability.andCallFake(function (c) {
return c === 'telemetry' ? mockTelemetry : undefined;
});
mockTelemetry.getMetadata.andReturn(testMetadata);
mockDomainObject.getId.andReturn("some-id");
mockDomainObject.getModel.andReturn({ name: "foo" });
mockTelemetry.getMetadata.andReturn(mockMetadata);
mockMetadata.valuesForHints.andReturn(["bar"]);
policy = new ImageryViewPolicy();
openmct = { telemetry: mockTelemetry };
policy = new ImageryViewPolicy(openmct);
});
it("checks for hints indicating image telemetry", function () {
policy.allow(testView, mockDomainObject);
expect(mockMetadata.valuesForHints)
.toHaveBeenCalledWith(["image"]);
});
it("allows the imagery view for domain objects with image telemetry", function () {
testMetadata.ranges = [{ key: "foo", format: "imageUrl" }];
expect(policy.allow(testView, mockDomainObject)).toBeTruthy();
});
it("disallows the imagery view for domain objects without image telemetry", function () {
testMetadata.ranges = [{ key: "foo", format: "somethingElse" }];
expect(policy.allow(testView, mockDomainObject)).toBeFalsy();
});
it("disallows the imagery view for domain objects without telemetry", function () {
testMetadata.ranges = [{ key: "foo", format: "imageUrl" }];
mockDomainObject.getCapability.andReturn(undefined);
mockMetadata.valuesForHints.andReturn([]);
expect(policy.allow(testView, mockDomainObject)).toBeFalsy();
});
it("allows other views", function () {
testView.key = "somethingElse";
testMetadata.ranges = [{ key: "foo", format: "somethingElse" }];
expect(policy.allow(testView, mockDomainObject)).toBeTruthy();
});

View File

@ -34,7 +34,6 @@ define([
'../example/extensions/bundle',
'../example/forms/bundle',
'../example/identity/bundle',
'../example/imagery/bundle',
'../example/mobile/bundle',
'../example/msl/bundle',
'../example/notifications/bundle',

View File

@ -25,13 +25,15 @@ define([
'./utcTimeSystem/plugin',
'../../example/generator/plugin',
'../../platform/features/autoflow/plugin',
'./timeConductor/plugin'
'./timeConductor/plugin',
'../../example/imagery/plugin'
], function (
_,
UTCTimeSystem,
GeneratorPlugin,
AutoflowPlugin,
TimeConductorPlugin
TimeConductorPlugin,
ExampleImagery
) {
var bundleMap = {
CouchDB: 'platform/persistence/couch',
@ -113,5 +115,7 @@ define([
return GeneratorPlugin;
};
plugins.ExampleImagery = ExampleImagery;
return plugins;
});