Multiple Bing Map Pushpins from SQL not showing in Firefox & Chrome but do in IE - sql

I'm displaying a Bing Map (v7) in my Webmatrix2 website with a series of pushpins & infoboxes drawn from a SQL Express database using a JSON enquiry.
While the maps appears in all 3 browsers I'm testing (IE, FF & Chrome) the pushpins are sometimes not showing in FF & Chrome, particularly if I refresh with Cntrl+F5
This is my first JSON and Bing Maps app so expect there's a few mistakes.
Any suggestions on how to improve the code and get display consistency?
#{
Layout = "~/_MapLayout.cshtml";
}
<script type="text/javascript" src="~/Scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
<link rel="StyleSheet" href="infoboxStyles.css" type="text/css">
<script type="text/javascript">
var map = null;
var pinLayer, pinInfobox;
var mouseover;
var pushpinFrameHTML = '<div class="infobox"><a class="infobox_close" href="javascript:closeInfobox()"><img src="/Images/close2.jpg" /></a><div class="infobox_content">{content}</div></div><div class="infobox_pointer"><img src="images/pointer_shadow.png"></div>';
var pinLayer = new Microsoft.Maps.EntityCollection();
var infoboxLayer = new Microsoft.Maps.EntityCollection();
function getMap() {
map = new Microsoft.Maps.Map(document.getElementById('map'), {
credentials: "my-key",
zoom: 4,
center: new Microsoft.Maps.Location(-25, 135),
mapTypeId: Microsoft.Maps.MapTypeId.road
});
pinInfobox = new Microsoft.Maps.Infobox(new Microsoft.Maps.Location(0, 0), { visible: false });
AddData();
}
$(function AddData() {
$.getJSON('/ListSchools', function (data) {
var schools = data;
$.each(schools, function (index, school) {
for (var i = 0; i < schools.length; i++) {
var pinLocation = new Microsoft.Maps.Location(school.SchoolLat, school.SchoolLon);
var NewPin = new Microsoft.Maps.Pushpin(pinLocation);
NewPin.title = school.SchoolName;
NewPin.description = "-- Learn More --";
pinLayer.push(NewPin); //add pushpin to pinLayer
Microsoft.Maps.Events.addHandler(NewPin, 'mouseover', displayInfobox);
}
});
infoboxLayer.push(pinInfobox);
map.entities.push(pinLayer);
map.entities.push(infoboxLayer);
});
})
function displayInfobox(e) {
if (e.targetType == "pushpin") {
var pin = e.target;
var html = "<span class='infobox_title'>" + pin.title + "</span><br/>" + pin.description;
pinInfobox.setOptions({
visible: true,
offset: new Microsoft.Maps.Point(-33, 20),
htmlContent: pushpinFrameHTML.replace('{content}', html)
});
//set location of infobox
pinInfobox.setLocation(pin.getLocation());
}
}
function closeInfobox() {
pinInfobox.setOptions({ visible: false });
}
function getCurrentLocation() {
var geoLocationProvider = new Microsoft.Maps.GeoLocationProvider(map);
geoLocationProvider.getCurrentPosition();
}
</script>
<body onload="getMap();">
<div id="map" style="position:relative; width:800px; height:600px;"></div>
<div>
<input type="button" value="Find Nearest Schools" onclick="getCurrentLocation();" />
</div>
</body>
The JSON file is simply
#{
var db = Database.Open("StarterSite");
var sql = #"SELECT * FROM Schools WHERE SchoolLon != ' ' AND SchoolLon != 'null' ";
var data = db.Query(sql);
Json.Write(data, Response.Output);
}

Add your pinLayer, infobox, and infoboxLayer before calling the AddData function and see if that makes a difference. Also verify that school.SchoolLat and school.SchoolLon are numbers and not a string version of a number. If they are a string, then use parseFloat to turn them into a number. Other than that everything looks fine.

Related

Using Self-Segmentation javascript of Mediapipe to pass user selfie as a texture on Networked-Aframe for multiplaying experiences

