I tested the IBMIoTF in a node.js server and it worked well.
IBMIoTF you can find here: https://www.npmjs.com/package/ibmiotf
Now I want to use the IBMIoTF in a WebApplication and I notice this little note in the documentation: https://www.npmjs.com/package/ibmiotf#load-the-library-in-browser
Load the library in browser
load iotf-client-bundle.js or iotf-client-bundle-min.js from the dist directory
I also took a look into the http://browserify.org/, but I am not able to get it working.
It is able to load the library in the index.html
<script src="libs/iotf/iotf-client-bundle.min.js"></script>
, but how can I create a object instance in the angular module?
Option 1
I am not able to use require in a WebApplication.
var config = {
"org": "THEORG",
"id": "IOT_WEB_APPLICATION",
"auth-key": "THEKEY",
"auth-token": "THETOKEN",
"type" : "shared"
};
var IotClient = require('ibmiotf');
var iotClient = new IotClient.IotfApplication(config);
In this situation I get
angular.js:14110 ReferenceError: require is not defined
Option 2
I also tried to use a object, I found in iotf-client.js file.
module.exports = {
IotfDevice: _IotfDevice['default'],
IotfManagedDevice: _IotfManagedDevice['default'],
IotfGateway: _IotfGateway['default'],
IotfManagedGateway: _IotfManagedGateway['default'],
IotfApplication: _IotfApplication['default']
};
and did a implementation like this in my controller:
var config = {
"org": "THEORG",
"id": "IOT_WEB_APPLICATION",
"auth-key": "THEKEY",
"auth-token": "THETOKEN",
"type" : "shared"
};
var iotClient = new IotfApplication(config);
Here I get:
angular.js:14110 ReferenceError: IotfApplication is not defined
These options didn't work, but how to create a instance for the IBMIoTF?
Can anyone help me?
You need to browserify the ibmiotf as part of your buildprocess:
1. in your package.json add dependency to ibmiotf npm
2. do npm install
3. add a script command to your package.json for browserify/uglify like this
"scripts": {
"build": "browserify your.js | uglifyjs -m -c warnings=false > bundle.js"
}
do npm build, this will produce a bundle.js with all your javascript files and the dependencies specified to bundle.js
Include the bundle.js in your web html file. ...<script src="bundle.js"></script>
in "your.js" do something like this
var config = require(YOURCONFIG);
var deviceType = "YOURDEVICETYPE";
var appClient = new client.IotfApplication(config);
appClient.connect();
appClient.on("connect", function () {
console.log("Connected");
appClient.subscribeToDeviceEvents(deviceType);
});
appClient.on("deviceEvent", function (deviceType, deviceId, eventType, format, payload) {
console.log("Device Event from :: "+deviceType+" : "+deviceId+" of event "+eventType+" with payload : "+payload);
});
Related
I am new to emscripten, so this may be an easy one to answer for others. I can't get access to my C functions. Here is the setup:
Simple C file square.c:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <emscripten.h>
EMSCRIPTEN_KEEPALIVE
double square(double x){
return x*x;
}
Content of ready.js:
ready = function () {
startup();
}
startup is a function that I added to square.html to know when everything is ready.
Emcc command Line:
emcc square.c -DNDEBUG -s MINIMAL_RUNTIME -s ALLOW_MEMORY_GROWTH=1 -s INVOKE_RUN=0 -s ENVIRONMENT=web,worker -s MODULARIZE=1 -s SUPPORT_ERRNO=0 --pre-js ./ready.js -s EXPORT_NAME=wasmMod -o square.html
output is as expected: square.html, square.js, square.wasm
Everything runs in Chrome as expected, startup is called. Now I want to access the square function:
function startup(){
console.log('startup called');
let y = _square(2);
console.log(`square: ${y}`);
}
this gives me an error: "VM291:1 Uncaught ReferenceError: _square is not defined"
If I use
let y = wasmMod._square(2);
instead, I get
"square.js:783 TypeError: wasmMod._square is not a function"
I have tried a lot of things and searched the web, but I can't seem to find the error.
If I remove -s MODULARIZE=1, I can call _square(2) without problems, however, in that case wasmMod doesn't hold anything, all variables and functions are in Global context, which is something I want to avoid.
Once it works I want to embed this part into a larger JS project using ES6 modules, so my goal is to keep everything related to emscripten in one module.
Any help is very much appreciated. Thanks in advance!
2020/10/27: added script from html file:
// Depending on the build flags that one uses, different files need to be downloaded
// to load the compiled page. The right set of files will be expanded to be downloaded
// via the directive below.
function binary(url) { // Downloads a binary file and outputs it in the specified callback
return new Promise((ok, err) => {
var x = new XMLHttpRequest();
x.open('GET', url, true);
x.responseType = 'arraybuffer';
x.onload = () => { ok(x.response); }
x.send(null);
});
}
function script(url) { // Downloads a script file and adds it to DOM
return new Promise((ok, err) => {
var s = document.createElement('script');
s.src = url;
s.onload = () => {
var c = wasmMod;
delete wasmMod;
ok(c);
};
document.body.appendChild(s);
});
}
Promise.all([script('square.js'), binary('square.wasm')]).then((r) => {
// Detour the JS code to a separate variable to avoid instantiating with 'r' array as "this" directly to avoid strict ECMAScript/Firefox GC problems that cause a leak, see https://bugzilla.mozilla.org/show_bug.cgi?id=1540101
var js = r[0];
js({ wasm: r[1] });
});
2020/10/27: added some content from square.js:
var wasmMod=
function(wasmMod) {
wasmMod = wasmMod || {};
var Module = wasmMod;
...lots of javascript follows ...
var imports = {
"env": asmLibraryArg,
"wasi_snapshot_preview1": asmLibraryArg
};
var _square, _fflush, stackSave, stackRestore, stackAlloc, _emscripten_get_sbrk_ptr, _sbrk;
if (!Module["wasm"]) throw "Must load WebAssembly Module in to variable Module.wasm before adding compiled output .js script to the DOM";
WebAssembly.instantiate(Module["wasm"], imports).then(function(output) {
var asm = output.instance.exports;
_square = asm["square"];
_fflush = asm["fflush"];
stackSave = asm["stackSave"];
stackRestore = asm["stackRestore"];
stackAlloc = asm["stackAlloc"];
_emscripten_get_sbrk_ptr = asm["emscripten_get_sbrk_ptr"];
_sbrk = asm["sbrk"];
wasmTable = asm["__indirect_function_table"];
initRuntime(asm);
ready();
}).catch(function(error) {
console.error(error);
});
return {}
}
I did some more testing, and I have a working solution now based on the recommendation that #Thomas provided. Thanks again for that.
However, I got it to work only if I drop the MINIMAL_RUNTIME flag.
The difference:
without MINIMAL_RUNTIME:
emcc square.c -DNDEBUG -s ALLOW_MEMORY_GROWTH=1 -s SAFE_HEAP=1 -s INVOKE_RUN=0 -s ENVIRONMENT=web,worker -s MODULARIZE=1 -s SUPPORT_ERRNO=0 -s "EXPORT_NAME='wasmMod'" -o square.html
Call from square.html:
let res = binary('square.wasm')
.then(wasm => { wasmMod({wasm: wasm})
.then(MyModule => {
console.log('WebAssembly loaded!');
console.log(MyModule._square(3));
});
});
MyModule contains everything I need. I can use my wasm functions without problems.
Now with MINIMAL_RUNTIME:
emcc square.c -DNDEBUG -s MINIMAL_RUNTIME -s ALLOW_MEMORY_GROWTH=1 -s SAFE_HEAP=1 -s INVOKE_RUN=0 -s ENVIRONMENT=web,worker -s MODULARIZE=1 --pre-js ./ready.js -s SUPPORT_ERRNO=0 -s "EXPORT_NAME='wasmMod'" -o square.html -s EXTRA_EXPORTED_RUNTIME_METHODS="['getValue','setValue']"
Using the same calling sequence in the HTML file gives an error:
square.html:44 Uncaught (in promise) TypeError: wasmMod(...).then is not a function at square.html:44
I can't get this to work like the version without MINIMAL_RUNTIME. Inside function ready() I have access to _square() inside the wasmMod closure, however, outside that closure no module exists that I can access. wasmMod points to the js function only, not to a module.
I expect the error to be on my side, however, I can't spend any more time on this, so I will for now cruise with the full version.
I'm launching native apps with the help of WebdriverIO and mocha, but unable to communicate with the device, but able to launch the application but not interact with the element.
android_app_test.js
const webdriverio = require('webdriverio');
const androidOptions = require('../../../helpers/caps').androidOptions;
const assert = require('chai').assert;
androidOptions.capabilities.appPackage = "com.google.android.calculator"
androidOptions.capabilities.appActivity = "com.android.calculator2.Calculator"
describe('Create Chrome web session', function () {
let client;
before(async function () {
client = await webdriverio.remote(androidOptions)
});
after(async function () {
await client.deleteSession();
});
it('should create and destroy Android browser session', async function () {
const elem = await $('#digit_2')
elem.waitForDisplayed(3000);
await client.touchClick('digit_2');
});
});
config.js
var Mocha = require('mocha'), fs = require('fs');
var mocha = new Mocha({
reporter: 'mochawesome-screenshots',
reporterOptions: {
reportDir: 'customReportDir',
reportName: 'customReportName',
reportTitle: 'customReportTitle',
reportPageTitle: 'customReportPageTitle',
takePassedScreenshot: true,
clearOldScreenshots: true,
shortScrFileNames: true,
jsonReport: false,
multiReport: false
},
timeout: 600000,
})
var file = ['./test/basic/app/']; //location of the test js
for (var i = 0; i < file.length; i++) {
fs.readdirSync(file[i]).forEach(function (filename) {
mocha.addFile(file[i] + filename);
});
}
mocha.run(function (failures) {
process.on('exit', function () {
process.exit(failures);
});
});
package.json
"scripts": {
"test": "mocha config.js"
},
Not sure about that, i think something was wrong in my configuration or else
The $ global is added through the WebdriverIO test runner. Since you're using wdio through standalone mode, you don't get access to those globals. Try this instead:
const elem = await client.$('#digit_2')
Make sure you're using the newest version of Webdriver.io. Webdriver.io v5 is the latest version that also implements the $('selector') shortcut.
If you're using Webdriver.io v4 - you may still need to use browser.element('selector') to find your elements.
It appears from the tags in your question, and the code you posted you maybe on version 4.
$ is usually used as a shorthand to run JQuery functions (such as your $('#digit_2'), in the "android_app_test.js" file).
From the WebdriverIO's doc:
The $ command is a short way to call the findElement command in order to fetch a single element on the page. It returns an object that with an extended prototype to call action commands without passing in a selector. However if you still pass in a selector it will look for that element first and call the action on that element.
To fix this you have to install JQuery with this commands:
In a terminal run:
npm install --save jquery
npm install --save-dev #types/jquery
then import it at the top of your "android_app_test.js" file like this
import * as $ from "jquery";
I am learning NativeScript. I have a basic app working. I am now trying to import a JavaScript library that I've used in the past. I'm importing the library by using:
npm install git://github.com/my-company/my-project.git --save
I've confirmed that the package is being installed. In my view model, I then add the following:
var MyLibrary = require('MyLibrary');
That line alone causes the app to crash. Basically, NativeScript cannot seem to find it (or load it). I looked, and I can see the "MyLibrary" directory in the "node_modules" directory. The directory structure looks like this:
.
node_modules
MyLibrary
dist
MyLibrary.min.js
src
MyLibrary.js
package.json
The MyLibrary.js file looks like this:
class MyLibrary {
process(vals) {
let result = 0;
if (vals) {
vals.forEach(function(val) {
result = result + val;
});
}
return result;
}
}
module.exports = MyLibrary;
The "MyLibrary.min.js" file is the result of running it through Babel and converting it to ES5. What am I doing wrong? I'm just trying to get the following code into my view model:
var MyLibrary = require('MyLibrary');
var library = new MyLibrary();
var result = library.process([1, 2, 3, 4]);
In your package.json, add a property like this :
{
"main": "./dist/MyLibrary.min.js"
}
In your code, use your module like this :
var MyLibraryModule = require('MyLibrary');
var library = new MyLibraryModule.MyLibrary();
var result = library.process([1, 2, 3, 4]);
We are trying to use only nodeJS with minimal dependencies to other packages, the challenge we now encounter is HandelbarsJS. We found a package, Assemble who can generate html for us. Only, it is very very slow, about 3 seconds each time, of these 3 seconds, there are 2,5 / 2,7 seconds of the next line:
var assemble = require('assemble');
Our package.json script section:
"scripts": {
"build:handlebars": "node scripts/handlebars.js",
"watch:handlebars": "nodemon --watch assets --exec \"npm run build:handlebars\"" }
the script/handlebars.js file
#! /usr/bin/env node
var assemble = require('assemble');
var extname = require('gulp-extname');
console.log(Date.now() - start);
assemble.data('assets/templates/data/*.json');
assemble.layouts('assets/templates/layouts/*.hbs');
assemble.partials('assets/templates/partials/*.hbs');
assemble.src('assets/templates/*.hbs', { layout: 'default' })
.pipe(extname())
.pipe(assemble.dest('build/'));
Each time, when we save a .hbs file, Nodemon restart and the external javascript file will be called.
How can we ensure that 'require' get called only once, or whether they remain in memory?
Thank you!
Since you want to accomplish using this with assemble, but without gulp, I recommend chokidar.
npm install chokidar --save
Now you can require chokidar like this:
var chokidar = require('chokidar');
Then define a little helper that runs handler whenever something in a pattern changes:
function watch(patterns, handler) {
chokidar.watch(patterns, {
ignoreInitial: false
}).on('add', handler).on('change', handler).on('unlink', handler);
}
Now we can alter the script like this:
#! /usr/bin/env node
var assemble = require('assemble');
var extname = require('gulp-extname');
var chokidar = require('chokidar');
console.log(Date.now() - start);
assemble.data('assets/templates/data/*.json');
assemble.layouts('assets/templates/layouts/*.hbs');
assemble.partials('assets/templates/partials/*.hbs');
// Enable --watch command line for Chokidar, otherwise, just run!
if (process.argv.pop() === '--watch') {
watch('assets', runOnce);
} else {
runOnce();
}
function watch(patterns, handler) {
chokidar.watch(patterns, {
ignoreInitial: false
}).on('add', handler).on('change', handler).on('unlink', handler);
}
function runOnce() {
assemble.src('assets/templates/*.hbs', { layout: 'default' })
.pipe(extname())
.pipe(assemble.dest('build/'));
}
And instead of nodemon, this will keep your script alive and running. So, in npm, you want this:
"scripts": {
"build:handlebars": "node scripts/handlebars.js",
"watch:handlebars": "node scripts/handlebars.js --watch"
}
Whenever a file changes, the script will now run, without re-invoking from scratch.
The beta version of assemble is based on gulp and has a cli that you can use just like you would use gulp, but if you don't want to use the cli and use npm scripts instead, you can do something based on #roel-van-uden's answer without chokidar and also be able to reload the actual assets (e.g. data, layouts, partials)
#! /usr/bin/env node
var start = Date.now();
var assemble = require('assemble');
var extname = require('gulp-extname');
assemble.task('assets', function () {
console.log(Date.now() - start);
assemble.data('assets/templates/data/*.json');
assemble.layouts('assets/templates/layouts/*.hbs');
assemble.partials('assets/templates/partials/*.hbs');
return assemble.src('assets/templates/*.hbs', { layout: 'default' })
.pipe(extname())
.pipe(assemble.dest('build/'));
});
assemble.task('watch', ['assets'], function () {
assemble.watch('./assets/**/*.*', ['assets]');
});
// Enable --watch command line
if (process.argv.pop() === '--watch') {
assemble.run(['watch']);
} else {
assemble.run(['assets']);
}
I'm looking to create multiple HTML files from a single Jade template using Grunt.
Here's what I'm doing:
Grabbing the JSON data from an external file
Looping through that object
Creating a grunt config task for each value in that JSON object
Here's my code:
neighborhoods = grunt.file.readJSON('data/neighborhoods.json');
for(var i = 0; i < Object.keys(neighborhoods).length; i++) {
var neighborhood = {
"title" : Object.keys(neighborhoods)[i],
"data" : neighborhoods[Object.keys(neighborhoods)[i]]
};
grunt.config(['jade', neighborhood.title], {
options: {
data: function() {
return {
neighborhoods: neighborhood.data
}
}
},
files: {
"build/neighborhoods/<%= neighborhood.title %>.html": "layouts/neighborhood.jade"
}
});
}
The problem that I'm running in to is this
Running "jade:Art Museum" (jade) task
Warning: An error occurred while processing a template (Cannot read property 'title' of undefined). Use --force to continue.
If I make the filename a string, it runs fine but obviously creates all the files with the same filename, thus only creating one file. I need to make that filename dynamic.
I found the solution here:
Use Global Variable to Set Build Output Path in Grunt
The issue is that the module exports before those global variables get set, so they are all undefined in subsequent tasks defined within the initConfig() task.
This did the trick!
var neighborhoods = grunt.file.readJSON('data/neighborhoods.json');
for(var i = 0; i < Object.keys(neighborhoods).length; i++) {
var neighborhood = {
"title" : Object.keys(neighborhoods)[i],
"data" : neighborhoods[Object.keys(neighborhoods)[i]]
};
/*
* DEFINE VALUE AS GRUNT OPTION
*/
grunt.option('neighborhood_title', neighborhood.title);
grunt.config(['jade', neighborhood.title], {
options: {
data: function() {
return {
neighborhoods: neighborhood.data,
neighborhood_title: neighborhood.title
}
}
},
/*
* OUTPUT GRUNT OPTION AS FILENAME
*/
files: {
"build/neighborhoods/<%= grunt.option('neighborhood_title') %>.html": "layouts/neighborhood.jade"
}
});
}
This results in the desired output:
Running "jade:East Passyunk" (jade) task
File build/neighborhoods/Society Hill.html created.
Running "jade:Fishtown" (jade) task
File build/neighborhoods/Society Hill.html created.
Running "jade:Graduate Hospital" (jade) task
File build/neighborhoods/Society Hill.html created.
Running "jade:Midtown Village" (jade) task
File build/neighborhoods/Society Hill.html created.
Running "jade:Northern Liberties" (jade) task
File build/neighborhoods/Society Hill.html created.
...
I know this is an old post but I kept coming back here whilst trying to solve a similar problem. I wanted to output multiple html files from a single jade template file using a for-loop.
The two problems I came across was setting the output filename (a javascript object literal KEY) and making sure inline javascript functions are run immediately so that the loop variables are available.
Here is my full source code with comments. I hope this is of use to anyone else stumbling across this post.
Gruntfile.js:
module.exports = function(grunt) {
// Create basic grunt config (e.g. watch files)
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
watch: {
grunt: { files: ['Gruntfile.js'] },
jade: {
files: 'src/*.jade',
tasks: ['jade']
}
}
});
// Load json to populate jade templates and build loop
var json = grunt.file.readJSON('test.json');
for(var i = 0; i < json.length; i++) {
var obj = json[i];
// For each json item create a new jade task with a custom 'target' name.
// Because a custom target is provided don't nest options/data/file parameters
// in another target like 'compile' as grunt wont't be able to find them
// Make sure that functions are called using immediate invocation or the variables will be lost
// http://stackoverflow.com/questions/939386/immediate-function-invocation-syntax
grunt.config(['jade', obj.filename], {
options: {
// Pass data to the jade template
data: (function(dest, src) {
return {
myJadeName: obj.myname,
from: src,
to: dest
};
}()) // <-- n.b. using() for immediate invocation
},
// Add files using custom function
files: (function() {
var files = {};
files['build/' + obj.filename + '.html'] = 'src/index.jade';
return files;
}()) // <-- n.b. using () for immediate invocation
});
}
grunt.loadNpmTasks('grunt-contrib-jade');
grunt.loadNpmTasks('grunt-contrib-watch');
// Register all the jade tasks using top level 'jade' task
// You can also run subtasks using the target name e.g. 'jade:cats'
grunt.registerTask('default', ['jade', 'watch']);
};
src/index.jade:
doctype html
html(lang="en")
head
title= pageTitle
script(type='text/javascript').
if (foo) {
bar(1 + 5)
}
body
h1 #{myJadeName} - node template engine
#container.col
p.
Jade is a terse and simple
templating language with a
strong focus on performance
and powerful features.
test.json:
[{
"id" : "1",
"filename" : "cats",
"tid" : "2016-01-01 23:35",
"myname": "Cat Lady"
},
{
"id" : "2",
"filename" : "dogs",
"tid" : "2016-01-01 23:45",
"myname": "Dog Man"
}]
After running 'grunt' the output should be:
build/cats.html
build/dogs.html
Came across a similar requirement for a project I'm working on but couldn't get this to work. I kept getting only one file generated since the grunt option had same value for all tasks (the last value). So I ended up using <%= grunt.task.current.target %> for the file name which in your case would be same as neighborhood.title.