Erroring in my Perl script coming from CAM::PDF::Annot module. Don't know why - perl

I believe this may be a bug in the module I am using, or I am just completely overlooking something.
My code is this:
#!/usr/bin/perl
use strict;
use warnings;
use CAM::PDF;
use CAM::PDF::Annot;
sub main()
{
my $pdf = CAM::PDF::Annot->new( 'b.pdf' );
my $otherDoc = CAM::PDF::Annot->new( 'b_an.pdf' );
my $page = 1;
my %refs;
my #list = #{$pdf->getAnnotations($page)};
for my $annotRef (#list){
$otherDoc->appendAnnotation( $page, $pdf, $annotRef, \%refs);
}
$otherDoc->output('pdf_merged.pdf');
}
exit main;
This code was taken almost directly from the synopsis found on the module's CPAN page: http://metacpan.org/pod/CAM::PDF::Annot
The problem comes when I run the script using TWO pdf's with annotations. Using two pdf's without annotations runs. Using one pdf with annotations, and one pdf without annotations, runs. Only when both pdf's have annotations does it error.
The error is: "Can't use string ("46") as an ARRAY ref while "strict refs" in use at /usr/opt/perl5/lib/site_perl/5.10.1/CAM/PDF/Annot.pm line 195"
Line 195 of Annot.pm is:
push #{$annots->{value}}, $pupRef;
Annot.pm is inside the CAM::PDF::Annot module.
Any guidance in fixing this would be greatly appreciated!
P.S. In the error, "string ("x")", x is always a number, and seems to change depending on the pdf and the annotations within the pdf.
And I will try to add any other information that you need to help figure this out!

Whenever I have a problem with a CPAN module, I go to its webpage to try and assess its quality and see if any bugs have already been reported.
http://search.cpan.org/~donatoaz/CAM-PDF-Annot-0.06 shows the following suspicious results:
CPAN Testers PASS (2) FAIL (168) NA (49)
It is surprising that you were able to install the module. No one has reported bugs, but there is clearly a major problem with the code. It seems the author is either unaware of the tester reports (which have been sent to his CPAN email address for more than a year), or has stopped maintaining it.
You could submit a bug report, so at least others will be aware of your issue.
I realize this does not answer your question of how to fix the problem, but even if you do identify a fix, the author may not apply it (in which case, someone could start the process of becoming a co-maintaner).

Related

How can I fix `"main::HKEY_LOCAL_MACHINE" used only once` warnings when using Perl's Win32::Registry?

