F#: Breaking out of a loop - for-loop

I am new to programming and F# is my first language.
I have a list of URLs that, when first accessed, either returned HTTP error 404 or experienced gateway timeout. For these URLs, I would like to try accessing them another 3 times. At the end of these 3 attempts, if a WebException error is still thrown, I will assume that the URL doesn't exist, and I will add it to a text file containing all of the invalid URLs.
Here is my code:
let tryAccessingAgain (url: string) (numAttempts: int) =
async {
for attempt = 1 to numAttempts do
try
let! html = fetchHtmlAsync url
let name = getNameFromPage html
let id = getIdFromUrl url
let newTextFile = File.Create(htmlDirectory + "\\" + id.ToString("00000") + " " + name.TrimEnd([|' '|]) + ".html")
use file = new StreamWriter(newTextFile)
file.Write(html)
file.Close()
with
:? System.Net.WebException -> File.AppendAllText("G:\User\Invalid URLs.txt", url + "\n")
}
I have tested fetchHtmlAsync, getNameFromPage and getIdFromUrl in F# Interactive. All of them work fine.
If I succeed in downloading the HTML contents of a URL without using all 3 attempts, obviously I want to break out of the for-loop immediately. My question is: How may I do so?

use recursion instead of the loop:
let rec tryAccessingAgain (url: string) (numAttempts: int) =
async {
if numAttempts > 0 then
try
let! html = fetchHtmlAsync url
let name = getNameFromPage html
let id = getIdFromUrl url
let newTextFile = File.Create(htmlDirectory + "\\" + id.ToString("00000") + " " + name.TrimEnd([|' '|]) + ".html")
use file = new StreamWriter(newTextFile)
file.Write(html)
file.Close()
with
| :? System.Net.WebException ->
File.AppendAllText("G:\User\Invalid URLs.txt", url + "\n")
return! tryAccessingAgain url (numAttempts-1)
}
please note that I could not test it and there might be some syntax errors - sorry if
as we are at it - you might want to rewrite the logging of the invalid url like this:
let rec tryAccessingAgain (url: string) (numAttempts: int) =
async {
if numAttempts <= 0 then
File.AppendAllText("G:\User\Invalid URLs.txt", url + "\n")
else
try
let! html = fetchHtmlAsync url
let name = getNameFromPage html
let id = getIdFromUrl url
let newTextFile = File.Create(htmlDirectory + "\\" + id.ToString("00000") + " " + name.TrimEnd([|' '|]) + ".html")
use file = new StreamWriter(newTextFile)
file.Write(html)
file.Close()
with
| :? System.Net.WebException ->
return! tryAccessingAgain url (numAttempts-1)
}
this way it will only be logged once the attempts where all made

Related

How do I accept a literal "*" as a command-line argument?

I am writing a very simple command line calculator in rust, getting a number ,an operator, then another number and do the calculation and print the result. To show what I am getting from command args, I have printed them in a loop before the main code. I works fine for plus, minus and division, but for multiplication I get unexpected result, as I print it, instead of a star (*) for multiplication, I get the files list on my current directory.
Here is my rust code, I will appreciate an explanation and if there is any workaround.
use std::env;
fn main(){
let args: Vec<String> = env::args().collect();
for arg in args.iter(){
println!("{}", arg);
}
let mut result = 0;
let opt = args[2].to_string();
let oper1 = args[1].parse::<i32>().unwrap();
let oper2 = args[3].parse::<i32>().unwrap();
match opt.as_ref(){
"+" => result = oper1 + oper2,
"-" => result = oper1 - oper2,
"*" => result = oper1 * oper2,
"/" => result = oper1 / oper2,
_ => println!("Error")
}
println!("{} {} {} = {}", oper1, opt, oper2, result);
}
The wildcard (*) is expanding out. The shell is going to send this out to the program before it even sees what you actually typed
You can read more about here.
To avoid this, you can just wrap it in quotes, like so:
./program 1 "*" 1

Bing custom search apis returning only limited results from one location and full result from different location

