List all drives Addon SDK (Nodejs/jpm) without require Chrome - node.js

Is this the only SO question about listing drives ??
I'm on Windows, I'm a newbee in addon developement, I (currently) use Firefox Addon SDK with Node.js/jpm, but not Web Extensions (yet), nor the XPCOM/XUL thing. Seems like some are mixing the whole thing..
Correct me if I'm wrong, but as of May 2016, Web Extensions can't parse File System (otherwise I would be very happy to have access to the documentation allowing that too ^^.) And it appears that the Require chrome is now deprecated along with XUL/XPCOM things. As I guess everyone is pushed forward (looks like) to go Web Extensions (that is out of the scope of the subject), there's no way I would go Require chrome as I would have to drop it anyway next year...
So how do we list drives in Firefox Addon SDK without importing the deprecated libraries ?
My answer below, but would like to have a better option if any. The MDN page about is :
either talking about deprecated methods
or just showing you how to manipulate a directory you already know the whereabout.

Here is what I could do with the Addon SDK (or initially jetpack if I'm not mistaken), and yeah, that's a kind of hack because I don't know how to do it in a cleaner way, and I don't want to use Require Chrome.
Minimal version :
// index.js or main.js
// declare the io/file API :
var ioFile = require('sdk/io/file');
// array to make attempts :
let drivesIds = ["c", "d", "e", "f", "g", .... "z" ]; // hack isn't it ? :/
for (let i = 0; i < drivesIds.length; i++) {
let driveName = drivesIds[i] + ":\\";
if (ioFile.exists(driveName)) {
console.log(driveName + " is a drive and is ready !");
}
}
And you're done ! Okay, that was pretty obvious, but I failed to find that code anywhere I searched, or a code that does it better (again, without require('chrome'))
Extended versions can :
put the whole thing in a function getDrives() that returns array of drives objects like { path: "c:\\", hasChildren: true, etc: "etc" }. (check for child directories by combining ioFile.isFile() with ioFile.list() in a for loop that breaks the moment a subdir is encountered.
port the code to another addon module, with exports implementations
even encapsulates io functions and properties as members of a global object in a module (you can monitor filesystem changes like unplugged dir, store filesystem tree in memory, etc.)
All that making your index.js file lighter. Can this be adapted to other OS ? I don't know. The title is misleading while this is the only question about listing drives Addon SDK tagged.
Never ever try to build an entire drive tree, that would bring the computer to a halt, and fail at a point or another because io/file is limited to 250-260 chars in path length on Windows.
Security issues ! That's probably why it's undocumented, why WebExtensions disallows io operations ? But, I use that to inject a nice windows explorer (select a dir to save whatever you want in there, shortcutting save as or download dialogs). That's the only relevant reason why I use Firefox. I would go back to dotNet and reinvent the wheel with again lots of security holes if io is not flexible enough (or missing) in WE, or try Chrome instead (if no deprecated API in the next 10 years). Fact is, the moment you can automate io parsing, there will be security issues, but the moment you disallow that, Addon extensions is not the way to go with filesystem.

Related

HTML5 Audio long buffering before playing

I'm currently making an electron app that needs to play some 40Mbyte audio file from the file system, maybe it's wrong to do this but I found that the only way to play from anywhere in the file system is to convert the file to a dataurl in the background script and then transfer it using icp, after that I simply do
this.sound = new Audio(dataurl);
this.sound.preload = "metadata"
this.sound.play()
(part of a VueJS component hence the this)
I did a profling inside electron and this is what came out:
Note that actually transferring the 40Mbytes audio file doesn't take that long (around 80ms) what is extremely annoying is the "Second Task" which is probably buffering (I have no idea) which last around 950ms, this is way too long and ideally would need it under <220ms
I've already tried changing the preload option to all available options and while I'm using the native html5 audio right now I've also tried howlerjs with similar results (seemed a bit faster tho).
I would guess that loading the file directly might be faster but even after disabling security measures put by electron to block the file:/// it isn't recognized as a valid URI by XHR
Is there a faster way to load the dataurl since all the data is there it just needs to be converted to a buffer or something like that ?
Note: I can not "pre-buffer" every file in advance since there is about 200 of them it just wouldn't make sense in my opinion.
Update:
I found this post Electron - throws Not allowed to load local resource when using showOpenDialog
don't know how I missed it, so I followed step 1 and I now can load files inside electron with the custom protocol, however, nor Audio nor howlerjs is faster, it's actually slower at around 6secs from click to first sound, is it that it needs to buffer the whole file before playing ?
Update 2:
It appears that the 6sec loading time is only effective on the first instance of audio that is created. I do not know why tho. After that the use of two instances (one playing and one pre-buffering) work just fine, however even loading a file that isn't loaded is instantaneous. Seems weird that it only is the firs one.

uninitialized constant OrigenTesters

I am working on transferring one application from rgen to Origen.
I added environment/j750.rb in my application.
added the below code into j750.rb
# environment/j750.rb
$tester = OrigenTesters::J750.new
in Target folder, I also added $test as below:
$tester = OrigenTesters::J750.new
however, when I tried to generate pattern, it still failed and showed'uninitialized constant OrigenTesters'.
When and how to initialize it?
Thanks a lot in advance!
Normally this is something that Origen users don't particularly need to worry about, if you add:
gem 'origen_testers'
to your application's Gemfile, then it will be required automatically and a reference like OrigenTesters in your environment file or anywhere else will just work.
However, I note that you mention upgrading from an rgen app, which means that your application must be very old and in fact may not even have a Gemfile.
If you contact me internally I can send you the link to our intranet page which has a guide on how to update these really old apps.

What is the simplest way to create a UI test in Android Studio that can take screenshots when I need it to?

I am trying to create a UI test in Android Studio which will navigate through the various screens of my application and take screenshots when I tell it to.
I am new to Android Studio and Android programming in general; I have a decent understanding of XML and Java, but I don't know much about build files and I am not very good at using Android Studio, it seems.
I started this endeavor a couple weeks ago, and the first solution I tried was to use uiautomator. However, the documentation on that page (and seemingly just about everywhere else) is geared towards development with Eclipse, which I would like to avoid using for this project if possible.
The next thing I tried was Espresso. After I overcame some issues with implementing Espresso into my project, I was able to write tests with Espresso which would navigate through the screens of my application. However, unlike uiautomator, Espresso does not have built-in functionality to take screenshots at this time.
I first attempted to solve this problem of being unable to take screenshots with Espresso by writing custom code; as I'm still unfamiliar with Android, I wasn't really sure how to go about that, so I searched for help on the Internet (How to programmatically take a screenshot in Android?). However, I was unable to get the solutions I found to function from inside the test file.
Somebody recommended the usage of this tool: https://github.com/rtyley/android-screenshot-lib but I could not figure out how to import that into my project.
I eventually came back to uiautomator; I was still having a lot of trouble importing it into my project, and some people said that Robotium would help with that. I got Robotium to work, but I still could not import uiautomator.
It has been probably one month since I started using Android Studio, and in that time, I've had nothing but trouble simply getting the software to function properly. For the sake of brevity, I've omitted all the problems I have managed to solve on my own, but, to put it bluntly, I'm at the end of my patience.
TL;DR
If somebody could either:
-explain in the simplest possible way how to import uiautomator into an Android Studio project (I have read a lot of documentation about how to import external libraries into a project, but they all tell me to add a 'libs' folder to my project, but do not specify which type of folder to use [Java Resource Folder? Assets Folder? Module? etc.], and/or they tell me to go into Project Structure, select my app, go to dependencies, and choose "Import as Module," which does not work...)
OR
-explain how best to take a screenshot from inside of an Espresso test, including any instructions on how to import any required libraries
OR
-explain in detail some other way to create a UI test that can take screenshots...
...I would really appreciate it. I've spent days trying to figure out how to do this, and I am so frustrated. Many people have asked similar questions, but the answers are either too vague or the problems aren't close enough to my own.
Thanks!
Alright, after much trouble, I've found a very simple solution. It took me a very long time to work out, but if anyone else needs to do something similar, I'll put my conclusion here.
First of all, the testing framework that is easiest to use with Android Studio, it seems, is Espresso. Setting up Espresso is fairly simple; most of the instructions can be found here: https://code.google.com/p/android-test-kit/wiki/EspressoSetupInstructions Make sure you read it carefully -- it tells you basically everything you need to know, but I missed some important details and that caused me a lot of trouble.
If you browse around that Espresso site, it tells you just about everything you need to know about how to write Espresso tests. It was a little frustrating for me because, if I wrote a test and the test failed, my device would then have connection issues with my laptop and I would have to disconnect and reconnect the USB cord I was using. I think this had something to do with the fact that I was using a Nexus 7 with a Windows 8 laptop, which has given me some problems in other areas, so you may not encounter this issue yourself.
Now, unlike uiautomator, the documentation of which claims to have support for taking screenshots, Espresso does not have built-in support for taking screenshots. That means you'll have to figure out a different way to take screenshots. My solution was to create a new class (called HelperClass, in my case) inside my androidTest package and add this method to it.
public static void takeScreenshot(String name, Activity activity)
{
//slightly modified version of solution from http://www.ssaurel.com/blog/how-to-programmatically-take-a-screenshot-in-android/
//I added "/Pictures/" to my path because that's the folder where I wanted to store my screenshots -- you might not have that folder on your device, so you might want to replace "/Pictures/" with just "/" until you decide where you want to store the screenshots
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/" + name;
View v = activity.getWindow().getDecorView().getRootView();
v.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(v.getDrawingCache());
v.setDrawingCacheEnabled(false);
OutputStream out = null;
File imageFile = new File(path);
//the following line will help you find where the screen will be stored on your device
Log.v("Screenshot", "The image file path is " + imageFile.getPath());
try {
out = new FileOutputStream(imageFile);
// choose JPEG format
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
} catch (FileNotFoundException e) {
// manage exception
} catch (IOException e) {
// manage exception
} finally {
try {
if (out != null) {
out.close();
}
} catch (Exception exc) {
}
}
}
In order for this function to work, you will also have to add the following line to your manifest file.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Without that, the function above will throw a FileNotFoundException every time you run it.
Finally, to call the takeScreenshot function from inside your Espresso test code, use this line (assuming you called your class HelperClass... if not, use the name of your class instead.
HelperClass.takeScreenshot("Whatever you want to call the file", getActivity());
Finding where your screenshots are stored can be a little difficult if you don't know where to look. I added a line of code to the takeScreenshot function that would print the filepath to LogCat, but I was using the file explorer on my computer to look for the screenshots on my Nexus (which was, of course, connected to the computer), and I couldn't find that path. However, I got a file explorer application on my tablet which made it very easy to find where the files were located in relation to everything else.
My solution may not be the simplest and it certainly isn't the best -- you'll fill your device up with screenshots before long if you aren't careful to delete the ones you don't need anymore, and I haven't got any idea how one would go about saving the screenshots directly to, say, a computer connected to the tablet via USB. That would certainly be helpful. However, if you really need a simple UI test that takes screenshots, and you're frustrated to no end like I was, this solution should probably help. I certainly found it useful.
I hope this helps somebody else -- it definitely solved my problems, at least for now.
Of course if you don't have all the restrictions that I did when I had to write a UI test that took screenshots, the other posts in this thread probably work much better.
You should give AndroidViewClient/culebra a try. Using culebra GUI, you can automatically generate a test case that interacts with your app and takes screenshot exactly when you indicate so.

Where/How to save a preferences file in a *nix command line utility?

I am writing a small command line utility. It should hopefully be able to run on OSX, UNIX and Linux.
It needs to save a few preferences somewhere, like in a small YAML config file.
Where would one save such a file?
Language: Python 2.7
OS: *nix
Commonly, these files go somewhere like ~/.rc (eg: ~/.hgrc). This could be the path to a file, or to a directory if you need lots of configuration settings.
For a nice description see http://www.linuxtopia.org/online_books/programming_books/art_of_unix_programming/ch10s03.html
I would avoid putting the file in the ~ directory only because it has gotten totally flooded with crap. The recent trend, at least on ubuntu, is to use ~/.config/<appname>/ for whatever dot files you need. I really like that convention.
If your application is named "someapp" you save the configuration in a file such as $HOME/.someapp. You can give the config file an extension if you like. If you think your app may have more than one config file you can use the directory $HOME/.someapp and create regular-named (not hidden) files in there.
Many cross-platform tools use the same path on OS X as on linux (and other POSIX/non-Windows platforms). The main advantage of using the POSIX locations isn't saving a few lines of code, but saving the need for Mac-specific instructions, and allowing Mac users to get help from the linux users in the community (without any need to translate their suggestions).
The other alternative is to put them in the "Mac-friendly" locations under ~/Library instead. The main advantage of using the Mac locations is basically "Apple says so"—unless you plan to sandbox your code, in which case the main advantage is that you can do so.
If you choose to use the Library locations, you should read About the OS X File System and OS X Library Directory Details in the File System Programming Guide, but here's the short version:
Almost everything: Create a subdirectory with your app's name or bundle ID (unless you're going out of your way to set a bundle ID, you'll get org.python.python, which you don't want…) under ~/Library/Application Support. Ideally you should use APIs like -[NSFileManager URLForDirectory:inDomain:appropriateForURL:create:error:] to get the path; if not, you have to deal with things like localization, sandbox containers, etc. manually.
Anything that can be easily re-created (so it doesn't need to be backed up, migrated, etc.): An identically-named subdirectory of ~/Library/Caches.
Preferences: Use the NSUserDefaults or CFPreferences APIs instead. If you use your own format, the "old" way of doing things is to create a subdirectory under ~/Library/Preferences named with your app's name or bundle ID, and put your files in that. Apple no longer recommends that, but doesn't really recommend an alternative (short of "use CFPreferences, damnit!"); many apps (e.g., Aquamacs) still do it the old way, but others instead pretend they're not preferences and store them under Application Support.
In Python, this works as follows (leaving out the error handling, and assuming you're going by name instead of setting a bundle ID for yourself):
from Foundation import *
fm = NSFileManager.defaultManager()
appsupport = (fm.URLForDirectory_inDomain_appropriateForURL_create_error_(
NSApplicationSupportDirectory, NSUserDomainMask, None, True, None)[0].
URLByAppendingPathComponent_isDirectory_(
appname, True))
caches = (fm.URLForDirectory_inDomain_appropriateForURL_create_error_(
NSCachesDirectory, NSUserDomainMask, None, True, None)[0].
URLByAppendingPathComponent_isDirectory_(
appname, True))
prefs = NSUserDefaults.persistentDomainForName_(appname)

Overriding PromptService in newer XULRunner

Our application uses embedded xulrunner. We override the default PromptService to provide custom dialogs for alert, prompt, etc by
componentRegistrar.RegisterFactory (PROMPTSERVICE_CID, aClassName, aContractID, MyPromptServiceFactory);
where,
PROMPTSERVICE_CID is "a2112d6a-0e28-421f-b46a-25c0b308cbd0"
CONTRACT_ID is "#mozilla.org/embedcomp/prompt-service;1"
When using XULRunner 1.9.* versions, this works perfectly and the call comes to MyPromptSerivceFactory. But, this doesn't work on newer XULRunner versions (>= 4.0)
I have modified the PROMPTSERVICE_CID to "7ad1b327-6dfa-46ec-9234-f2a620ea7e00" (copied from nsPrompter.manifest). While registering the factory I get the error NS_ERROR_FACTORY_EXISTS.
If I continue to use the old PROMPTSERVICE_CID, then nsIPromptService2 is not used instead nsIWindowCreator2.CreateChromeWindow2 is used to display alerts and prompts.
I have googled on this, but I couldn't find a solution to either fix the NS_ERROR_FACTORY_EXISTS error or for MyPromptServiceFactory to be used.
Any help/suggestions?
It would probably be better to use the existing prompt service the way Firefox does it rather than replace it. If you look at nsPrompter.openPrompt(), before opening a modal dialog it will try to locate and call a JavaScript function getTabModalPrompt() in the window containing the browser. It expects to get a promptBox element back and will call methods appendPrompt() and removePrompt() on it. Obviously, you don't have to give it a promptBox element, just something that behaves similarly - and displays a message any way you like.
But if you really want to replace system components, you shouldn't duplicate prompter's CID - use your own one but #mozilla.org/prompter;1 as contract ID (the old contract ID is for backwards compatibility only).

Resources