Well my target is to make a multiplaying 3D environment where the persons are represented by cubes that have as textures their selfie without the background. It is a kind of cheap virtual production without chroma key background. The background is removed with MediaPipe Selfie-Segmentation. The issue is that instead of having the other player texture on the cube (P1 should see P2, and P2 should see P1, each one sees his selfie. This means that P1 sees P1 and P2 sees P2 which is bad.
Live demo: https://vrodos-multiplaying.iti.gr/plain_aframe_mediapipe_testbed.html
Instructions: You should use two machines to test it Desktops, Laptops or Mobiles. Use only Chrome as Mediapipe is not working at other browsers. In case webpage jams, reload the webpage (Mediapipe is sometimes sticky). At least two machines should load the webpage in order to start the multiplaying environment.
Code:
<html>
<head>
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<!-- Selfie Segmentation of Mediapipe -->
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/#mediapipe/control_utils#0.6/control_utils.css" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/#mediapipe/camera_utils#0.3/camera_utils.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/#mediapipe/control_utils#0.6/control_utils.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/#mediapipe/drawing_utils#0.3/drawing_utils.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/#mediapipe/selfie_segmentation#0.1/selfie_segmentation.js" crossorigin="anonymous"></script>
<!-- Networked A-frame -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.slim.js"></script>
<script src="/easyrtc/easyrtc.js"></script>
<script src="https://unpkg.com/networked-aframe/dist/networked-aframe.min.js"></script>
</head>
<body>
<a-scene networked-scene="
adapter: easyrtc;
video: true;
debug: true;
connectOnLoad: true;">
<a-assets>
<template id="avatar-template">
<a-box material="alphaTest: 0.5; transparent: true; side: both;"
width="1"
height="1"
position="0 0 0" rotation="0 0 0"
networked-video-source-mediapiped></a-box>
</template>
</a-assets>
<a-entity id="player"
networked="template:#avatar-template;attachTemplateToLocal:false;"
camera wasd-controls look-controls>
</a-entity>
<a-plane position="0 -2 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4" ></a-plane>
<a-sky color="#777"></a-sky>
</a-scene>
</body>
<script>
// Networked Aframe : Register new component for streaming the Selfie-Segmentation video stream
AFRAME.registerComponent('networked-video-source-mediapiped', {
schema: {
},
dependencies: ['material'],
init: function () {
this.videoTexture = null;
this.video = null;
this.stream = null;
this._setMediaStream = this._setMediaStream.bind(this);
NAF.utils.getNetworkedEntity(this.el).then((networkedEl) => {
const ownerId = networkedEl.components.networked.data.owner;
if (ownerId) {
NAF.connection.adapter.getMediaStream(ownerId, "video")
.then(this._setMediaStream)
.catch((e) => NAF.log.error(`Error getting media stream for ${ownerId}`, e));
} else {
// Correctly configured local entity, perhaps do something here for enabling debug audio loopback
}
});
},
_setMediaStream(newStream) {
if(!this.video) {
this.setupVideo();
}
if(newStream != this.stream) {
if (this.stream) {
this._clearMediaStream();
}
if (newStream) {
this.video.srcObject = canvasElement.captureStream(30);
this.videoTexture = new THREE.VideoTexture(this.video);
this.videoTexture.format = THREE.RGBAFormat;
// Mesh to send
const mesh = this.el.getObject3D('mesh');
mesh.material.map = this.videoTexture;
mesh.material.needsUpdate = true;
}
this.stream = newStream;
}
},
_clearMediaStream() {
this.stream = null;
if (this.videoTexture) {
if (this.videoTexture.image instanceof HTMLVideoElement) {
// Note: this.videoTexture.image === this.video
const video = this.videoTexture.image;
video.pause();
video.srcObject = null;
video.load();
}
this.videoTexture.dispose();
this.videoTexture = null;
}
},
remove: function() {
this._clearMediaStream();
},
setupVideo: function() {
if (!this.video) {
const video = document.createElement('video');
video.setAttribute('autoplay', true);
video.setAttribute('playsinline', true);
video.setAttribute('muted', true);
this.video = video;
}
}
});
// ----- Mediapipe ------
const controls = window;
//const mpSelfieSegmentation = window;
const examples = {
images: [],
// {name: 'name', src: 'https://url.com'},
videos: [],
};
const fpsControl = new controls.FPS();
let activeEffect = 'background';
const controlsElement = document.createElement('control-panel');
var canvasElement = document.createElement('canvas');
canvasElement.height= 1000;
canvasElement.width = 1000;
var canvasCtx = canvasElement.getContext('2d');
// --------
function drawResults(results) {
canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);
canvasCtx.drawImage(results.segmentationMask, 0, 0, canvasElement.width, canvasElement.height);
canvasCtx.globalCompositeOperation = 'source-in';
canvasCtx.drawImage(results.image, 0, 0, canvasElement.width, canvasElement.height);
}
const selfieSegmentation = new SelfieSegmentation({
locateFile: (file) => {
console.log(file);
return `https://cdn.jsdelivr.net/npm/#mediapipe/selfie_segmentation#0.1/${file}`;
}
});
selfieSegmentation.onResults(drawResults);
// -------------
new controls
.ControlPanel(controlsElement, {
selfieMode: true,
modelSelection: 1,
effect: 'background',
})
.add([
new controls.StaticText({title: 'MediaPipe Selfie Segmentation'}),
fpsControl,
new controls.Toggle({title: 'Selfie Mode', field: 'selfieMode'}),
new controls.SourcePicker({
onSourceChanged: () => {
selfieSegmentation.reset();
},
onFrame: async (input, size) => {
const aspect = size.height / size.width;
let width, height;
if (window.innerWidth > window.innerHeight) {
height = window.innerHeight;
width = height / aspect;
} else {
width = window.innerWidth;
height = width * aspect;
}
canvasElement.width = width;
canvasElement.height = height;
await selfieSegmentation.send({image: input});
},
examples: examples
}),
new controls.Slider({
title: 'Model Selection',
field: 'modelSelection',
discrete: ['General', 'Landscape'],
}),
new controls.Slider({
title: 'Effect',
field: 'effect',
discrete: {'background': 'Background', 'mask': 'Foreground'},
}),
])
.on(x => {
const options = x;
//videoElement.classList.toggle('selfie', options.selfieMode);
activeEffect = x['effect'];
selfieSegmentation.setOptions(options);
});
</script>
</html>
Screenshot:
Here Player 1 sees Player 1 stream instead of Player 2 stream (Grrrrrr):
Well, I found it. The problem was that a MediaStream can have many video tracks. See my answer here:
https://github.com/networked-aframe/networked-aframe/issues/269
Unfortunately networked-aframe EasyRtcAdapter does not support many MediaStreams, but it is easy to add another video track and then get videotrack[1] instead of videotrack[0]. I should make a special EasyRtcAdapter to avoid having two video tracks and avoid overstressing bandwidth.