I am trying to use Bing Custom Search's API for documents from Cognitive Services. The strange thing is that when I run it from India, it gives me more than a thousand results, but when I run it from a US server, it returns only 25 (sometimes 50 results). Here is the sample code for that:
var totalCount = 0;
var filetypes = new List<string> { "pdf", "docx", "doc" };
foreach (var filetype in filetypes)
{
var searchTerm = "microsoft%20.net%20resume+filetype%3a" + filetype;
Console.WriteLine("Searching for : " + filetype);
for (var i = 0; i < 40; i++)
{
var nextCount = 0;
var url = "https://api.cognitive.microsoft.com/bingcustomsearch/v7.0/search?" +
"q=" + searchTerm +
"&customconfig=" + customConfigId +
"&count=25" + "&offset=" + ((i * 25) + nextCount);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", subscriptionKey);
var httpResponseMessage = client.GetAsync(url).Result;
var responseContent = httpResponseMessage.Content.ReadAsStringAsync().Result;
BingCustomSearchResponse response =
JsonConvert.DeserializeObject<BingCustomSearchResponse>(responseContent);
if (response.webPages == null || response.webPages.value.Length <= 0)
{
Console.WriteLine("response.webPages is null ");
break;
}
foreach (var webPage in response.webPages.value)
{
Console.WriteLine("name: " + webPage.name);
Console.WriteLine("url: " + webPage.url);
Console.WriteLine("displayUrl: " + webPage.displayUrl);
Console.WriteLine("snippet: " + webPage.snippet);
Console.WriteLine("dateLastCrawled: " + webPage.dateLastCrawled);
Console.WriteLine();
}
totalCount = totalCount + response.webPages.value.Length;
}
}
}
The subscription key I am using is a trial key.
I got the reason of this behavior. Actually it had nothing to do with region/country/market.
After looking into the response i got this message.
"Rate limit is exceeded. Try again in 1 seconds"
It means for after each call in the loop i have to wait for 1 second to give next call. Now need to know is this limit for trial subscription or this is kept for all calls to prevent DDOS attack or something.
May be from India it was working because may one iteraction is already taking one or more second.
Two things you can try: 1) In searchTerm, no need to use %20 and %3a, just use punctuations as you type in Bing, e.g. var searchTerm = "microsoft.net resume filetype::"+filetype, and 2) Enforce market by appending mkt=en-in (for India) or en-us (for US) in the query. You can do this by appending +"&mkt=en-in" at the end of url.
I presume for custom search you have selected domains (for both en-in and en-us markets) that return thousands of results for this query.

Getting below error while running ruby script

I am running a test suite in Soap UI where I am trying to call one ruby script from groovy script. The step is getting executed successfully but still the script is not able to move on to the next step as it gives this error after running.
Have searched in google about this error, but found no proper resolution. Moreover the error itself is not very explanatory.
Will appreciate any kind of help.
Below is the groovy script which is calling "ap-v4-batch_DEV_QA.rb" ruby script.
This ruby script opens a browser and performs the task successfully and closes the browser. We expect the step to be marked as Passed so that it can move on to the next step, but it gives the error mentioned at the bottom.
Groovy Script:
String script = "webdriver/v4/ap-v4-batch_DEV_QA.rb";
String argv0 = com.eviware.soapui.SoapUI.globalProperties.getPropertyValue("GLOB_DefaultIP");
String argv1 = "com.wupay.batch.process.tasks.PaymentFileParsingTask_RunOnce";
String argv2 = "";
String argv3 = "";
String argv4 = "";
/* Nothing needs to be modified below */
String commandLine = "ruby " + com.eviware.soapui.SoapUI.globalProperties.getPropertyValue("GLOB_ScriptLocation") + "/" + script + " " + argv0 + " " + argv1 + " " + argv2 + " " + argv3 + " " + argv4;
log.info("Running command line: " + commandLine);
java.lang.Runtime runtime = java.lang.Runtime.getRuntime();
java.lang.Process p = runtime.exec(commandLine);
def propertyStep = testRunner.testCase.getTestStepByName("Properties");
java.io.BufferedReader stdInput =
new java.io.BufferedReader(new java.io.InputStreamReader(p.getInputStream()));
java.io.BufferedReader stdError =
new java.io.BufferedReader(new java.io.InputStreamReader(p.getErrorStream()));
String s = null;
String e = null;
StringBuffer eb = new StringBuffer();
while ((e = stdError.readLine()) != null) {
eb.append(e);
log.error("Ruby: " + e);
}
while ((s = stdInput.readLine()) != null) {
log.info("Ruby: " + s);
if(s.startsWith("#prop")) {
String[] propSplit = s.split(":", 3);
testRunner.testCase.setPropertyValue(propSplit[1], propSplit[2]);
}
}
p.waitFor();
log.info("Ruby: exit value " + p.exitValue());
if(eb.length() > 0) {
throw new Exception(eb.toString());
}
Error:
java.lang.Exception: C:/Ruby23/lib/ruby/site_ruby/2.3.0/rubygems/core_ext/kernel_require.rb:133:in require':require "watir-webdriver"is deprecated. Please, userequire "watir". java.lang.Exception: C:/Ruby23/lib/ruby/site_ruby/2.3.0/rubygems/core_ext/kernel_require.rb:133:inrequire': require "watir-webdriver" is deprecated. Please, use require "watir". error at line: 57
I have finally resolved the issue.
The issue was that ruby script was not accepting require "watir-webdriver".
I installed watir and replaced require "watir-webdriver" with require "watir".
now I am not getting the above mentioned error.
Thanks anyways!
Regards,
Faraz

