Extract zip folder in iOS using phone gap 2.9.0 - ios

I have used zipUtil plugin to extract the zip folder and Below is the image showing how i used ZipUtil plugin in my application. I am using phone gap 2.9.0 and Xcode 5.1, I am very new in phone gap development and I want to unzip/extract the downloaded zip file from the server.
I am able to download the zip file from server and I am getting path of that file as well, But I am not able to extract that zip file.
<!DOCTYPE HTML>
<html>
<head>
<meta name = "viewport" content = "user-scalable=no,width=device-width" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Test Page</title>
<script type="text/javascript" charset="utf-8" src="cordova.js"></script>
<script type="text/javascript" src="js/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="ZipUtil.js"></script>
<style type="text/css">
* {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
</style>
<script type="text/javascript" charset="utf-8">
var localPath;
function init() {
document.addEventListener("deviceready", ready, true);
}
function ready() {
console.log("App is ready.");
}
function download() {
// var remoteFile = "https://dl.dropbox.com/u/6731723/a.zip";
var remoteFile = "https://github.com/shazron/ZipUtil/archive/master.zip";
var localFileName = remoteFile.substring(remoteFile.lastIndexOf('/') + 1);
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSystem) {
fileSystem.root.getFile(localFileName, { create: true, exclusive: false }, function (fileEntry) {
localPath = fileEntry.fullPath;
console.log("localPath1:" + localPath);
if (device.platform === "Android" && localPath.indexOf("file://") === 0) {
localPath = localPath.substring(7);
}
console.log("localPath2 save:" + localPath);
var ft = new FileTransfer();
ft.download(remoteFile,
localPath, function (entry) {
console.log("file path:" + entry.fullPath);
var linkopen = document.getElementById("openlink");
linkopen.style.display = "block";
linkopen.href = entry.fullPath;
// var dwnldImg = document.getElementById("dwnldImg");
//dwnldImg.src = entry.fullPath;
//dwnldImg.style.visibility = "visible";
//dwnldImg.style.display = "block";
}, fail);
}, fail);
}, fail);
}
function fail(error) {
console.log("error:" + error.code);
}
function unzip(){
//alert("hi");
// this is both a zip progress and and result handler
var win = function(json) {
if (json.zipProgress) {
// {"zipProgress":{"entryNumber":1,"source":"/path/to/test.zip","filename":"myfolder/myfile.png","entryTotal":10,"zip":false}}
console.log((json.zipProgress.zip? "zip" : "unzip") + " entry " + json.zipProgress.entryNumber + "/" + json.zipProgress.entryTotal + " ("+ ((json.zipProgress.entryNumber/json.zipProgress.entryTotal)*100).toFixed(2) + "%)" );
} else if (json.zipResult) {
// zip ok, and done
// {"zipResult":{"zip":false,"source":"/path/to/test.zip","target":"/path/to/targetfolder/"}}
console.log((json.zipResult.zip? "zip" : "unzip") + " OK: " + JSON.stringify(json));
}
}
// handles failure
var fail = function(obj) {
if (obj && obj.zipResult) {
// zip failed, and done
// {"zipResult":{"zip":false,"source":"/path/to/test.zip","target":"/path/to/targetfolder/"}}
console.log((obj.zipResult.zip? "zip" : "unzip") + " FAIL: " + JSON.stringify(obj));
} else {
// general failure message
console.log("FAIL: " + obj);
}
}
var zu = cordova.require("cordova/plugin/ziputil");
zu.unzip(win, fail, localPath, localPath+'/unzip/');
}
</script>
</head>
<body onload="init();">
Download file
<br />
<br />
<br />
open
</body>
</html>
In the above code I used ZipUtil plugin but its showing error,
2013-12-05 15:10:38.739 TestUnzip[6934:a0b] CDVPlugin class ZipUtil (pluginName: ZipUtil) does not exist.
2013-12-05 15:10:38.740 TestUnzip[6934:a0b] ERROR: Plugin 'ZipUtil' not found, or is not a CDVPlugin. Check your plugin mapping in config.xml.