MSE WebM video with no audio

I've written a MSE video player and it's loading WebMs. These are loading well, however I have a problem with video files with no audio tracks.
I've tried changing the codec depending on if there is audio
mediaSource.addSourceBuffer(`video/webm; ${videoHasAudio(asset) ? 'codecs="vp9,vorbis"' : 'codecs="vp9"'}`)`
And I thought this was working but now isn't. How do I run silent WebMs in MSE?
I have added sample MSE project here:
https://github.com/thowfeeq178/MediaSourceExtention
checkout the example in the github
overview:
we need to add one for video and one for audio like below:
// BBB : https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd
var baseUrl = "https://dash.akamaized.net/akamai/bbb_30fps/";
var initUrl = baseUrl + "bbb_30fps_480x270_600k/bbb_30fps_480x270_600k_0.m4v";
var initAudioUrl = baseUrl + "bbb_a64k/bbb_a64k_0.m4a";
var templateUrl =
baseUrl + "bbb_30fps_480x270_600k/bbb_30fps_480x270_600k_$Number$.m4v";
var templateUrlForAudio = baseUrl + "bbb_a64k/bbb_a64k_$Number$.m4a";
var sourceBuffer;
var audioSourceBuffer;
var index = 0;
var audioIndex = 0;
var numberOfChunks = 159;
var video = document.querySelector("video");
var ms = new MediaSource();
function onPageLoad() {
console.log("page loaded ..");
if (!window.MediaSource) {
console.error("No Media Source API available");
return;
}
// making source controlled by JS using MS
video.src = window.URL.createObjectURL(ms);
ms.addEventListener("sourceopen", onMediaSourceOpen);
}
function onMediaSourceOpen() {
// create source buffer
sourceBuffer = ms.addSourceBuffer('video/mp4; codecs="avc1.4d401f"');
audioSourceBuffer = ms.addSourceBuffer('audio/mp4; codecs="mp4a.40.5"');
// when ever one segment is loaded go for next
sourceBuffer.addEventListener("updateend", nextSegment);
audioSourceBuffer.addEventListener("updateend", nextAudioSegment);
// fire init segemnts
GET(initUrl, appendToBuffer);
GET(initAudioUrl, appendToAudioBuffer);
// play
video.play();
}
// get next segment based on index and append, once everything loaded unlisten to the event
function nextSegment() {
var url = templateUrl.replace("$Number$", index);
GET(url, appendToBuffer);
index++;
if (index > numberOfChunks) {
sourceBuffer.removeEventListener("updateend", nextSegment);
}
}
// get next audio segment based on index and append, once everything loaded unlisten to the event
function nextAudioSegment() {
var audioUrl = templateUrlForAudio.replace("$Number$", audioIndex);
GET(audioUrl, appendToAudioBuffer);
audioIndex++;
if (index > numberOfChunks) {
audioSourceBuffer.removeEventListener("updateend", nextAudioSegment);
}
}
// add to existing source
function appendToBuffer(videoChunk) {
if (videoChunk) {
sourceBuffer.appendBuffer(new Uint8Array(videoChunk));
}
}
function appendToAudioBuffer(audioChunk) {
if (audioChunk) {
audioSourceBuffer.appendBuffer(new Uint8Array(audioChunk));
}
}
// just network thing
function GET(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.responseType = "arraybuffer";
xhr.onload = function(e) {
if (xhr.status != 200) {
console.warn("Unexpected status code " + xhr.status + " for " + url);
return false;
}
callback(xhr.response);
};
xhr.send();
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>MSE Demo</title>
</head>
<body onload="onPageLoad()">
<h1>MSE Demo</h1>
<div>
<video muted controls width="80%"></video>
</div>
</body>
</html>

Change avatar with vue.js without refresh?

I have this in view:
<div class="seller_image" :style="{background: 'url(' + user_credentials.avatar +')', backgroundSize: 'cover ', display: 'block'}">
</div>
In vue i have this:
setAvatar:function(x,y,w,h){
this.setAvatarLoader = true;
var data = new FormData();
this.x1 = $('#x1').val();
this.y1 = $('#y1').val();
this.w = $('#w').val();
this.h = $('#h').val();
this.x2 = $('#x2').val();
this.y2 = $('#y2').val();
data.append('avatar',this.$els.fileAvatarImage.files[0]);
data.append('x1',this.x1);
data.append('x2',this.x2);
data.append('y1',this.y1);
data.append('y2',this.y2);
data.append('w',this.w);
data.append('h',this.h);
user_id = this.user_credentials.user_id;
this.$http.post('/profile/' + user_id + '/basic_info/set_avatar',data).then(function(response){
this.avatarImageSet = false;
public_path = response.data.public_path;
url_path = response.data.url_path;
filename = response.data.filename;
this.setAvatarLoader = false;
this.basic_status = true;
this.basic_success_message = response.data.successMsg;
this.profile_image = url_path;
this.user_credentials.avatar = url_path
this.getAvatar();
$("html, body").animate({ scrollTop: 0 }, "slow");
}, function(response) {
this.setAvatarLoader = false;
$('#myModal').modal('hide');
this.getAvatar();
console.log('error');
});
},
When I refresh the page I get the avatar but in time when I set it it does not change the image.
Any suggestion?
As #AWolf said, it's difficult to guess what's the problem with your code because I can see only a part of your code base.
Another possible issue could be the url_path. If it remains the same, will never change. So, you need to append the timestamp:
this.user_credentials.avatar = url_path + '?' + Date.now()
https://jsfiddle.net/pespantelis/fy0re26m/
As mentioned in the comments, try to avoid jQuery because it's most of the time not needed and it is making things more complicated.
Please have a look at the demo below for a simple image uploader/avatar changer or at this fiddle.
The demo just opens a file picker dialog and then the returned file is used to update the displayed image. (Posting to server is not added in the demo.)
To your code:
Something like $('#x1').val() shouldn't be done with Vue.js because in Vue you're doing that model driven.
So the only source of truth is your data model and not the stuff displayed in the DOM.
Not sure what you're trying to do with the x1,y1, ... code. That's not clear from your snippet with-out the html markup.
new Vue({
el: '#app',
data() {
return {
user_credentials: {
avatar: 'https://unsplash.it/100/100'
}
}
},
methods: {
changeAvatar() {
const input = document.createElement('input');
let self = this;
input.setAttribute("type", "file");
input.addEventListener('change', function(e) {
// uploading code from this fiddle: http://jsfiddle.net/vacidesign/ja0tyj0f/
if (this.files && this.files[0]) {
var reader = new FileReader();
reader.onload = function(e) {
// image is loaded callback
self.user_credentials.avatar = e.target.result;
// here you can post the data to your backend...
};
reader.readAsDataURL(this.files[0]);
}
})
input.click(); // opening dialog
return false; // avoiding navigation
}
}
})
.seller_image {
width: 200px;
height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.js"></script>
<div id="app">
<div class="seller_image" :style="{background: 'url(' + user_credentials.avatar +')', backgroundSize: 'cover ', display: 'block'}">
</div>
<button #click="changeAvatar()">
Change
</button>
</div>

marker clusterer doesn't cluster when zoom

i'm trying to learn google api and i want to use marker clusterer. i create a database
from here and do whatever google said. my code is
`
<script src="markerclusterer.js" type="text/javascript"></script>
<script type="text/javascript">
//<![CDATA[
var customIcons = {
restaurant: {
icon: 'images/pin1.png',
shadow: 'http://labs.google.com/ridefinder/images/mm_20_shadow.png'
},
bar: {
icon: 'images/pin2.png',
shadow: 'http://labs.google.com/ridefinder/images/mm_20_shadow.png'
}
};
function initialize() {
var markers = null;
var mcmarkers = [];
var map = new google.maps.Map(document.getElementById("map"), {
center: new google.maps.LatLng(47.6145, -122.3418),
zoom: 12,
mapTypeId: 'satellite'
});
var infoWindow = new google.maps.InfoWindow;
// Change this depending on the name of your PHP file
downloadUrl("phpsqlajax_genxml.php", function(data) {
var xml = data.responseXML;
markers = xml.documentElement.getElementsByTagName("marker");
for (var i = 0; i < markers.length; i++) {
var name = markers[i].getAttribute("name");
var address = markers[i].getAttribute("address");
var type = markers[i].getAttribute("type");
var lat = parseFloat(markers[i].getAttribute("lat"));
var lng = parseFloat(markers[i].getAttribute("lng"))
var point = new google.maps.LatLng(lat, lng);
var html = "<b>" + name + "</b> <br/>" + address;
var icon = customIcons[type] || {};
var marker = new google.maps.Marker({
map: map,
position: point,
icon: icon.icon,
shadow: icon.shadow
});
mcmarkers.push(marker);
var mc = new MarkerClusterer(map, mcmarkers);
bindInfoWindow(marker, map, infoWindow, html);
}
});
}
function bindInfoWindow(marker, map, infoWindow, html) {
google.maps.event.addListener(marker, 'click', function() {
infoWindow.setContent(html);
infoWindow.open(map, marker);
});
}
function downloadUrl(url, callback) {
var request = window.ActiveXObject ?
new ActiveXObject('Microsoft.XMLHTTP') :
new XMLHttpRequest;
request.onreadystatechange = function() {
if (request.readyState == 4) {
request.onreadystatechange = doNothing;
callback(request, request.status);
}
};
request.open('POST', url, true);
request.send(null);
}
function doNothing() {}
//]]>
google.maps.event.addDomListener(window, 'load', initialize);
`
it works well when i open for the first time but when i zoom in or out there was no clusters except max zoom out. i couldn't figure it out. thanks for your help...
var mc = new MarkerClusterer(map, mcmarkers);
This line cannot be placed inside the for loop. but outside after it. I did exactly the same mistake:).

Rally App SDK: Is there a way to have variable columns for table?

Using the Rally App SDK, is there a way to create a table with a variable number of columns? For example, for a selected release, the columns are the iterations within that release date range, and the rows are each project.
I have all of the data I want to display, but not sure how to create the table.
Here's an example app that dynamically builds a table config with Iteration Names as columns and then adds some dummy data to it. Not too exciting, but it illustrates the idea.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<!-- Copyright (c) 2002-2011 Rally Software Development Corp. All rights reserved. -->
<html>
<head>
<title>Iterations as Table Columns</title>
<meta name="Name" content="App: Iterations as Table Columns"/>
<script type="text/javascript" src="https://rally1.rallydev.com/apps/1.29/sdk.js"></script>
<script type="text/javascript">
function iterationsAsTableColumns(rallyDataSource)
{
var wait = null;
var table = null;
var tableHolder = null;
// private method the builds the table of Iteration columns and your info
function showResults(results)
{
if (wait) {
wait.hide();
wait = null;
}
if (table) {
table.destroy();
}
var myIterations = results.iterations;
if (myIterations.length === 0) {
tableHolder.innerHTML = "No iterations were found";
return;
}
var columnKeys = new Array();
var columnHeaders = new Array();
var columnWidths = new Array();
var columnWidthValue = '80px';
var keyName;
// Dynamically build column config arrays for table config
for (i=0; i<myIterations.length;i++){
keyName = "Column"+i;
columnKeys.push(keyName);
columnHeaders.push("'" + myIterations[i].Name + "'");
columnWidths.push("'" + columnWidthValue + "'");
}
var config = { 'columnKeys' : columnKeys,
'columnHeaders' : columnHeaders,
'columnWidths' : columnWidths
};
table = new rally.sdk.ui.Table(config);
var cellValue;
var propertyAttributeStatement;
var rowData = new Array();
for (i=0;i<10;i++){
// create Object for row data
rowItem = new Object();
for (j=0; j<columnKeys.length;j++){
cellValue = "Cell[" + i + "][" + j + "] = Your Data Here";
propertyAttributeStatement = "rowItem." + columnKeys[j] + " = '"+cellValue+"';";
eval(propertyAttributeStatement);
}
rowData.push(rowItem);
}
table.addRows(rowData);
table.display(tableHolder);
}
//private method to query for iterations that get listed as columns
function runMainQuery(sender, eventArgs) {
var queryCriteria = '(Project.Name = "Avalanche Hazard Mapping"")';
var queryConfig =
{
key : "iterations",
type : "Iteration",
fetch : "FormattedID,Name,Project,StartDate,EndDate,CreationDate",
order : "CreationDate desc",
};
tableHolder.innerHTML = "";
wait = new rally.sdk.ui.basic.Wait({});
wait.display(tableHolder);
rallyDataSource.findAll(queryConfig, showResults);
}
//private method to start building controls on page
function initPage() {
buttonSpan = document.getElementById('buttonSpan');
tableHolder = document.getElementById('table');
var buttonConfig = {
text: "Show Table",
value: "myValue"
};
var showTableButton = new rally.sdk.ui.basic.Button(buttonConfig);
showTableButton.display(buttonSpan, runMainQuery);
}
// only public method
this.display = function() {
rally.sdk.ui.AppHeader.showPageTools(true);
initPage();
};
}
</script>
<script type="text/javascript">
rally.addOnLoad(function() {
var rallyDataSource = new rally.sdk.data.RallyDataSource('__WORKSPACE_OID__',
'__PROJECT_OID__',
'__PROJECT_SCOPING_UP__',
'__PROJECT_SCOPING_DOWN__');
var iterationsAsTableColumnsExample = new iterationsAsTableColumns(rallyDataSource);
iterationsAsTableColumnsExample.display();
});
</script>
</head>
<body>
<div>
<span id="buttonSpan"></span>
</div>
<div style="height: 15px;"> </div>
<div id="table"></div>
</body>
</html>