I have a script that would get a registry key value. Here's the code.
use strict;
use warnings;
my $winRegistryStatus=0;
eval {
require Win32::Registry;
Win32::Registry->import();
};
unless($#) {
$winRegistryStatus=1;
}
my $registryPath = "Self\Random";
my $keyName = "Configure";
my $registryKeySettings;
my %registrySubKeyValues;
$main::HKEY_LOCAL_MACHINE->Open($registryPath, $registryKeySettings) || die "Cannot open $registryPath: $!";
$registryKeySettings->GetValues(\%registrySubKeyValues); # get sub keys and value -hash ref
foreach my $subKey (keys %registrySubKeyValues) {
my $_subKey = $registrySubKeyValues{$subKey};
next unless $$_subKey[0] eq $keyName;
print "Configure=" . $$_subKey[2];
}
Output
Name "main::HKEY_LOCAL_MACHINE" used only once: possible typo at ....
Configure=Yes
I could get the value of Configure but it also returns a warning which I don't know how to fix it.
Any body where am I wrong and could show me how to fix it?
Thanks.
The "used only once" is a warning that use warnings issues because you have used $main::HKEY_LOCAL_MACHINE only once. You are not at fault here. It is a mere hint that you might have forgotten something.
In this case, you can either ignore it, or simply deactivate that kind of warning: no warnings 'once'.
In general it is a good idea to enclose these things in a BLOCK and add a long, descriptive comment to it that explains why you are turning off that kind of warning here.
{ # Disable 'used only once' warning because the $::HKEY_...
# var was imported by Win32::Registry and is not used anywhere else.
$main::HKEY_LOCAL_MACHINE->Open($registryPath, $registryKeySettings)
|| die "Cannot open $registryPath: $!";
}
You can find more infos about warnings here.
This module is rather odd in that it exports symbols to the main package regardless of where it is used from.
But in your case this is what you want: your program is in main as you have no package statement, and you can omit the main:: from $HKEY_LOCAL_MACHINE.
As to your problem, the code you show doesn't raise the warning you say it does. The problem must be somewhere else. Please would you show your full code so that we can advise you better.
In the mean time please pay heed to #Sinan Ünür's advice - Win32::TieRegistry is preferable to Win32::Registry. Even the POD documentation of Win32::Registry says this:
NOTE: This module provides a very klunky interface to access the
Windows registry, and is not currently being developed actively. It
only exists for backward compatibility with old code that uses it. For
more powerful and flexible ways to access the registry, use
Win32::TieRegistry.
Update
I understand the problem having seen the update to your question and it is because you are executing the require Win32::Registry at run time. That means that $HKEY_LOCAL_MACHINE doesn't exist at compile time and so the compiler complains about it.
The fix is to declare it at compile time with
our $HKEY_LOCAL_MACHINE
at the top of the program.
By the way there is no need for the import call if all you need is this scalar.

How to use bugzilla API in existing bugzilla code?

Well, at the moment i have two goals.
User don't have Edit bug rights in bugzilla, but he/she should write/post comments on that bug. I think this could be possible by the following API, but I am not sure, since I am new in bugzilla and Perl. http://www.bugzilla.org/docs/tip/en/html/api/Bugzilla/WebService/Bug.html#add_comment
I want to import bugs by using importxml.pl, but I don't want new entries in DB. I just want to modify some fields of existing bugs of bugzilla, on the base of bug.xml file which contains bug info.
i.e. perl -T C:\bugzilla\bugzilla\importxml.pl -v C:\bugzilla\bugzilla\mybugs\bug.xml
Might be following API could be helpful, but I am not sure.
http://www.bugzilla.org/docs/tip/en/html/api/Bugzilla/WebService/Bug.html#update
So, what are possible ways to achieve these goals ??
As I am thinking, may be i should use the methods of these APIs into existing bugzilla code and my dreams are:
comments would be enabled for the user who don't have bug-edit right.
I'll run the importxml.pl script from command line by passing some parameters and I'll modify some fields of existing bugs.
But I am not sure, either I am thinking right or wrong. I also don't know how to use the method of these APIs??
The email_in.pl script can do the types of things you are asking. However, you will need to create a user that does have permissions to make the changes and you will need to transform the data into a form that email_in.pl understands.
http://www.bugzilla.org/docs/4.2/en/html/api/email_in.html
I can help with the first point:
Here's an excerpt from a a svn_bz_append.pl script (http://www.telegraphics.com.au/svn/svn_bz/trunk/) that I've modified that I use to update bugzilla comments on svn commits. Note that I have this script running on the same machine as the Bugzilla install, as it uses modules from within the Bugzilla directory. I have this working for Bugzilla v 4.2.3.
I've omitted quite a bit of this script to pull out the excerpt below:
use strict;
use warnings;
use Bugzilla;
use Bugzilla::Config;
use Bugzilla::Bug;
use Data::Dumper;
... create/fetch the userid and some bug Ids to work on ...
eg:
my $userid = 1;
my #bugs = ( 1, 2, 3 );
my $message = 'Say something here';
... now loop through the bug ids and add the comment...
foreach my $bugId (#bugs) {
my $user = new Bugzilla::User({ id => $userid})
|| ThrowUserError('invalid_username', { id => $userid}); #get the user from bugzilla
print STDERR 'user: '. Dumper($user); #pretty prints the user object
Bugzilla->set_user($user); #this authenticates the user so that you may perform actions on bugs that the user has permissions to.
my $bug = Bugzilla::Bug->check($bugId); #gets the bug
print STDERR 'bug: '. Dumper($bug); #pretty prints the bug object
$bug->add_comment($message); #adds a comment to the bug
$bug->update(); #updated the bug - don't forget to do this!
}
Please note that the Dumper functions are just using the excellent Data::Dumper module: http://perldoc.perl.org/Data/Dumper.html - you don't need them except for debugging.
The log in info came from: How can I authenticate when using the Bugzilla Perl API in a script?