Related

NativeScript WebView loading local resources in src document

I am loading a local html file as the src for a NativeScript WebView component. Contained within the html file are script tags which reference javascript files that are also local resources (bundled within the app). The html file loads into the WebView just fine, but the referenced script file (mylib.js) does not.
I suspect a pathing problem but I have tried almost every variation I can think of to no avail.
My project is actually a NativeScript-Vue project and is as follows:
App.vue
<template>
<Page #loaded="onPageLoaded">
<ActionBar title="Welcome to WebView"/>
<GridLayout>
<WebView ref="myWebView" row="0" col="0"
:src="filePath" #loadFinished="onWebViewLoaded" />
</GridLayout>
</Page>
</template>
<script>
import * as fs from "tns-core-modules/file-system"
import * as utils from "utils/utils"
export default {
data() {
return {
filePath: ''
}
},
methods: {
onPageLoaded () {
this.setLocalIndexFilePath()
},
onWebViewLoaded (event) {
if (event.error) {
console.log(error)
} else {
console.log('webview loaded')
}
},
setLocalIndexFilePath () {
const deviceName =
utils.ios.getter(UIDevice, UIDevice.currentDevice).name
// iPhone 6 is the name of my simulator
if (deviceName == 'iPhone 6') {
const webViewSRC =
encodeURI(`${fs.knownFolders.currentApp().path}/www/index.html`)
this.filePath = webViewSRC
console.log(webViewSRC)
} else {
this.filePath = "~/www/index.html"
}
}
}
}
</script>
index.html
<!doctype html>
<head>
<script src="./mylib.js" type="text/javascript"></script>
<script type="text/javascript">
function onBodyLoaded() {
var msg = document.getElementById('msg');
msg.insertAdjacentHTML('beforeend', '<br />body loaded!');
}
function onLocalButtonClicked() {
var msg = document.getElementById('msg');
msg.insertAdjacentHTML('beforeend', '<br />local: You clicked button!');
}
</script>
</head>
<html>
<body onload="onBodyLoaded()">
<Button onclick="onLocalButtonClicked()">Click Me</Button>
<Button onclick="onButtonClicked()">Click Me to test external js</Button>
<p id="msg">Debug:</p>
</body>
</html>
mylib.js
// This function never gets called
function onButtonClicked() {
var msg = document.getElementById('msg');
msg.insertAdjacentHTML('beforeend', '<br />external js file: You clicked button!');
}
webpack.config.sys
...
// Copy assets to out dir. Add your own globs as needed.
new CopyWebpackPlugin([
{ from: "fonts/**" },
{ from: "**/*.+(jpg|png)" },
{ from: "assets/**/*" },
{ from: "www/**/*" },
...
This is a known issue with iOS. There is a patch work you could try, I had implemented the same in Playground for a similar issue, its applicable for Vue too.

does HTML5 Geolocation work?

I have the following script for HTML5 geolocation:
<!DOCTYPE html>
<html>
<head>
<title>Geolocation</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<style>
body {
padding: 20px;
background-color:#ffffc9
}
p { margin : 0; }
</style>
<script>
function geoFindMe() {
var output = document.getElementById("out");
if (!navigator.geolocation){
output.innerHTML = "<p>Geolocation is not supported by your browser</p>";
return;
}
function success(position) {
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
output.innerHTML = '<p>Latitude is ' + latitude + '° <br>Longitude is ' + longitude + '°</p>';
var img = new Image();
img.src = "https://maps.googleapis.com/maps/api/staticmap?center=" + latitude + "," + longitude + "&zoom=13&size=300x300&sensor=false";
output.appendChild(img);
}
function error() {
output.innerHTML = "Unable to retrieve your location";
}
output.innerHTML = "<p>Locating…</p>";
navigator.geolocation.getCurrentPosition(success, error);
}
</script>
</head>
<body>
<!-- Learn about this code on MDN: https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/Using_geolocation -->
<p><button onclick="geoFindMe()">Show my location</button></p>
<div id="out"></div>
</body>
</html>
It always gives me the following result:
Your Latitude : 51.5412621
Your Longitude : -0.08813879999999999
Regardless of whether it is on a laptop or mobile and different browsers -- anyone any ideas? it seems unreliable to me!

Cordova Media Plugin setVolume() not working

Here is my play function: As you can see I setVolume() in multiple locations to 0. This has absolutely no effect. I've tried to also set to 0.8, 0.2, doesn't matter it wont work. I've also tried non string value, which doesn't really matter as the value is converted to a float val inside of the Obj-C module. I also NSLogged to ensure the value was being passed correctly and it is.
Testing with iPad iOS 9.2 | Cordova 6.2 | Cordova Media Plugin 2.3.1.
play: function(src, seekTime)
{
App.Log.info('Playing audio source', src);
seekTime = seekTime ? seekTime : 0;
var obj = {
source: src,
startTime: new Date().getTime(),
seekTime: seekTime,
duration: 0,
preloadedNext: false,
audioSource: false
};
obj.audioSource = new Media(src, function(event){
$this.player().onAudioEnd(event, obj);
}, function(){
//on error
}, function(status)
{
obj.audioSource.setVolume("0.0");
if(status == 2){
obj.audioSource.setVolume("0.0");
obj.audioSource.seekTo(obj.seekTime * 1000);
obj.timer = setInterval(function(){
obj.seekTime++;
obj.duration = obj.audioSource._duration;
if(obj.duration < 0){
return;
}
if(obj.seekTime >= (obj.duration - $this.default.fadeTime))
{
if(obj.preloadedNext){
return;
}
obj.preloadedNext = true;
$this.player().preloadNext(obj);
}
}, 1000);
}
});
obj.audioSource.setVolume("0.0");
obj.audioSource.play();
obj.audioSource.setVolume("0.0");
obj.audioSource.seekTo(obj.seekTime * 1000);
console.log('Audio Source', JSON.stringify(obj));
$this.playing.push(obj);
}
Any help or direction would be awesome.
The following sample code works fine and it is tested in Android & iOS devices:
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="format-detection" content="telephone=no" />
<!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
<link rel="stylesheet" type="text/css" href="css/index.css" />
<meta name="msapplication-tap-highlight" content="no" />
<title>Hello World</title>
</head>
<body>
<button id="playMp3">Play MP3</button><br><br>
<button id="playMp3Mild">Play MP3 Mild</button><br><br>
<button id="playRemoteFile">Play Remote File</button>
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="js/index.js"></script>
</body>
</html>
index.js:
document.addEventListener('deviceready', onDeviceReady, false);
function onDeviceReady() {
document.querySelector("#playMp3").addEventListener("touchend", playMP3, false);
document.querySelector("#playMp3Mild").addEventListener("touchend", playMp3Mild, false);
document.querySelector("#playRemoteFile").addEventListener("touchend", playRemoteFile, false);
};
function playMP3() {
var mp3URL = getMediaURL("sounds/button-1.mp3");
var media = new Media(mp3URL, null, mediaError);
media.setVolume(1.0);
media.play();
}
function playMp3Mild() {
var mp3URL = getMediaURL("sounds/button-1.mp3");
var media = new Media(mp3URL, null, mediaError);
media.setVolume(0.1);
media.play();
}
function playRemoteFile() {
var media = new Media("http://SERVER_IP:PORT/media/test.mp3");
media.setVolume(0.1);
media.play();
}
function getMediaURL(s) {
if(device.platform.toLowerCase() === "android") return "/android_asset/www/" + s;
return s;
}
function mediaError(e) {
alert('Media Error');
alert(JSON.stringify(e));
}
The sample app can be downloaded from the github page. Ensure to add media and device plugin to test the same. More info can be found on the README file of the sample app. Hope it helps.
I'm not sure this will solve your issue, but maybe the volume is not set to zero because the setVolume is called too "early". Could you please try this code and report eventually some logs in order to refine my solution?
play: function(src, seekTime)
{
App.Log.info('Playing audio source', src);
seekTime = seekTime ? seekTime : 0;
var obj = {
source: src,
startTime: new Date().getTime(),
seekTime: seekTime,
duration: 0,
preloadedNext: false,
audioSource: false
};
obj.audioSource = new Media(src, function(event){
$this.player().onAudioEnd(event, obj);
}, function(){
//on error
}, function(status)
{
obj.audioSource.setVolume("0.0");
if(status == 2){
obj.audioSource.setVolume("0.0");
obj.audioSource.seekTo(obj.seekTime * 1000);
obj.timer = setInterval(function(){
obj.seekTime++;
obj.duration = obj.audioSource._duration;
if(obj.duration < 0){
return;
}
if(obj.seekTime >= (obj.duration - $this.default.fadeTime))
{
if(obj.preloadedNext){
return;
}
obj.preloadedNext = true;
$this.player().preloadNext(obj);
}
}, 1000);
}
});
//obj.audioSource.setVolume("0.0");
obj.audioSource.play();
setTimeout(function() { //try to set volume to 0 after 10 milliseconds
obj.audioSource.setVolume("0.0");
}, 10);
setTimeout(function() { //try to seekTo after 1 second
obj.audioSource.seekTo(obj.seekTime * 1000);
}, 1000);
console.log('Audio Source', JSON.stringify(obj));
$this.playing.push(obj);
}
Can you set a mute delay of one second to see if it creates at least a correct delayed behaviour? (process of elimination)
setTimeout(function() {
obj.audioSource.setVolume("0.0");
}, 1000);

Fusion infowindow output adding "\n" and geolocation

I've been working on this for a couple so getting to this point should make me very happy. However, I cannot figure out my infowindow output is adding "\n" to every new line. No idea how it's getting there. The geolocation is also being appended to the search result infowindow. I'd like to remove that as well.
Here is a link to the map: http://58design.com/gmaps/
Here is my code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Sheriff | Zone Leader Look Up</title>
<meta name="author" content="Santa Clarita Valley Sheriff" />
<meta name="copyright" content="Copyright 2013 SCV Sheriff" />
<meta name="keywords" content="Santa Clarita Valley Sheriff, SCV Sheriff, Canyon Country, Valencia, Saugus, Newhall, Castaic, Gorman, Stevenson Ranch, " />
<meta name="description" content="Santa Clarita Valley Sheriff Zone Leader Contact Inforamtion Look Up." />
<meta name="robots" content="index,follow" />
<meta name="Googlebot" content="follow" />
<meta name="googlebot" content="archive" />
<meta name="distribution" content="global" />
<!--Load the AJAX API-->
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
//<![CDATA[
google.load('visualization', '1', {'packages':['corechart', 'table', 'geomap']});
//var FusionTableID = 1931355;
var FusionTableID = '1uSGM1yPMJBlu74Znm4fPqdCsJjteB_kQ_nGz3tk';
var map = null;
var geocoder = null;
var infowindow = null;
var marker = null;
function initialize() {
geocoder = new google.maps.Geocoder();
infowindow = new google.maps.InfoWindow({size: new google.maps.Size(150,50) });
// create the map
var myOptions = {
zoom: 10,
center: new google.maps.LatLng(34.452789398370045, -118.51948001245114),
mapTypeControl: true,
mapTypeControlOptions: {style: google.maps.MapTypeControlStyle.DROPDOWN_MENU},
navigationControl: true,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"),
myOptions);
//layer = new google.maps.FusionTablesLayer(FusionTableID,{suppressInfoWindows:true});
layer = new google.maps.FusionTablesLayer({
map: map,
suppressInfoWindows: true,
heatmap: { enabled: false },
query: {
select: "col2",
from: "1uSGM1yPMJBlu74Znm4fPqdCsJjteB_kQ_nGz3tk",
where: "",
},
options: {
styleId: 2,
templateId: 2
}
});
layer.setMap(map);
google.maps.event.addListener(layer, "click", function(e) {
var content = e.row['description'].value+"<br><br>";
infowindow.setContent(content);
infowindow.setPosition(e.latLng);
infowindow.open(map);
});
}
function showAddress(address) {
var contentString = address+"<br>Outside Area";
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var point = results[0].geometry.location;
contentString += "<br>"+point;
map.setCenter(point);
if (marker && marker.setMap) marker.setMap(null);
marker = new google.maps.Marker({
map: map,
position: point
});
// query FT for data
var queryText ="SELECT 'description', 'Zone Area' FROM "+FusionTableID+" WHERE ST_INTERSECTS(\'Zone Area\', CIRCLE(LATLNG(" + point.toUrlValue(6) + "),0.5));";
// document.getElementById('FTQuery').innerHTML = queryText;
queryText = encodeURIComponent(queryText);
var query = new google.visualization.Query('http://www.google.com/fusiontables/gvizdata?tq=' + queryText);
//set the callback function
query.send(openInfoWindowOnMarker);
} else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}
function openInfoWindowOnMarker(response) {
if (!response) {
alert('no response');
return;
}
if (response.isError()) {
alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
return;
}
FTresponse = response;
//for more information on the response object, see the documentation
//http://code.google.com/apis/visualization/documentation/reference.html#QueryResponse
numRows = response.getDataTable().getNumberOfRows();
numCols = response.getDataTable().getNumberOfColumns();
var content = "<b>Outside area</b><br><br>";
var unionBounds = null;
// alert(numRows);
for (var i=0; i < numRows; i++) {
var name = FTresponse.getDataTable().getValue(i,0);
var kml = FTresponse.getDataTable().getValue(i,1);
content = response.getDataTable().getValue(i,0)+"<br><br>";
}
infowindow.setContent(content+marker.getPosition().toUrlValue(6));
// zoom to the bounds
// map.fitBounds(unionBounds);
google.maps.event.addListener(marker, 'click', function() {
infowindow.open(map,marker);
});
google.maps.event.trigger(marker, 'click');
}
</script>
</head>
<body onload="initialize()">
<div id="content">
<h1>SCV Sheriff Reporting Zones</h1>
<p>Use the map below to determine your area's Zone Leader. Enter your street address, city and zip code in the search field below to view the Zone Leader's contact info.</p>
<form action="#" onsubmit="showAddress(this.address.value); return false" style="padding:10px 0px 30px 0px; background:none;">
<label>Address Search</label>
<input type="text" size="60" name="address" value="23920 Valencia Blvd. Santa Clarita, CA 91355" class="address" />
<input type="submit" value="Search" />
</p>
<div id="map_canvas" style="width: 516px; height: 387px; margin-bottom:30px; border:1px solid #999;"></div>
</form>
</div>
<div id="sidebar">
</div>
<div class="clear"><!--clear--></div>
</div>
</body>
</html>
The problem is in the data in your FusionTable (the line feeds are getting translated into "\n"). I fixed the entry for "Gorman" in my example (by removing the extraneous line feeds).
This line of my code is appending the geolocation to the search result infowindow:
infowindow.setContent(content+marker.getPosition().toUrlValue(6));

403 Forbidden when trying to access a merged Fusion Table

I'm getting a 403 Forbidden error when trying to access a merged Fusion Table with the code below. Nor I understand why neither how to resolve this.
Accessing the table that has been merged with another table works like a charme.
The merged table as well as the base tables are publicly downloadable.
Anyone knows what could be wrong?? Is accessing merged tables somehow restricted?
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="UTF-8">
<title>FÖJ-Einsatzstellen</title>
<style>
body {
font-family: Arial, sans-serif;
font-size: 12px;
}
#map-canvas {
height: 500px;
width: 600px;
}
</style>
<script type="text/javascript"
src="https://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript"
src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js">
</script>
<script type="text/javascript">
var map;
var infoWindow = new google.maps.InfoWindow();
var DEFAULT_ICON_URL = 'http://g.etfv.co/http://www.google.com'
// EDIT: change this key to your own from the Google APIs Console
// https://code.google.com/apis/console/
var apiKey = 'PLACE_YOUR_OWN_KEY_HERE';
// EDIT: Specify the table with location data and icon URLs
//var tableID = '1i0mw7f4b06sG14-mAO-zEJI1gekZ8wte_J6w05c'; // Basis-Table
var tableID = '1eCPADfnXccPMAYh24W-pUEF-eiKSlOD9e0xSKBM'; // ge-merge-te Table
// Create variables for the columns you need to retrieve from the table
var latitudeColumn = 'Latitude';
var iconUrlColumn = 'Farbcodierung für Marker';
function createMarker (coordinate, url, content) {
var marker = new google.maps.Marker({
map: map,
position: coordinate,
icon: new google.maps.MarkerImage(url)
});
google.maps.event.addListener(marker, 'click', function(event) {
infoWindow.setPosition(coordinate);
infoWindow.setContent(content);
infoWindow.open(map);
});
};
function fetchData() {
// Construct a query to get data from the Fusion Table
var query = 'SELECT '
+ latitudeColumn + ','
+ '\'' + iconUrlColumn + '\''
+ ' FROM '
+ tableID;
var encodedQuery = encodeURIComponent(query);
// Construct the URL
var url = ['https://www.googleapis.com/fusiontables/v1/query'];
url.push('?sql=' + encodedQuery);
url.push('&key=' + apiKey);
url.push('&callback=?');
// Send the JSONP request using jQuery
$.ajax({
url: url.join(''),
dataType: 'jsonp',
success: onDataFetched,
error: onError,
timeout : 7500
});
}
function onError(e) {
alert(e);
}
function onDataFetched(data) {
if(data.error) {
var errs = data.error.errors;
var msg = "";
for (var i in data.error.errors) {
msg +=
parseInt(i, 10)+1 + ". Fehler:" +
"\ndomain: " + errs[i].domain +
"\nmessage: " + errs[i].message +
"\nreason: " + errs[i].reason + "\n";
}
alert(
"Leider sind Fehler aufgetreten (um genau zu sein: " + data.error.errors.length + " Fehler, Code: " + data.error.code + "):\n" + msg
);
return;
}
var rows = data['rows'];
var iconUrl;
var iconUrl_part1 = 'http://chart.apis.google.com/chart?cht=mm&chs=32x32&chco=';
var iconUrl_part2 = '&ext=.png';
var content = "mein content";
var coordinate;
// Copy each row of data from the response into variables.
// Each column is present in the order listed in the query.
// Starting from 0.
// EDIT this if you've changed the columns, above.
for (var i in rows) {
var geocode = rows[i][0].split(",");
coordinate = new google.maps.LatLng(geocode[0],geocode[1]);
if (rows[i][1] != '') { // ensure not empty
iconUrl = iconUrl_part1 + rows[i][1] + iconUrl_part2;
createMarker(coordinate, iconUrl, content);
} else {
createMarker(coordinate, DEFAULT_ICON_URL, content);
}
}
}
function initialize() {
fetchData(); // begin retrieving data from table, and put it on the map
map = new google.maps.Map(document.getElementById('map-canvas'), {
center: new google.maps.LatLng(48.537778, 9.041111),
zoom: 7,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="map-canvas"></div>
</body>
</html>

Resources