How can one address two instances of the same application through osascript - javascript

Can anyone think of a workaround for the osascript index-by-name bottle-neck in its reference to multiple instances of the same application ?
If we obtain two process ids – one for each of two different instances of the same application, osascript returns the same instance in exchange for either pid - as if it first maps the pid to an application name, and then retrieves the first application process with that name.
For example, start two different instances of VLC.app, playing two different video files, with something like:
open -na /Applications/VLC.app ~/fileA.m4v
open -na /Applications/VLC.app ~/fileB.m4v
then obtain the two separate application process ids with, for example:
echo "$(ps -ceo pid=,comm= | awk '/VLC/ { print $1}')"
We can then use Applescript or Yosemite JXA Javascript to get a reference to an application object from either pid.
It turns out, however, that whichever process id we supply, we are always returned a reference to the same instance, running the same video file, as if osascript simply translates a pid to an application name, and then always returns the first process which matches that name.
Yosemite Javascript for applications:
function run() {
var app = Application.currentApplication();
app.includeStandardAdditions = true;
var lstVLC = app.doShellScript(
"echo \"$(ps -ceo pid=,comm= | awk '/VLC/ { print $1}')\""
).split(/[\r\n]/).map(Number).map(Application);
return {
firstInstance: lstVLC[0].windows[0].name(),
secondInstance: lstVLC[1].windows[0].name()
};
}
Applescript:
on run {}
set strCMD to "echo \"$(ps -ceo pid=,comm= | awk '/VLC/ { print $1}')\""
set lstNum to paragraphs of (do shell script strCMD)
repeat with i from 1 to length of lstNum
set item i of lstNum to (item i of lstNum) as number
end repeat
tell application "System Events"
set oProcA to first application process where unix id = (item 1 of lstNum)
set oProcB to first application process where unix id = (item 2 of lstNum)
end tell
return [name of first window of oProcA, name of first window of oProcB]
end run
Any thoughts on a route to scripting each instance separately ?

For each instance, ask the name of the window from the same line as the specific process, like this :
set windowNames to {}
set lstNum to paragraphs of (do shell script "ps -ceo pid=,comm= | awk '/VLC/ { print $1}'")
tell application "System Events" to repeat with i in lstNum
set end of windowNames to name of first window of (first application process where unix id = i)
end repeat
return windowNames

This seems to have been fixed in El Capitan, as your JavaScript code ran fine on my machine.

Using jackjr300's approach in Javascript, to get at least to UI scripting (though not to the Application object interface):
function run() {
var appSE = Application("System Events");
app = Application.currentApplication();
app.includeStandardAdditions = true;
function uiWidgets(lngID) {
return appSE.processes.whose({
unixId: lngID
})[0].windows[0].uiElements();
}
var lstWidgets = app.doShellScript(
"ps -ceo pid=,comm= | awk '/VLC/ { print $1}'"
).split(/\r/).map(Number).map(uiWidgets);
return lstWidgets;
}

JXA is a bundle of bugs and defective design. Its failure to do stuff like this right is depressing, but entirely unsurprising (the AS team has form).
As for AppleScript, it's never provided a direct way to target apps by PID. In the past I may have cheated it by enabling Remote Apple Events and targeting the process with an eppc://USER#HOST/APPNAME?pid=PID URL, but trying it just now on 10.10 damned if I could get it to work as it always returned a "remote access not allowed" error.
Appscript could do this stuff in its sleep, but I dropped public support for it due to Apple's War on Carbon and crappy "replacement" Cocoa APIs forcing it into "legacy" status, so you're on your own there.
The one officially supported option that may work is OS X's Scripting Bridge framework, which provides a method for targeting processes by PID. Though like JXA it's riddled with design flaws, missing features, and application compatibility problems, so YMWV.

Related