Selenium WebDriver with Perl

I am trying to run the Selenium driver with Perl bindings, and due to the lack of examples and documentation, I am running into some roadblocks. I have figured out how to do some basic things, but I seem to be running into some issues with other simple things like validating the text on a page using Remote::Driver package.
If I try to do something like this:
$sel->get("https://www.yahoo.com/" );
$ret = $sel->find_element("//div[contains( text(),'Thursday, April 26, 2012')]");
I get a message back that the element couldn't be found. I am using xpath because the driver package doesn't appear to have a sub specific for finding text.. at least not that I've found.
If my xpath setup is wrong or if someone knows a better way, that would be extremely helpful. I'm having problems with some button clicking too.. but this seems like it should be easier and is bugging me.
Finding text on a web page and comparing that text to some "known good value" using Selenium::Remote::Driver can be implemented as follows:
File: SomeWebApp.pm
package SomeWebApp;
sub get_text_present {
my $self = shift;
my $target = shift;
my $locator = shift;
my $text = $self->{driver}->find_element($target, $locator)->get_text();
return $text;
}
Somewhere in your test script: test.pl
my $text = $some_web_app->get_text_present("MainContent_RequiredFieldValidator6", "id");
The above finds the element identified by $target using the locating scheme identified by $locator and stores it in the variable $text. You can then use that to compare / validate as required / needed.
https is a tad slower loading than http. Although WebDriver is pretty good about waiting until it's figured out that the requested page is fully loaded, maybe you need to give it a little help here. Add a sleep(2); after the get() call and see if it works. If it does, try cutting down to 1 second. You can also do a get_title call to see if you've loaded the page you think you have.
The other possibility is that your text target isn't quite exactly the same as what's on the page. You could try looking first for one word, such as "April", and see if you get a hit, and then expand until you find the mismatch (e.g., does this string actually have a newline or break within it? How about an HTML entity such as a non-breaking space?). Also, you are looking for that bit of text anywhere under a div (all child text supposedly is concatenated, and then the search done). That would more likely cast too wide a net than not get anything at all, but it's worth knowing.

How do I get the text-form verification code when doing auto site access in Perl?

