I have a JavaScript code that I need to get into console application. The script works fine trough cmd but I want to make a console application out of it so its more user friendly. Can someone explain to me how I can write this code in console application or attach it inside the console application with links. I am new to console application so I apologize if I ask anything stupid :-)
When I use it trough cmd then I do the following;
- Run cmd.
- Type "cd downloads" and press enter.
- Type "cscript /nologo process.js log.txt 100 200" and press enter.
- Then I will get a list in the cmd window and I need to have process.js and log.txt in the download folder to make this work.
if(WScript.Arguments.Count() < 3)
{
WScript.Echo("Usage: cscript process.js <filename> <lower_value> <upper_value>");
WScript.Quit();
}
var filename = WScript.Arguments.Item(0);
var lowerBound = parseInt(WScript.Arguments.Item(1));
var upperBound = parseInt(WScript.Arguments.Item(2));
WScript.Echo("Here is the data from the file associated with the text 'verdi', where the");
WScript.Echo("number following 'verdi' is above " + lowerBound + " and below " + upperBound);
var fso = new ActiveXObject("Scripting.FileSystemObject")
var file = fso.OpenTextFile("log.txt", 1, false);
var lines = file.ReadAll().split('\r');
var failed = 0;
for(var idx in lines)
{
try
{
if(lines[idx].indexOf('verdi') > 0)
{
var tmp = lines[idx];
var regex = /verdi\s*\=\s*(\d+)/;
var result = regex.exec(tmp);
var num = parseInt(result[1]);
if(num >= lowerBound && num <= upperBound)
{
WScript.Echo(num);
}
}
}
catch(ex)
{
failed++;
}
}
if(failed > 0)
{
WScript.Echo("WARNING: one or more lines could not be processed!");
}
I have made this code in console application but it doesent work properly. I can choose the values and get the cmd to run. But I don't get the results in the window and print the result to a document.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication3
{
class Program
{
private static object cmd;
private static int verdi;
private static int s;
private static int d;
public static object WScript { get; private set; }
static void Main(string[] args)
{
//Choose lower and upper value
Console.WriteLine("Choose a lower and upper value:");
string value = Console.ReadLine();
//Choose file
Console.WriteLine("Choose a file to scan:");
string file = Console.ReadLine();
//Run the javascript code
Console.WriteLine("cd downloads");
Console.WriteLine("cscript /nologo process.js {0} {1} > mydata.txt", file, value);
string command = Console.ReadLine();
Console.WriteLine("Press any key to start scan");
System.Diagnostics.Process.Start("cmd.exe", "/C" + command);
//Quit Console Application
Console.WriteLine("Press any key to quit.");
Console.ReadKey();
}
}
}
Console.WriteLine only prints strings. It doesn't allow you to execute commands.
You could try this instead:
string command = $"cscript /nologo c:/downloads/process.js c:/downloads/{file} {lowerValue} {upperValue} > mydata.txt");
System.Diagnostics.Process.Start($"cmd.exe /C {command}");
There is also an error in process.js. That script always reads from log.txt and ignores the filename.
But why are you using two programs here? You could just have all the code in one file. And why use JavaScript for one and C# for the other?
Related
I am trying to write a JXA script in Apple Script Editor, that compresses a string using the LZ algorithm and writes it to a text (JSON) file:
var story = "Once upon a time in Silicon Valley..."
var storyC = LZString.compress(story)
var data_to_write = "{\x22test\x22\x20:\x20\x22"+storyC+"\x22}"
app.displayAlert(data_to_write)
var desktopString = app.pathTo("desktop").toString()
var file = `${desktopString}/test.json`
writeTextToFile(data_to_write, file, true)
Everything works, except that the LZ compressed string is just transformed to a set of "?" by the time it reaches the output file, test.json.
It should look like:
{"test" : "㲃냆Њޱᐈ攀렒삶퓲ٔ쀛䳂䨀푖㢈Ӱນꀀ"}
Instead it looks like:
{"test" : "????????????????????"}
I have a feeling the conversion is happening in the app.write command used by the writeTextToFile() function (which I pulled from an example in Apple's Mac Automation Scripting Guide):
var app = Application.currentApplication()
app.includeStandardAdditions = true
function writeTextToFile(text, file, overwriteExistingContent) {
try {
// Convert the file to a string
var fileString = file.toString()
// Open the file for writing
var openedFile = app.openForAccess(Path(fileString), { writePermission: true })
// Clear the file if content should be overwritten
if (overwriteExistingContent) {
app.setEof(openedFile, { to: 0 })
}
// Write the new content to the file
app.write(text, { to: openedFile, startingAt: app.getEof(openedFile) })
// Close the file
app.closeAccess(openedFile)
// Return a boolean indicating that writing was successful
return true
}
catch(error) {
try {
// Close the file
app.closeAccess(file)
}
catch(error) {
// Report the error is closing failed
console.log(`Couldn't close file: ${error}`)
}
// Return a boolean indicating that writing was successful
return false
}
}
Is there a substitute command for app.write that maintains the LZ compressed string / a better way to accomplish what I am trying to do?
In addition, I am using the readFile() function (also from the Scripting Guide) to load the LZ string back into the script:
function readFile(file) {
// Convert the file to a string
var fileString = file.toString()
// Read the file and return its contents
return app.read(Path(fileString))
}
But rather than returning:
{"test" : "㲃냆Њޱᐈ攀렒삶퓲ٔ쀛䳂䨀푖㢈Ӱນꀀ"}
It is returning:
"{\"test\" : \"㲃냆੠Њޱᐈ攀렒삶퓲ٔ쀛䳂䨀푖㢈Ӱນꀀ\"}"
Does anybody know a fix for this too?
I know that it is possible to use Cocoa in JXA scripts, so maybe the solution lies therein?
I am just getting to grips with JavaScript so I'll admit trying to grasp Objective-C or Swift is way beyond me right now.
I look forward to any solutions and/or pointers that you might be able to provide me. Thanks in advance!
After some further Googl'ing, I came across these two posts:
How can I write UTF-8 files using JavaScript for Mac Automation?
read file as class utf8
I have thus altered my script accordingly.
writeTextToFile() now looks like:
function writeTextToFile(text, file) {
// source: https://stackoverflow.com/a/44293869/11616368
var nsStr = $.NSString.alloc.initWithUTF8String(text)
var nsPath = $(file).stringByStandardizingPath
var successBool = nsStr.writeToFileAtomicallyEncodingError(nsPath, false, $.NSUTF8StringEncoding, null)
if (!successBool) {
throw new Error("function writeFile ERROR:\nWrite to File FAILED for:\n" + file)
}
return successBool
};
While readFile() looks like:
ObjC.import('Foundation')
const readFile = function (path, encoding) {
// source: https://github.com/JXA-Cookbook/JXA-Cookbook/issues/25#issuecomment-271204038
pathString = path.toString()
!encoding && (encoding = $.NSUTF8StringEncoding)
const fm = $.NSFileManager.defaultManager
const data = fm.contentsAtPath(pathString)
const str = $.NSString.alloc.initWithDataEncoding(data, encoding)
return ObjC.unwrap(str)
};
Both use Objective-C to overcome app.write and app.read's inability to handle UTF-8.
Using the browser if I visit a certain direct download URL, it automatically downloads the file. However, when I use Java code to download the file, I get the HTML code instead of the file contents:
<html>
<body>
<script type="text/javascript" src="/aes.js"></script>
<script>function toNumbers(d) {
var e = [];
d.replace(/(..)/g, function (d) {
e.push(parseInt(d, 16))
});
return e
}
function toHex() {
for (var d = [], d = 1 == arguments.length && arguments[0].constructor == Array ? arguments[0] : arguments, e = "", f = 0; f < d.length; f++) e += (16 > d[f] ? "0" : "") + d[f].toString(16);
return e.toLowerCase()
}
var a = toNumbers("f655ba9d09a112d4968c63579db590b4"), b = toNumbers("98344c2eee86c3994890592585b49f80"),
c = toNumbers("b5eb8dc5c53e5107faa7ec1c1f3e3dc7");
document.cookie = "__test=" + toHex(slowAES.decrypt(c, 2, a, b)) + "; expires=Thu, 31-Dec-37 23:55:55 GMT; path=/";
location.href = "http://example.com/Test.txt?i=1";</script>
<noscript>This site requires Javascript to work, please enable Javascript in your browser or use a browser with
Javascript support
</noscript>
</body>
</html>
My file downloading code is e.g. the following:
URL url = new URL("...");
try (InputStream inputStream = url.openStream())
{
Files.copy(inputStream, downloadedFilePath, REPLACE_EXISTING);
}
How would it be possible to download the file programmatically in Java? There are ways to execute JavaScript but how is it supposed to work exactly? It seems like the document.cookie has to be set (correctly) to download.
Downloading works by passing the correct cookie value alongside of the request. The cookie value can be retrieved using e.g. the Google Chrome DevTools -> Application -> Cookies. Since in my example the cookie value does not change, a code like the following would do the trick:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class DownloadWithCookieExample
{
public static void main(String[] arguments)
{
try
{
URL url = new URL("...");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestProperty("Cookie", "blabla"); // Hard-coded correct cookie value
String readStream = readStream(con.getInputStream());
System.out.println(readStream);
} catch (Exception exception)
{
exception.printStackTrace();
}
}
private static String readStream(InputStream inputStream) throws IOException
{
StringBuilder stringBuilder = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)))
{
String line;
while ((line = reader.readLine()) != null)
{
stringBuilder.append(line);
stringBuilder.append(System.lineSeparator());
}
}
return stringBuilder.toString().trim();
}
}
An even better solution would be to execute the JavaScript to receive the cookie value and to pass the result. This task is left as an exercise for another answer for whoever knows how to do this elegantly.
I want to retrieve data from a website using Nashorn script engine
I have the java code where I can retrieve data from a sample website template.
Now I want to call that java file from java script file.
following is the code:
JAVA CODE(Nsample.java):
package sample;
import java.net.*;
import java.io.*;
public class Nsample
{
public static void main(String[] args)
{
String output = getUrlContents("https://freewebsitetemplates.com/");
System.out.println(output);
}
public static String getUrlContents(String theUrl)
{
StringBuilder content = new StringBuilder();
try
{
URL url = new URL(theUrl);
URLConnection urlConnection = url.openConnection();
BufferedReader bufferedReader = new BufferedReader(new
InputStreamReader(urlConnection.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null)
{
content.append(line + "\n");
}
bufferedReader.close();
}
catch(Exception e)
{
e.printStackTrace();
}
return content.toString();
}
}
JAVASCRIPT code:(sample.js)
var n = Java.type('C.JavaFolder.sample.Nsample');
var result = n.getUrlContents("https://freewebsitetemplates.com/");
print(result);
I'm trying to compile javascript code using command prompt but it is showing CLASSNOTFOUNDEXCEPTION.
The command was jjs sample.js.Im assuming I did some mistake in Java.type() function.
Can anyone solve this?
This line is the problematic line:
var n = Java.type('C.JavaFolder.sample.Nsample');
Java.type accepts fully qualified java type name. Based on your Java code, your package seems to be "sample" and class name is "Nsample". So the fully qualified class name would be "sample.Nsample".
You should compile your Java classes and specify the directory in -classpath option (of jjs tool or your java application if you use javax.script API with nashorn).
Instead of calling Java from JavaScript , I tried to call JavaScript from java and worked well.
I created some functions in JavaScript and invoked those functions from Java code.
Following is the code.Hope this helps.
Test.java:
import javax.script.*;
import java.io.*;
import java.util.*;
public class Test{
public static void main(String[] args) throws Exception{
ScriptEngine engine = new ScriptEngineManager().getEngineByName("Nashorn");
engine.eval(new FileReader("test.js"));
Invocable invoke = (Invocable)engine;
Object res = invoke.invokeFunction("httpGet","https://www.javaworld.com");
System.out.println(res);
}
}
test.js:
var httpGet = function(theUrl){
var con = new java.net.URL(theUrl).openConnection();
con.requestMethod = "GET";
return asResponse(con);
}
function asResponse(con){
var d = read(con.inputStream);
return d;
}
function read(inputStream){
var inReader = new java.io.BufferedReader(new
java.io.InputStreamReader(inputStream));
var inputLine;
var response = new java.lang.StringBuffer();
while ((inputLine = inReader.readLine()) != null) {
response.append(inputLine);
}
inReader.close();
return response.toString();
}
I have created a native iOS app (Xcode 5.1), and I want to open via a btn, a cordova(Cordova 2.9.0) web view(Otherwise CDVViewController). I've succeed this and the web view works and it shows me the webpage, but when I embed the cordova.js (inside the webpage), the
CDVCommandQueue.m
- (void)fetchCommandsFromJs
{
// Grab all the queued commands from the JS side.
NSString* queuedCommandsJSON = [_viewController.webView stringByEvaluatingJavaScriptFromString:
#"cordova.require('cordova/exec').nativeFetchMessages()"];
NSLog(#"---- %#",queuedCommandsJSON);
[self enqueCommandBatch:queuedCommandsJSON];
if ([queuedCommandsJSON length] > 0) {
CDV_EXEC_LOG(#"Exec: Retrieved new exec messages by request.");
}
}
calls the above function and it executes the 'cordova.require('cordova/exec').nativeFetchMessages()',
this function returns
[["Device748313476","Device","getDeviceInfo",[]],["NetworkStatus748313477","NetworkStatus","getConnectionInfo",[]]]
and then it passes this value to
- (void)executePending
{
// Make us re-entrant-safe.
if (_currentlyExecuting) {
return;
}
#try {
_currentlyExecuting = YES;
for (NSUInteger i = 0; i < [_queue count]; ++i) {
// Parse the returned JSON array.
NSLog(#"%#",[_queue objectAtIndex:i]);
**NSArray* commandBatch = [[_queue objectAtIndex:i] JSONObject];**
// Iterate over and execute all of the commands.
for (NSArray* jsonEntry in commandBatch) {
CDVInvokedUrlCommand* command = [CDVInvokedUrlCommand commandFromJson:jsonEntry];
CDV_EXEC_LOG(#"Exec(%#): Calling %#.%#", command.callbackId, command.className, command.methodName);
if (![self execute:command]) {
#ifdef DEBUG
NSString* commandJson = [jsonEntry JSONString];
static NSUInteger maxLogLength = 1024;
NSString* commandString = ([commandJson length] > maxLogLength) ?
[NSString stringWithFormat:#"%#[...]", [commandJson substringToIndex:maxLogLength]] :
commandJson;
DLog(#"FAILED pluginJSON = %#", commandString);
#endif
}
}
}
[_queue removeAllObjects];
} #finally
{
_currentlyExecuting = NO;
}
}
My app is crashing because on this line
NSArray* commandBatch = [[_queue objectAtIndex:i] JSONObject];
doesn't recognize the value as json object and it gives me this error message
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString JSONObject]: unrecognized selector sent to instance
Thanks a lot.
Had the same recently, while was building old cordova app in new Xcode.
You should check Other linker flags in Your target settings:
For the debug build configuration You could use -ObjC flag. (What does the -ObjC linker flag do?, Why do I get a runtime exception of "selector not recognized" when linking against an Objective-C static library that contains categories?)
If after reading previous links, You still want to use this flag in release — just do it.
Otherwise, You should add -force_load ${BUILT_PRODUCTS_DIR}/libCordova.a to the release linker flag.
In order to check/edit active build configuration go to Product > Scheme > Edit scheme (Cmd <).
I've put together a very simple program that uses JavaScriptCore to evaluate JS:
#import <CoreFoundation/CoreFoundation.h>
#import <JavaScriptCore/JavaScriptCore.h>
int main(int argc, const char * argv[])
{
JSGlobalContextRef ctx = JSGlobalContextCreate(NULL);
FILE *f = fopen(argv[1],"r");
char * buffer = malloc(10000000);
fread(buffer,1,10000000,f);
CFStringRef strs = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingASCII);
JSStringRef jsstr = JSStringCreateWithCFString(strs);
JSValueRef result = JSEvaluateScript(ctx, jsstr, NULL, NULL, 0, NULL);
double res = JSValueToNumber(ctx, result, NULL);
JSGlobalContextRelease(ctx);
printf("%lf\n", res);
return 0;
}
The idea here is that the last value is expected to be a Number, and that value is printed. This works for valid javascript code, such as
var square = function(x) { return x*x; }; square(4)
However, if the code tries to perform a console.log, the program segfaults. Is there a log function available in JSC or do I have to roll my own?
You do have to provide your own console log if using the JavaScriptCore framework from Mac or IOS.
Here is some code that worked for me (sorry it is Objective-C rather than standard C as per your code above):
JSContext *javascriptContext = [[JSContext alloc] init];
javascriptContext[#"consoleLog"] = ^(NSString *message) {
NSLog(#"Javascript log: %#",message);
};
Then you use it from Javascript by:
consoleLog("My debug message");
Note that I have tried to define a vararg version (log taking multiple parameters) but I couldn't get this to work correctly across the framework api.
Note that this solution uses features introduced with the new Objective-C API for the JavaScriptCore.framework introduced at the same time as IOS 7. If you are looking for an intro to this well-integrated bridge between Objective-C and Javascript, check out the 2013 WWDC introduction "Integrating JavaScript into Native Apps" session on Apple's developer network: https://developer.apple.com/videos/wwdc/2013/?id=615
Update to answer:
For those of you wanting to maximise your javascript code reuse without refactoring, I've managed to get a version working that declares a log of the form console.log() :
JSContext *javascriptContext = [[JSContext alloc] init];
[javascriptContext evaluateScript:#"var console = {}"];
javascriptContext[#"console"][#"log"] = ^(NSString *message) {
NSLog(#"Javascript log: %#",message);
};
Then you use it from Javascript by:
console.log("My debug message");
Swift 3.0
let javascriptContext = JSContext()
javascriptContext?.evaluateScript("var console = { log: function(message) { _consoleLog(message) } }")
let consoleLog: #convention(block) (String) -> Void = { message in
print("console.log: " + message)
}
javascriptContext?.setObject(unsafeBitCast(consoleLog, to: AnyObject.self), forKeyedSubscript: "_consoleLog" as (NSCopying & NSObjectProtocol)!)
Swift 2.1
let javascriptContext = JSContext()
javascriptContext.evaluateScript("var console = { log: function(message) { _consoleLog(message) } }")
let consoleLog: #convention(block) String -> Void = { message in
print("console.log: " + message)
}
javascriptContext.setObject(unsafeBitCast(consoleLog, AnyObject.self), forKeyedSubscript: "_consoleLog")
Then you use it from Javascript by:
console.log("My debug message");
self.jsContext = JSContext()
self.jsContext.evaluateScript(...)
let logFunction: #convention(block) (String) -> Void = { (string: String) in
print(string)
}
self.jsContext.setObject(logFunction, forKeyedSubscript: "consoleLog" as NSCopying & NSObjectProtocol)
You can debug JS file attached to context in Safari.
Steps:
1) Start Safari
2) In Safari, enable the Develop menu by going to "Preferences" -> "Advanced" -> "Show Develop menu in menu bar"
3) Go to Develop menu -> "Simulator" or name of your computer -> select "Automatically show web inspector for JSContexts" and "Automatically pause connecting to JSContexts"
4) Re-run your project and Safari should auto-show the web inspector
Swift 5.0
The other suggestions didn't work for me, so I found a web post that explains how to do it now.Essentially
let logFunction: #convention(block) (String) -> Void = { string in
print("JS_Console:", string)
}
if let console = context.objectForKeyedSubscript("console") {
console.setObject(logFunction, forKeyedSubscript: "log") // works for me
// is this needed? "console.setObject(unsafeBitCast(logFunction, to: AnyObject.self), forKeyedSubscript: "log")
}
log.console is variadic, but I could find no way to utilize it even though the link above suggests it's possible. What I did discover though is that you can use JavaScript interpolation to get values, for example:
console.log(`getCombinedFrameYaw: ${frameYaw} rot=${pathRotation}`)