JMeter asserting a response has been successfully downloaded

I am using JMeter to test some of the functionality on my site. Through using the Save Responses to a file element, I have been able to successfully issue a request to download a pdf through JMeter. However, I am curious if there is an assertion to check that a file has actually downloaded (and if possible, is in the format I specified!). I know I can simply look at the file, but I'm hoping to make this more automated. I have checked "Save Successful Responses Only," but I want to ensure a response has actually been saved.
I think you need to use a Beanshell Assertion for this.
Example code to check file presence, size and content type is below:
File file = new File("/path/to/downloaded/file");
//check file existence
if (!file.exists())
{
Failure = true;
FailureMessage = "File " + file.getName() + " does not exist";
}
//check file size
long expectedSize = SampleResult.getBodySize();
long actualSize = file.length();
if (expectedSize != actualSize)
{
Failure = true;
FailureMessage = "Actual file size differs from expected. Expected: " + expectedSize + " and got: " + actualSize ;
}
//check content type
String expectedType = SampleResult.getContentType();
String actualType = file.toURI().toURL().openConnection().getContentType();
if (!expectedType.equals(actualType))
{
Failure = true;
FailureMessage = "Response types are different. Expected: " + expectedType + " and got: " + actualType;
}
See How to Use JMeter Assertions in 3 Easy Steps guide for more information on JMeter Assertions superpower.

Script Works on Win 7, Not on Server 2003

I have a script that is rather simple, it boots up WinSCP and checks the directory for a file that starts with "TSA". If the file exists, it exits, if it does not exist, it transfers over a new file.
Its up and running on my Windows 7 machine, that is where i created it - but when i transfer it over to my server [windows server 2003] it never finds the file.
My script:
var FILEPATH = "../zfinance/TSA";
// Session to connect to
var SESSION = "someplace#somewhere.com";
// Path to winscp.com
var WINSCP = "c:\\program files\\winscp\\winscp.com";
var filesys = WScript.CreateObject("Scripting.FileSystemObject");
var shell = WScript.CreateObject("WScript.Shell");
var logfilepath = filesys.GetSpecialFolder(2) + "\\" + filesys.GetTempName() + ".xml";
var p = FILEPATH.lastIndexOf('/');
var path = FILEPATH.substring(0, p);
var filename = FILEPATH.substring(p + 1);
var exec;
// run winscp to check for file existence
exec = shell.Exec("\"" + WINSCP + "\" /log=\"" + logfilepath + "\"");
exec.StdIn.Write(
"option batch abort\n" +
"open \"" + SESSION + "\"\n" +
"ls \"" + path + "\"\n" +
"exit\n");
// wait until the script finishes
while (exec.Status == 0)
{
WScript.Sleep(100);
WScript.Echo(exec.StdOut.ReadAll());
}
if (exec.ExitCode != 0)
{
WScript.Echo("Error checking for file existence");
WScript.Quit(1);
}
// look for log file
var logfile = filesys.GetFile(logfilepath);
if (logfile == null)
{
WScript.Echo("Cannot find log file");
WScript.Quit(1);
}
// parse XML log file
var doc = new ActiveXObject("MSXML2.DOMDocument");
doc.async = false;
doc.load(logfilepath);
doc.setProperty("SelectionNamespaces",
"xmlns:w='http://winscp.net/schema/session/1.0'");
doc.setProperty("SelectionLanguage", "XPath");
var nodes = doc.selectNodes("//w:file/w:filename[starts-with(#value, '" + filename + "')]");
if (nodes.length > 0)
{
WScript.Echo("File found");
WScript.Quit(0);
}
else
{
WScript.Echo("File not found");
WScript.Quit(1);
}
After much investigation, i think i've found the piece of code that does not function properly:
// parse XML log file
var doc = new ActiveXObject("MSXML2.DOMDocument.6.0");
doc.async = false;
doc.load(logfilepath);
doc.setProperty("SelectionNamespaces",
"xmlns:w='http://winscp.net/schema/session/1.0'");
The only problem is, i have no idea why. The log file at this point should be written over with the xml code, but this does not happen.
Thanks in advance for any help.
And the answer is........... WinSCP on Windows Server 2003 was WAY out of date. So out of date that the log was completely different from one version to the next. Updated and VIOLA! Problem solved. Thanks for your help.
Maybe you need to install MSXML2.DOMDocument.6.0
http://msdn.microsoft.com/en-us/library/windows/desktop/cc507436%28v=vs.85%29.aspx
If you open up regedit and look for "MSXML2.DOMDocument.6.0" does it find it? If so maybe security settings for the script need to be set in order to be able to create an activeX object.
What can you see when you put some stuff in try catch?
try{
//stuff
}catch(e){
WScript.Echo(e.message);
}

Resources