net.adoptopenjdk.icedteaweb.shaded.mozilla.javascript.EcmaError: ReferenceError: "java" is not defined. (internal#105)

When trying to invoke a JNLP application with Open Web start , I get this stack trace of errors.
net.adoptopenjdk.icedteaweb.shaded.mozilla.javascript.EcmaError: ReferenceError: "java" is not defined. (internal#105)
at net.adoptopenjdk.icedteaweb.shaded.mozilla.javascript.ScriptRuntime.constructError(ScriptRuntime.java:3557)
at net.adoptopenjdk.icedteaweb.shaded.mozilla.javascript.ScriptRuntime.constructError(ScriptRuntime.java:3535)
at net.adoptopenjdk.icedteaweb.shaded.mozilla.javascript.ScriptRuntime.notFoundError(ScriptRuntime.java:3620)
at net.adoptopenjdk.icedteaweb.shaded.mozilla.javascript.ScriptRuntime.name(ScriptRuntime.java:1652)
at net.adoptopenjdk.icedteaweb.shaded.mozilla.javascript.Interpreter.interpretLoop(Interpreter.java:3413)
at script.dnsResolve(internal:105)
at script.getResolvedIp(http://uhic.ca.edu/toodeepregression3.pac:569)
at script.FindProxyForURL(http://uhic.ca.edu/toodeepregression3.pac:62)
The script at line 569 is..
internalResolvedIp = dnsResolve(host)
if (
host
) {
// If the user has typed an IP address in the address bar, take it
// as it is.
var isIpV4Address = /^(\d+.){3}\d+$/;
var isIpV6Address = /^\[(.*)\]$/;
if (
isIpV4Address.test(host)
) {
internalResolvedIp = host;
} else {
var matches = host.match(isIpV6Address);
if (
matches && matches.length === 2
) {
// Get the address between the square brackets
internalResolvedIp = matches[1];
} else if (
isDnsResolvingAllowed
) {
****internalResolvedIp = dnsResolve(host);****
}
}
}
I am not sure what this error is . I have looked at the Open web start logs as well . I have searched far and wide in the itnernet world but I barely get any hits for this error.
You have clearly hit the Bug, I am trying to resolve in OWS for my Team as well. We have been stuck with this issue for 9 months ever since OWS rolled out.
I can explain you what I discovered so far. Infact I sent my sanitized pac-proy to OWS team to identify the issue but they sent it back to me .
So here is the issue.
OWS has a javascript file in its source code. When you call dnsResolve in your pac-proxy, it invokes the provider of dnsResolve and that implementation is in OWS source code.
Now the dnsResolve call java.net.* package classes internally. This requires Rhino and Java interface to have been stabilized at run time.
OWS is not able to create that interface connection so when javascript tries to call java through the Rhino interface , it can not find java classes since it can not recognize that interface and so comes back to say java not found.
I and my Team are still analyzing the wireshark logs of error to figure out how we could put a fix into OWS or understand how OWS ,Java and Rhino can be successfully talk to each other in the security sandbox container inside which OWS runs.
I could not give u a solution but a better understanding as to where you would like to put your efforts to make it work for u.

Provide an argument from Siri voice input to scriptable or pythonista script?

Does apple yet allow third party apps, like scriptable (javascript) or pythonista (python) to accept arguments provided via Siri voice commands, and if so, how can we access such arguments in a scriptable (javascript) script? If not, is there any work around such that someone can write a scriptable script and have it (somehow) accept some voice input?
What I know so far
Scriptable provides an example of args from a 'share sheet' although it's not entirely clear if it's possible to receive an a similar args variable via Siri voice
// Run from a share sheet to see which
// arguments are shared. Arguments are
// passed to a script when it is run
// from a share sheet.
// Configure the types of arguments
// a script supports from the script
// setttings. This script accepts all
// types of arguments and shows an alert
// with a summary of what ia being shared.
// This is useful to examine which
// values an app shares using the
// share sheet.
let summary = args.plainTexts.length
+ " texts\n"
+ args.images.length
+ " images\n"
+ args.urls.length
+ " URLs\n"
+ args.fileURLs.length
+ " file URLs"
let alert = new Alert()
alert.title = "Shared"
alert.message = summary
alert.addCancelAction("OK")
await alert.presentAlert()
No. Scriptable uses Shortcuts to handle Siri voice commands, which has no support for parameters.
One workaround could be to edit your shortcut to begin dictation before launching your Scriptable script, and passing the results of the dictation to the run script block.
Here's a link to an imgur album with screenshots on how to set up what is described above.

Clear Chrome browser logs in Selenium/Python

I have a large application and I am using Headless Chrome, Selenium and Python to test each module. I want to go through each module and get all the JS console errors produced while inside that specific module.
However, since each module is inside a different test case and each case executes in a separate session, the script first has to login on every test. The login process itself produces a number of errors that show up in the console. When testing each module I don't want the unrelated login errors to appear in the log.
Basically, clear anything that is in the logs right now -> go to the module and do something -> get logs that have been added to the console.
Is this not possible? I tried doing driver.execute_script("console.clear()") but the messages in the console were not removed and the login-related messages were still showing after doing something and printing the logs.
State in 2017 and late 2018
The logging API is not part of the official Webdriver specification yet.
In fact, it's requested to be defined for the level 2 specification. In mid 2017 only the Chromedriver has an undocumented non-standard implementation of that command.
In the sources there's no trace of a method for clearing logs:
The public API Webdriver.get_log()
which references internal Command names
which translate to acutal requests in RemoteConnection
Possible Workaround
The returned (raw) data structure is a dictionary that looks like this:
{
u'source': u'console-api',
u'message': u'http://localhost:7071/console.html 8:9 "error"',
u'timestamp': 1499611688822,
u'level': u'SEVERE'
}
It contains a timestamp that can be remembered so that subsequent calls to get_log() may filter for newer timestamps.
Facade
class WebdriverLogFacade(object):
last_timestamp = 0
def __init__(self, webdriver):
self._webdriver = webdriver
def get_log(self):
last_timestamp = self.last_timestamp
entries = self._webdriver.get_log("browser")
filtered = []
for entry in entries:
# check the logged timestamp against the
# stored timestamp
if entry["timestamp"] > self.last_timestamp:
filtered.append(entry)
# save the last timestamp only if newer
# in this set of logs
if entry["timestamp"] > last_timestamp:
last_timestamp = entry["timestamp"]
# store the very last timestamp
self.last_timestamp = last_timestamp
return filtered
Usage
log_facade = WebdriverLogFacade(driver)
logs = log_facade.get_log()
# more logs will be generated
logs = log_facade.get_log()
# newest log returned only
This thread is a few years old, but in case anyone else finds themselves here trying to solve a similar problem:
I also tried using driver.execute_script('console.clear()') to clear the console log between my login process and the page I wanted to check to no avail.
It turns out that calling driver.get_log('browser') returns the browser log and also clears it.
After navigating through pages for which you want to ignore the console logs, you can clear them with something like
_ = driver.get_log('browser')

Commander.js display help when called with no commands

I'm using commander.js to write a simple node.js program that interacts with an API. All calls require the use of subcommands. For example:
apicommand get
Is called as follows:
program
.version('1.0.0')
.command('get [accountId]')
.description('retrieves account info for the specified account')
.option('-v, --verbose', 'display extended logging information')
.action(getAccount);
What I want to do now is display a default message when apicommand is called without any subcommands. Just like when you call git without a subcommand:
MacBook-Air:Desktop username$ git
usage: git [--version] [--help] [-C <path>] [-c name=value]
[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
[-p | --paginate | --no-pager] [--no-replace-objects] [--bare]
[--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
<command> [<args>]
These are common Git commands used in various situations:
start a working area (see also: git help tutorial)
clone Clone a repository into a new directory
init Create an empty Git repository or reinitialize an existing one
...
You can do something like this by checking what arguments were received and if nothing other than node and <app>.js then display the help text.
program
.version('1.0.0')
.command('get [accountId]')
.description('retrieves account info for the specified account')
.option('-v, --verbose', 'display extended logging information')
.action(getAccount)
.parse(process.argv)
if (process.argv.length < 3) {
program.help()
}
When you're trying to pass a command, it stores the commands in process.argv array.
You can add a conditon like at the end of your code like -:
if(process.argv.length <= 2)
console.log(program.help());
else
program.parse();
What I want to do now is display a default message when apicommand is called without any subcommands. Just like when you call git without a subcommand
The help is automatically displayed from Commander 5 onwards if you call without a subcommand.
(Disclosure: I am a maintainer of Commander.)

Find free port not in use for apps - find some algorithm

I use the following API in my program to detrmine free port and provide it to application to run
portscanner.findAPortNotInUse(3000, 65000, '127.0.0.1', function(error, port) {
console.log('AVAILABLE PORT AT: ' + port)
})
https://github.com/baalexander/node-portscanner
This free port are given to application for use and working OK.
The problem is that if I provide a free port to application A and the application is doesn't occupied it yet(sometimes it takes some time...) and there is coming other application B and request a free port so it give to APP B the port of app A
Which cause to problem...
is there any elegant way to solve it?
my application doesn't have state so it cannot save to which app get which port...
There is solution that we can randomize the range but this is not robust ...
In my application Im getting the URL of the app that I should provide the free port to run.
update
I cannot use some broker or someting else that will controll this outside I need to find some algorithm (maybe with some smart random ) that can help me to do it internally i.e. my program is like singleton and I need some trick how to give port between 50000 to 65000 that will reduce the amount of collision of port that was provided to the apps
update 2
I've decided to try something like the following what do you think ?
using lodash https://lodash.com/docs/4.17.2#random to determine ports between with loops that provide 3(or more if that make sense) numbers for ranges like following
portscanner.findAPortNotInUse([50001, 60000, 600010], '127.0.0.1', function(err, port) {
if(err) {
console.log("error!!!-> " +err);
}else {
console.log('Port Not in Use ' + port);
}
//using that in a loop
var aa = _.random(50000, 65000);
Then If I got false in the port i.e. all 3 port are occupied ,run this process again for 3 other random number.comments suggestion are welcomed!!!
I try to find some way to avoid collision as much as possible...
I would simply accept the fact that things can go wrong in a distributed system and retry the operation (i.e., getting a free port) if it failed for whatever reason on the first attempt.
Luckily, there are lots of npm modules out there that do that already for you, e.g. retry.
Using this module you can retry an asynchronous operation until it succeeds, and configure waiting strategies, and how many times it should be retried maximally, and so on…
To provide a code example, it basically comes down to something such as:
const operation = retry.operation();
operation.attempt(currentAttempt => {
findAnUnusedPortAndUseIt(err => {
if (operation.retry(err)) {
return;
}
callback(err ? operation.mainError() : null);
});
});
The benefits of this solution are:
Works without locking, i.e. it is efficient and makes low usage of resources if everything is fine.
Works without a central broker or something like that.
Works for distributed systems of any size.
Uses a pattern that you can re-use in distributed systems for all kinds of problems.
Uses a battle-tested and solid npm module instead of handwriting all these things.
Does not require you to change your code in a major way, instead it is just adding a few lines.
Hope this helps :-)
If your applications can open ports with option like SO_REUSEADDR, but operation system keeps ports in the list in TIME_WAIT state, you can bind/open port you want to return with SO_REUSEADDR, instantly close it and give it back to application. So for TIME_WAIT period (depending on operation system it can be 30 seconds, and actual time should be decided/set up or found by experiment/administration) port list will show this port as occupied.
If your port finder does not give port numbers for ports in TIME_WAIT state, problem solved by relatively expensive open/close socket operation.
I'd advise you look for a way to retain state. Even temporary state, in memory, is better than nothing at all. This way you could at least avoid giving out ports you've already given out. Because those are very likely not free anymore. (This would be as simple as saving them and regenerating a random port if you notice you found a random port you've already given out). If you don't want collisions, build your module to have state so it can avoid them. If you don't want to do that, you'll have to accept there are going to be collisions sometimes when there don't need to be.
If the URLs you get are random, the best you can do is guess randomly. If you can derive some property in which the URLs uniquely and consistently differ, you could design something around that.
Code example:
function getUnusedPort(url) {
// range is [0, 65001). (inclusive zero, exclusive 65001)
const guessPort = () => Math.floor(Math.random() * 15001) + 50000;
let randomPort = guessPort();
while (checkPortInUse(randomPort)) {
randomPort = guessPort();
}
return randomPort;
}
Notes:
checkPortInUse will probably be asynchronous so you'll have to
accommodate for that.
You said 'between 50000 and 65000'. This is from 50000 up to and including 65000.
When managing multiple applications or multiple servers, where one must be right the first time (without retrying), you need a single source of truth. Applications on the same machine can talk to a database, a broker server or even a file, so long as the resource is "lockable". (Servers work in similar ways, though not with local files).
So your flow would be something like:
App A sends request to service to request lock.
When lock is confirmed, start port scanner
When port is used, release lock.
Again, this could be a "PortService" you write that hands out unused ports, or a simple lock in some shared resource so two things are getting the same port at the same time.
Hopefully you can find something suitable to work for your apps.
As you want to find an port that is not in use in your application, you could do is run following command:
netstat -tupln | awk '{print $4}' | cut -d ':' -f2
so in your application you will use this like:
const exec = require('child_process').exec;
exec('netstat -tupln | awk '{print $4}' | cut -d ':' -f2', (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
return;
}
var listPorts = stdout.split(/\n/)
console.log(listPorts); // list of all ports already in use
var aa = _.random(50000, 65000); // generate random port
var isFree = (listPorts.indexOf(aa)===-1) ? true : false;
if(isFree){
//start your appliation
}else{
// restart the search, write this in a function and start search again
}
});
this should give you list of all ports that are in use,so use any port except ones in the listPorts.

Categories