I'm playing around with Win32::IE:Mechanize to try to access some authentication-required sites automatically. So far I've achieved moderate success, for example, I can automatically log in to my yahoo mailbox. But I find many sites are using some kind of image verification mechanism, which is possibly called CAPTCHA. I can do nothing to them. But one of the sites I'm trying to auto access is using a plain-text verification code. It is comnposed of four digits, selectable and copyable. But they're not in the source file which can be fetched using
$mech->content;
I searched for the keyword that appears on the webpage but not in the source file through all the files in the Temporary Internet Files but still can't find it.
Any idea what's going on? I was suspecting that the verification code was somehow hidden in some cookie file but I can't seem to find it :(
The following is the code that completes all the fields requirements except for the verification code:
use warnings;
use Win32::IE::Mechanize;
my $url = "http://www.zjsmap.com/smap/smap_login.jsp";
my $eccode = "myeccode";
my $username = "myaccountname";
my $password = "mypassword";
my $verify = "I can't figure out how to let the script get the code yet"
my $mech = Win32::IE::Mechanize->new(visible=>1);
$mech->get($url);
sleep(1); #avoids undefined value error
$mech->form_name("BaseForm");
$mech->field(ECCODE => $eccode);
$mech->field(MEMBERACCOUNT => $username);
$mech->field(PASSWORD => $password);
$mech->field(verify => $verify);
$mech->click();
Like always any suggestions/comments would be greatly appreciated :)
UPDATE
I've figured out a not-so-smart way to solve this problem. Please comment on my own asnwer posted below. Thanks like always :)
This is the reason why they are there. To stop program like yours to do automated stuff ;-)
A CAPTCHA or Captcha is a type of
challenge-response test used in
computing to ensure that the response
is not generated by a computer.
This appears to be an irrelevant number. The page uses it in 3 places: generating it; displaying it on the form next to the input field for it; and checking for the input value being equal to the random number chosen. That is, it is a client-only check. Still, if you disable javascript it looks like, I'm guessing, important cookies don't get set. If you can execute JavaScript in the context of the page (you should be able to with a get method call and a javascript URI), you could change the value of random_number to f.e. 42 and fill that in on the form.
The code is inserted by JavaScript – disable JS, reload the page and see it disappear. You have to hunt through the JS code to get an idea where it comes from and how to replicate it.
Thanks to james2vegas, zoul and Shoban.
I've finally figured out on my own a not-so-smart but at-least-workable way to solve the problem I described here. I'd like to share it here. I think the approach suggested by #james2vegas is probably much better...but anyway I'm learning along the way.
My approach is this:
Although the verification code is not in the source file but since it is still selectable and copyable, I can let my script copy everything in the login page and then extract the verification code.
To do this, I use the sendkeys functions in the Win32::Guitest module to do "Select All" and "Copy" to the login page.
Then I use Win32:Clipboard to get the clipboard content and then Regexp to extract the code. Something like this:
$verify = Win32::Clipboard::GetText();
$verify =~ s/.* (\d{4}).*/$1/msg;
A few thoughts:
The random number is generated by something like this in Perl
my $random_number = int(rand(8999)) + 1000; #var random_number = rand(1000,10000);
And then it checks if $verify == $random_number. I don't know how to catch the value of one-session-only $random_number. I think it is stored somewhere in the memory. If I can capture the value directly then I wouldn't have gone to so much trouble of using this and that extra module.

How can I read the URL-Data send with POST in Perl?

I'm trying to read out the POST-Data that was sent from a form in a page to my Perl Script. I googled and found out that:
read(STDIN, $param_string, $ENV{'CONTENT_LENGTH'})
reads out the whole Data-String with and writes the whole string to $param_string in the form of
Param1=Value1&Param2=Value2&Param3=Value3
by spliting it at the right places I get the necessary Data.
But I wonder why my $param_string is empty.
When I try the whole thing with GET:
$param_string = $ENV{'QUERY_STRING'};
everything works fine. Does anybody have an idea?
There absolutely no real reason for someone at your level to want to hand parse CGI requests.
Please use CGI::Simple or CGI.pm.
CGI.pm has a lot of baggage (HTML generation, function oriented interface) which makes CGI::Simple preferable.
Using any CGI processing module on CPAN is better than trying to write CGI processing code from scratch.
See parse_query_string in CGI::Simple for a way of accessing parameters passed using the query string when processing a form that is POSTed to your script.
If you want to learn how to do it right, you can read the source code of either module. Reading through the CGI.pm CHANGES file is also instructive.
If you are able to retrieve GET-data but not able to retrieve POST-data, most likely you forgot to change form method from to be post. You can check your submit method by using this condition in if statement:
if ($ENV{'REQUEST_METHOD'} eq "POST"){
read(STDIN, $param_string, $ENV{'CONTENT_LENGTH'});
}else {
$param_string = $ENV{'QUERY_STRING'};
}
Under mod_perl 2, Apache2::Request works for me.