Thursday, January 29, 2026

Streaming audio without download

 Streaming audio without download

I'm sure many of you have often wondered how companies allow you to listen to audio or watch video, but don't allow you to right click and download, or even simply specify the URL and download it that way.

I'm sure some of you naughty people out there have found ways around that and can still download streamed audio or video, which understandably happens, but at least you've been poking around to work out how to do it.

However, not all systems will allow that, unless you're able to get the stream directly.

A long time ago in a company long now closed I did something similar using VB, ASP (no not .Net it was too long ago), where I had to hide the actual document URLs from the users so that I could put security around who could view what, without knowing where it really was.  Trust me, back then with Microsoft products it was a pain, as even changing the HTTP response didn't guarantee the user was going to be able to see the document without a pop up.  But these days, it has got a lot better, and as for a long time I like my Unix and Linux systems, way more.

Having recently updated the company web site, which lost the ability to stream audio without download, due to the original company changing it's plans., decided that I'd write my own version.

The components used to implement the secure stream and prevent download are;

  • Google reCaptcha v1 - Validation
  • node.js - Back-end
  • ReactJS - Front-end
  • Express
  • JSON
The URL that we're talking about is https://www.therapypages.com/player

The page you'll notice has the Google reCaptcha logo, meaning you're letting me know you've been to the page as a human being, less the faff (technical word, in this case meaning you don't have to click on silly pictures or type in some random text).  Without a reCaptcha token the list of files will not appear, since it is checked by the back-end node.js server to ensure that the token is valid during the API call.  If valid the server returns a JSON list back to the ReactJS code to provide the pull down list.

On selecting the track to play and clicking the Play Audio another call to the back-end server API is made sending the token and the track to the server, which then buffers the track and returns as a stream of data, rather than an audio file, by changing the content header in the HTTP response and content disposition to in-line before using fs.createReadStream to stream the file.  The ReactJS front-end uses useRef to play the stream.

With the API only streaming the file content, no URL is available to access the file directly, so no straight forward URL to pop into a browser, or command line tool.  When reviewing the developer tools you will only see the call to the API.

It's not a guaranteed prevention to stop downloading, as those clever folks out there will work out how to craft the right action to get the stream from the API server, but it works in a similar way to those other companies that charge a lot of money to perform similar features to not right click on your media.

Where there is a stream, there will always be a way to download media content, as long as you know the format that is being streamed and how to decode it.

As long as you have your own web servers that allow you to write the code you can mostly protect the content from everyday use.

The code for this is not publicly available, but you can work out how to implement your own semi-secure media player using Internet searches and or Copilot.  You won't get a complete solution, so you will need to know how to put it together, as Copilot will show you old code, and you'll need to understand how to use the validation methods, such as reCaptcha through documentation.

If you're interested in having something like this developed, or interested in how it was coded send me an Email through the contact form on the web site.

Thursday, December 10, 2020

Pandas change string to new dataframe

 Today I was given a challenge where someone was extracting JSON data and wanting to write it to a database and thanks to https://www.dataquest.io/blog/sql-insert-tutorial/ this gave the relevant information to enable the JSON data to be placed into a Pandas DataFrame and then grab the column names and the data and generate the necessary SQL.

HOWEVER

The data that was given had an array of dictionaries within it causing the DataFrame to show it as a string!

So this information was dropped from the DataFrame so that the core data for that table could be stored.

A second DataFrame was then required so the the Security Group data for each instance could then be stored into the database in its own table.

For this to happen I first created a new DataFrame that would contain;

  • Instance ID
  • Security Group array of dictionaries as a string
From here it was then a case of breaking it down so that the string and the instance ID could become a new record for a new DataFrame.


data = pd.read_json('ec2_data.json')
sg=data[['instance_id','sec_groups']]
a=[]
for x in sg.values:
    for y in x[1]:
        b=dict()
         b={"instance_id": x[0]}
         b.update(y)
         a.append(b)
df2=pd.DataFrame.from_dict(a)
print(df2)

  • The idea was to create the new DataFrame called sg from the original, but only taking the 2 columns we needed.
  • An empty array was then created so that the new DataFrame (df2) could be created since each record in a DataFrame is a dictionary from an array element.
  • We then iterate over the values of the sg DataFrame and within that iterate over the security groups since x[1] contains an array of security group dictionary objects.
  • A temporary dictionary is then created (b) to store the data of instance id, security group id and security group name.
  • That dictionary is then added to the array a.
  • This continues for all the data, and if there happens to be an instance with more than 1 security group then the instance ID will appear twice in the final DataFrame, but with the different security group data for each record.

Thursday, July 27, 2017

Windows PowerShell wget equivalent

Windows lacks useful tools that Linux and Unix have, but with the introduction of PowerShell things become more useful and easier to work with.

To implement wget in PowerShell and have it download any type of file use the following;

$webConnect = new-object System.Net.WebClient

$webConnect.DownloadFile("http://your.web.location/somefile.ext",".\localfile.ext")


The above example will download the file into the current directory.  somefile.ext could be for example a zip file such as mydocs.zip, and localfile.ext would simply be mydocs.zip.

If you omit the 2nd argument then the content of the URL will be output to the screen (stdout).

Wednesday, June 3, 2015

Dynamically adding Elements to forms and then submitting

Recently I decided to write a web application using PHP, for a change, rather than Perl, and as part of my application wanted to dynamically add some fields to a form, by allowing the user to decide how many fields they wanted to add.

The fields needed to be added to a table layout which would include the detail for the user in one column and the input fields in the right, example code;
<script>
function addExtraBoxes(numBoxes) {

        var container = document.getElementById('extragrid');
        // Clear container
        while ( container.hasChildNodes() ) {
                container.removeChild(container.lastChild);
        }
        
        // Add the question boxes
        for ( x = 1; x <= numBoxes; x++ ) {
                var newdiv = document.createElement('tr');
                newdiv.innerHTML = '<td>Extra Box ' + x + ': </td><td> <input type="text" name="extra' + x + '" size="60"></td></tr>'
                container.appendChild(newdiv);
        }
}
</script>

<table>
<form name='dynamic' id='dynamic' action='somepage.php' method='post'>
<tr><td>Number extra fields:</td><td><select name='extras' onChange='addExtraBoxes(this.options[this.selectedIndex].value)'>
<option value='Choose' selected>---Choose one---</option>
<option value='1'>1</option>
<option value='2'>2</option>
<option value='3'>3</option>
<option value='4'>4</option>
<option value='5'>5</option>
</select></td></tr>
<tr><td colspan='2'>
<table id='extragrid'></table>
</td></tr>
</form>
</table>

The above code will conveniently add the new input text boxes and field info to the table based on the users selection from the select box.

A lot of web sites will show you only this piece of code, and then proceed to tell you that if the form elements are showing within the <form> elements in your developer view (e.g. firebug or Chrome's developer tools) that the fields should be submitted with the rest of your form.  This sadly is not true, since what they are doing is adding the new form elements to either a DIV, or in my case above a table.  The table or DIV itself is not associated with the form (you have to know about the DOM to understand this).

So, let me explain:

I have a <form> called dynamic.  That form at the time of the web page rendering only has a <select> element and nothing else.
If we then select one of the numbers from the select element it fires the javascript function addExtraBoxes() which will add the chosen number of text field elements to the extragrid table.  The tables are not in the same location as the form in the DOM, so we get the following;

document.dynamic.extras     This is the form and the select box

document.extragrid               This is the table element
document.extragrid.extra1
document.extragrid.extra2    These extran elements are not associated with the form, but with the table since that is how javascript added them.

So you can see that the DOM does not associate the new form elements to the form, so although you will see them showing nicely in the developer tools, when you come to submit the form the elements are not submitted and are missing from the form data.

Therefore those people saying that if they are showing up in the developer tools inside the <form> and </form> elements when viewing the source, who say that the fields should be contained in the form data, couldn't be more wrong and don't understand the JavaScript DOM.

How do you over come this, I hear you ask.  Well if you have an understanding of the engineering of things then from above you'll realise that you'll need some more Javascript that will add these disjoint elements to the form before submitting it.  Below is the piece of code that will do that;

function addExtras() {
    var str="";
    try {
        var elems = document.getElementsByTagName('input');
        for ( i = 0; i < elems.length; i++ ) {
            if ( elems.item(i).type == 'text' ) {
                document.getElementById('dynamic').appendChild(elems.item(i));
            }
        }
    } catch(e) {
        alert(e.message);
    }
    document.getElementById('dynamic').submit();
    return false
}

Our <form> element needs to have the onSubmit event added to call the function as follows;
<form name='dynamic' id='dynamic' action='somepage.php' method='post' onSubmit='return addExtras()'>

By using the onSubmit event we are able to use the JavaScript to add the form elements to the correct location in the DOM, and therefore when the submit occurs the data is correctly posted with the rest of the form.

Here is the final code in the correct order;
<script>
function addExtraBoxes(numBoxes) {

        var container = document.getElementById('extragrid');
        // Clear container
        while ( container.hasChildNodes() ) {
                container.removeChild(container.lastChild);
        }
        
        // Add the question boxes
        for ( x = 1; x <= numBoxes; x++ ) {
                var newdiv = document.createElement('tr');
                newdiv.innerHTML = '<td>Extra Box ' + x + ': </td><td> <input type="text" name="extra' + x + '" size="60"></td></tr>'
                container.appendChild(newdiv);
        }
}

function addExtras() {
    var str="";
    try {
        var elems = document.getElementsByTagName('input');
        for ( i = 0; i < elems.length; i++ ) {
            if ( elems.item(i).type == 'text' ) {
                document.getElementById('dynamic').appendChild(elems.item(i));
            }
        }
    } catch(e) {
        alert(e.message);
    }
    document.getElementById('dynamic').submit();
    return false
}
</script>

<table>
<form name='dynamic' id='dynamic' action='somepage.php' method='post' onSubmit='return addExtras()'>
<tr><td>Number extra fields:</td><td><select name='extras' onChange='addExtraBoxes(this.options[this.selectedIndex].value)'>
<option value='Choose' selected>---Choose one---</option>
<option value='1'>1</option>
<option value='2'>2</option>
<option value='3'>3</option>
<option value='4'>4</option>
<option value='5'>5</option>
</select></td></tr>
<tr><td colspan='2'>
<table id='extragrid'></table>
</td></tr>
</form>
</table>

Wednesday, October 8, 2014

Reading Massive Files In PowerShell

It's a known fact that PowerShell is rubbish at reading large files, and that's putting it politely.  Why you ask?

Get-Content command let when used on it's own appears to display the content of the file as soon as it reads the data.  If, however, you then output to a pipeline the content it will buffer first before being able to use the data.  This in turn will force your memory and swap to be consumed greatly, and hence why PowerShell is useless with large files.

So, we need to go back a step to good old VBScript where by we made use of a system object called the Scripting.FileSystemObject, which works well with large files and allows you to work through a file and process as you go rather than killing your system trying to load it into memory.

$fso=New-Object -ComObject Scripting.FileSystemObject

$file=$fso.OpenTextFile("SomeTextFile.txt",1)

while ( ! $file.AtEndOfStream ) {
    $line = $file.ReadLine()

    if ( $line -match "findsomething" ) {
        write-host $line
    }
}

$file.Close()
$file=$Null


Now you can work effectively with large files in PowerShell and not use the cumbersome Get-Content, until the developers of PowerShell understand memory management and stop killing our Windows systems.

Tuesday, September 23, 2014

MySQL Data Import

I always forget this piece, as MySQL unlike SQL Server doesn't have a convenient data import tool, but instead provides a flexible command line import feature.

To import CSV (for example) data into MySQL you need;
- A database container
- A table

Let's start with a new database;

create database myDataImportExample;

use myDataImportExample;

Now we need a table for the data;

create table myData (
  ticker varchar(14),
  tradeDate varchar(8),
  openPrice decimal(17,4),
  volume bigint
);

Then import the data that has the 4 columns of data;

load data infile '/home/user1/myData.csv'
INTO table myData
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
IGNORE 1 ROWS;

Thursday, August 21, 2014

Java worse than ever

Java, the coffee is better than the language.

A language that is meant to make writing code for multiple platforms easier, but even with Oracles implementation of Java which you would think should allow me to compile one on any platform and then take the compiled byte code and place it on another platform with technically the same jvm would work straight away. So Java folk tell me what is all the fuss about having a language that doesn't do what it says it should?

1. I have to recompile code on windows and then again on Linux if it involves more than "Hello world".
So why not just do it in c++?
Or better still Perl then true write once run anywhere language.

2. Memory leaks. So many Java programmer are under the impression this language can't have memory leaks.
Can we make a law that says those who think this should be band from writing software.
The number of times I've had a Java dev ask for jvm values to be increased makes me laugh. Sorry your code out.

3. Frameworks. A fancy word for bloatware. I have to include a massive library of crap to fill up memory that i only use two functions from.

Come on people, with all this processing power we have today our computer systems really could be thinking for themselves. They could certainly be writing better code.

If we can't have a language that can compile one and run everywhere then let's just go back to c++ and Perl which let's be honest are still the only two real languages.

Write one compile everywhere such as Java is a poor excuse for software development.

A rang from a Perl and C programmer and system admin who's seen far too much poor coding in Java and fed up with having to complete a language that should only need compiling once to run anywhere.

The end, I'm off for a cup of Java :-)

Thursday, May 2, 2013

Python DB Abstraction

Whilst teaching Python this week on the 29 Apr - 2 May 2013, I decided to show those on the course how to make a script that would work between different databases, whilst keeping the amount of code in the main program to a minimum.

The program makes use of conditional import through Python's try/except capability, and uses the alias of module import to ensure that the abstract layer for the database calls are called by the same name.

Main Program
#!/usr/bin/python

import sys

if len(sys.argv) < 1:
  sys.stderr.write("Usage error\n")
  sys.stderr.write("Usage: "+sys.argv[0]+" dbtype sqliteFile\n")

# User chooses mysql
if sys.argv[1] == 'mysql':
  try:
    import MySQLdb
    import mysqlcond as actions  # Ensure that the module namespace is actions
    pyconn = MySQLdb.connect(host="localhost",user="root",db="abc")
  except:
    print "MySQLdb does not exist"
    sys.exit(1)
else:
  try:
    import sqlite3
    import sqlitecond as actions
    pyconn = sqlite3.connect(sys.argv[2])
  except:
    sys.stderr.write("SQLite does not exist\n")
    sys.exit(1)

pycur=pyconn.cursor()
myList=[2,'Shil','Steve','abc@xyz.com','blah blah']
actions.build(pycur)
actions.insert(pycur,myList)
actions.list(pycur)
pyconn.commit()
pyconn.close()



SQLite DB code layer "sqlitecond.py"
def build(pycur):
  sqlstmnt='''
        CREATE TABLE abook (
                id int primary key,
                surname varchar(50),
                firstname varchar(50),
                email varchar(150),
                notes text
        )
'''
  pycur.execute(sqlstmnt)

def insert(pycur,values):
  sql="INSERT INTO abook VALUES(?,?,?,?,?)"
  pycur.execute(sql,values);

def list(pycur,table=None,fields=None,values=None):

  sql="SELECT * FROM ",table
  pycur.execute(sql)
  return pycur.fetchall()
 
 




MySQL DB code layer "mysqlcond.py"
def build(pycur):
  sqlstmnt='''
        CREATE TABLE abook (
                id int primary key,
                surname varchar(50),
                firstname varchar(50),
                email varchar(150),
                notes text
        ) ENGINE = INNODB;
'''
  pycur.execute(sqlstmnt)

def insert(pycur,values):
  sql="INSERT INTO abook (id,surname,firstname,email) VALUES(?,?,?,?)"
  pycur.execute(sql,values);

def list(pycur,table=None,fields=None,values=None):

  sql="SELECT * FROM ",table
  pycur.execute(sql)
  return pycur.fetchall()

Thursday, March 21, 2013

Why Python Needs Perl's use strict

Having been playing with Python again after a couple of years away from it I had a good bunch of people to teach it too, and they had some good questions.  One of which came up during exceptions.

Now we all know that Python allows you to create variables on the fly and to declare them you must assign to them first;
myvar="hello world"

But imagine the following scenario where you have declared your variable such as a file handle to open a file, but you have used an exception to capture the fact that the file does not exist and in your except section have a typo for the file handle object.



try:
        fh=open("usestrict")
        for x in fh:
                print x,"\n"
except IOError:
        print "File could not be opened"
        ofh.close()

ofh.close()



So the Python Guy had a post at the following;
http://pythonguy.wordpress.com/2008/09/18/perl-really-sucks-and-they-dont-even-realize-it/

Well, clearly from the above code I would not get a compile error and my exception would happen and even if I didn't get the exception my my code would run and when it came to closing the file I'd get a NameError exception from Python.

Are you sure Python doesn't need a use strict?  Are Python developers that confident that they don't make typos?

Thursday, September 20, 2012

Listing all hosts in Active Directory using PowerShell

PowerShell is now a mature scripting language. I've enjoyed watching it flourish from it's early conception and the many ways in which people were convinced that it was better than Perl, or the Unix KornShell.  Well for Windows that is definitely the case as it puts the operating system in the league of serious enterprise systems especially now Server Core comes with the .Net framework and PowerShell making the command line offering more attractive than it's earlier attempt.  There are some great features that PowerShell provides which make it an enterprise suitable automation language, such as the ability to interact with WMI for remote and local host manipulation and ADSI for automating your Active Directory tasks.  Why would you want to click another mouse button, apart from to launch your PowerShell script to update 1000s of hosts, or change a particular aspect of all 5 million users in your enterpirse?  Clicking is for wimps, that's those of you who still like Windows Icons Menus and Pointers :-)

One thing I found great the other day was how simple and easy it is to get a list of all the properties from your hosts registered in Active Directory in so few lines;

$DirSearcher = New-Object System.DirectoryServices.DirectorySearcher([adsi]'LDAP://CN=Computers,DC=xx,DC=xxxx')


foreach ($hostObject in $DirSearcher.FindAll())
{
        echo $hostObject.Properties;    # Will list all hosts and their AD properties
        # echo $hostObject.Properties.name; # List just the hostname, dnshostname for FQDN name
}

If you simply want to grab a particular object from the directory you only need do the following;
$AD=[adsi]’LDAP://CN=xxxx,OU=xxxx,OU=xxx,DC=xxxx,DC=xxxx’
$AD.Properties


Couldn't be simpler.  And as long as the object has methods you can perform various actions to update values and more.

Tuesday, October 4, 2011

Ajax - Reminder for me - Multiple calls

This is more a reminder for me, rather than a useful post.

The ability to call different backend programs and have live updates into divs on a page, and here is the code that does it and works on Windows, Firefox and Google Chrome.


<html>
<head>
<style>
#time { position: absolute; top: 100px; left: 10px; border-left: 2px solid grey; border-bottom: 2px solid black; width: 200px; height: 200px }
#blob { position: absolute; top: 100px; left: 300px; border-left: 2px solid gray; border-bottom: 2px solid black; width: 200px; height: 200px }
</style>
</head>


<script type="text/javascript">
function ajaxFunction(myURL,myDIV)
{
var xmlHttp;
try
{
// Firefox, Opera 8.0+, Safari, Chrome
xmlHttp=new XMLHttpRequest();
}
catch (e)
{
// Internet Explorer 2 versions, capture both
try
{
xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e)
{
try
{
xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e)
{
alert("Your browser does not support AJAX!");
return false;
}
}
}
xmlHttp.onreadystatechange=function()
{
if(xmlHttp.readyState==4)
{
document.getElementById(myDIV).innerHTML=xmlHttp.responseText;
}
}
xmlHttp.open("GET",myURL,true);
xmlHttp.send(null);
}
</script>
<body>
<form name="myForm">
<p>Magic updating data, go edit the file
<div id=time></div>
<div id=blob></div>
</form>
<script>setInterval("ajaxFunction('cgi-bin/time.pl','time')",5000);</script>
<script>setInterval("ajaxFunction('cgi-bin/stuff.pl','blob')",5000);</script>
</body>
</html>

Sunday, October 2, 2011

Perl DBI and Sybase IMAGE fields

Sybase IMAGE fields and TEXT fields can be a right pain when working with Perl and the ct_ libraries. The manual pages are a little rough and don't give full examples, often missing out essential parts. So here it is in one section.

NOTE: Your LANG variable must be unset!

I noticed whilst identifying the issue for them that Sybase will allow dumps up to a certain size, e.g. the /etc/passwd file would quite happily fit into an IMAGE field if you use the following;


use strict;
use DBI;

# Open the connection to the database
my $dbh=DBI->connect('dbi:Sybase:server=STEVE;database=test','sa','') || die "Can't connect";

sub Insert
{
# Insert data
open(FH,"/etc/passwd");
local $/; # Slurp mode to suck in the file into one scalar
my $filename=<FH>; # read in the data
$/=1; # Return to normal newline mode
close FH;
$filename=unpack("H*",$filename); # Hex convert the entire file
my $length=length($filename);
$dbh->do("INSERT INTO data VALUES(4,'$filename')"); # Note the single quotes '
print "Insert done\n";
}

sub GetData
{
# Get data
my $sth=$dbh->prepare("SELECT * from data where id=4");
$sth->execute();
open(OFH, ">mytcap"); my $line;
while ( $line = $sth->fetchrow_hashref() )
{
my $data=$line->{'file'};
$data=pack('H*',$data); # Unpack the hex data
while ( $data =~ /(.{2})/g ) # Take each 2 characters from the hex code
{
print chr(hex($1)); # Turn the hex back into text
}
}
close(OFH);
$sth->finish();
}

Insert();
GetData();
$dbh->disconnect();

However, if the data became larger, e.g. the /etc/httpd/conf/httpd.conf file then you would start to see complaints from Sybase saying that the maximum size is only 30. That is, it can't move the point to the next available page size for the IMAGE. Which lead to the need for the ct_ functions as below;

use strict;
use DBI;

my $dbh=DBI->connect('dbi:Sybase:server=STEVE;database=test','sa','') || die "Can't connect";

sub Insert
{
# Insert data
$dbh->do("INSERT INTO data VALUES(4,'0xab')"); # Put some rubbish in the IMAGE field
}

sub Update
{
my $size = -s '/etc/httpd/conf/httpd.conf'; # Open a large file
open(FH,"/etc/httpd/conf/httpd.conf");
local $/;
my $filename=<FH>;
$/=1;
close FH;
$filename=unpack("H*",$filename); # Convert it to hex

my $sth=$dbh->prepare("select file from data where id=4"); # Grab the inserted new row
$sth->execute();
while($sth->fetch) # Fetch an array reference
{
$sth->syb_ct_data_info('CS_GET',1); # Set the pointer
}
$sth->syb_ct_prepare_send();
# Tell Sybase how much data we plan to send and turn the log on
$sth->syb_ct_data_info('CS_SET',1, {total_txtlen => length($filename), log_on_update => 1});
$sth->syb_ct_send_data($filename, length($filename)); # Send the data
$sth->syb_ct_finish_send();
}

sub GetData
{
# Get data
my $data;
my $sth=$dbh->prepare("SELECT datalength(file) AS len from data where id=4");
$sth->execute();
my $length=${$sth->fetchrow_hashref()}{'len'},"\n"; # Get the length of the IMAGE data
$sth->finish();
$dbh->{LongReadLen}=$length+1; # Tell Sybase how much data we plan to fetch

$sth=$dbh->prepare("SELECT id,file from data where id=4"); # What record do we want
$sth->{syb_no_bind_blob}=1; # Tell Sybase we are fetching binary
$sth->execute();
my ($len,$d);
while ( $d = $sth->fetch ) # Get array ref of data
{
$len = $sth->syb_ct_get_data(2,\$data,0); # Fetch all the data, $len contains number of bytes
# NOTE: \$data is the reference that will capture the data
while ( $data =~ /(.{2})/g ) # Do our favourite conversion on the returned data
{
print chr(hex($1)); # Print out the converted characters
}
}
$sth->finish();
}

Insert();
Update();
GetData();
$dbh->disconnect();

Note that with these examples I use Perl's unpack function to place the data into hex form before inserting it into the database, so that no quote or special character conversions are required. On retrieving the data I make use of the chr and hex functions to convert every 2 hex values into their decimal number and then chr to get the real character.

Saturday, October 30, 2010

Perl action indicator using Term::Cap

If you are wondering how to make one of those whirling "I'm doing something" indicator on a screen in Perl, here is some code that will get you going. There are many libraries out there, but for those of you in companies where they won't let you use just any old CPAN library, here is a Termcap version which is standard with all Unix/Linux distributions of Perl.

use Term::Cap;
use POSIX;

# Load terminal IO library
my $termios = new POSIX::Termios;
# Get terminal settings
$termios->getattr;
# Get terminal speed
my $ospeed = $termios->getospeed;

$|=1;
$terminal = Tgetent Term::Cap { TERM => undef, OSPEED => $ospeed };
$terminal->Trequire(qw/ce ku kd/);

# Array for spinning thingy
my @seq=qw(| / - | \ -);
my $count=0;

# Position on the screen left to right (0 being left of screen)
my $x = 0;
# Position on the screen top to bottom (0 being top of screen)
my $y = 10;

while (1)
{
$terminal->Tputs('cl',1,*STDOUT); # Clear screen
$terminal->Tputs('cd',1,*STDOUT); # Clear data

# Set cursor position on screen
$terminal->Tgoto('cm',$x,$y,*STDOUT);
# Print one of the chars | / - \
print "$seq[$count++]";
sleep 1;
if ( $count > 5 )
{
$count = 0;
}
}

Friday, October 29, 2010

Interactive Password on Console app with C#

If you've ever used C# for application development and needed to get a password into your program but don't want to display it to the screen, you'll realise that you will need to use some COM objects and kernel functionality.
This simple example provides you with a template to get the password from a user without displaying on the screen what they typed, and also accepting the backspace key when they press it.
The code;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace FirstOne
{
class Program
{
// Get the kernel function for setting console modes
[System.Runtime.InteropServices.DllImport("kernel32 ")]
private static extern int SetConsoleMode(IntPtr hConsoleHandle, int dwMode);
// Get the kernel function for getting console modes
[System.Runtime.InteropServices.DllImport("kernel32 ")]
private static extern int GetConsoleMode(IntPtr hConsoleHandle, ref int dwMode);

// Some useful constants for the console values
private const int ENABLE_LINE_INPUT = 2;
private const int ENABLE_ECHO_INPUT = 4;
// Standard input file handle
private const int CONIN = 3;

// Ensure that our process is single threaded as we as using COM and need to ensure communication
[STAThread]
static void Main(string[] args)
{
IntPtr hStdIn = new IntPtr(CONIN);
int myMode=0;
char inputChar;
string password = "";
Console.Write("Password: ");
// Get the current console settings
GetConsoleMode(hStdIn, ref myMode);
// Turn off echo
myMode = (myMode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT));
SetConsoleMode(hStdIn, myMode);

do
{
inputChar = (char)Console.Read();
if (inputChar == '\b') // Can also use 8 instead of '\b'
{
// Delete character if user has pressed backspace
password=password.Remove(password.Length-1);
}
if (inputChar >= 32)
{
// Store password characters
password += inputChar;
}
} while (inputChar != '\r');

// Reset terminal echo
myMode = (myMode | (ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT));
SetConsoleMode(hStdIn, myMode);
Console.WriteLine("");
Console.WriteLine("Password was: {0}", password);
}
}
}

Tracing a Web Reference

  1. First you will need SvcTraceViewer.exe which should be some where similar to;
    C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\SvcTraceViewer.exe
  2. Add your Web Reference to the project and code as normal
  3. To trace the service you will need to modify your app.Config file
The essential parts required to get a trace that can be viewed with SvcTraceViewer are;
  • <diagnostics> section which should be added after the <system.servicemodel> tag and before the <bindings> tag

<diagnostics>messagelogging logentiremessage="true"
logmalformedmessages="true" logmessagesatservicelevel="true"
logmessagesattransportlevel="true" maxmessagestolog="100"
maxsizeofmessagetolog="10000000"</diagnostics>

  • After the </system.serviceModel> tag you should then add the following <system.Diagnostics> section

<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Information,ActivityTracing" propagateActivity="true">
<listeners>
<add name="xml" />
</listeners>
</source>
<source name="System.ServiceModel.MessageLogging" switchValue="All" propagateActivity="true">
<listeners>
<add name="xml" />
</listeners>
</source>
</sources>
<sharedListeners>
<add initializeData="c:\abc.svclog" type="System.Diagnostics.XmlWriterTraceListener" name="xml" />
</sharedListeners>
<trace autoflush="true" />
</system.diagnostics>

  • Run your application and then locate your c:\abc.svclog file
  • Note that you should name and locate the initializeData attribute in a sensible location and a meaning full name.

Wednesday, October 27, 2010

Dynamic Perl Subroutines

You've got a set of subroutines that take similar numbers of parameters, but need to call a different constructor from different modules which use OO Perl. Here is an example of how that can be done using dynamic Perl subroutines.


---------- mod1.pm ----------
package mod1;

sub new
{
my ($modname,$a,$b) = @_;
print "In module 1\n";
return bless {'a'=>"$a","b"=>"$b"};
}

1;

---------- mod2.pm ----------
package mod2;

sub new
{
my ($modname,$a,$b) = @_;
print "In Module 2\n";
return bless {'a'=>"$a","b"=>"$b"};
}

1;


---------- main program -----
#!/usr/bin/perl

use mod1;
use mod2;

sub declared
{
my $module = shift;
# $cmd contains the code which will be the body of our subroutine
$cmd="my (\$name, \$fullname) = \@_; $module(\$name, \$fullname);";
# perform and evaluation on $cmd so that it becomes an anonymous subroutine reference
$cmd = eval("sub { $cmd };");
# return the subroutine reference (a normal Perl thing)
return $cmd;
};

# Create a subroutine reference that calls the new method from mod1
my $campus=declared("new mod1");
# Create a subroutine reference that calls the new method from mod2
my $camp=declared("new mod2");
# Now call the 2 subroutines from the different modules
my $f=&$campus("Module 1","blah blah");
my $g=&$camp("Module 2","more blah");
# Show that we did get different results from the 2 methods
print "f: ",$f->{a}," and ",$f->{b},"\n";
print "g: ",$g->{a}," and ",$g->{b},"\n";


What fun was that. Now you are all going to want to go away and reduce your code :-)

Monday, October 25, 2010

Temporarily closing STDERR in Perl

Someone asked me how to get rid of a STDERR message being printed from a Perl module as it was being annoying to the program that they were writing. But also what a pain that the module was writing the errors!

Anyway, the simple emulation of the module was to make it print to STDERR. Here's the module code (module called p.pm);

---------------- p.pm ---------------------------
package p;

sub dothis
{
print STDERR "There's a problem";
return 2;
}

1;
---------------- p.pm ---------------------------


The program code that temporarily prevents the STDERR from being displayed is as follows;

---------------- stopstderr ---------------------------
#!/usr/bin/perl
# using perl 5.8

use p;

# Open a new file handle to remember where STDERR really points to
open (OLDER, ">&", \*STDERR) || die "Can't dup stderr";
close STDERR;
# Repoint STDERR to null
open (STDERR, ">/dev/null") || die "Can't remap STDERR";
print "No message here: ";
# No message printed from the module
my $s=p->dothis();
print "\n";
print "Return value is $s\n";
print "Trying to print to STDERR directly: ";
# No output printed to STDERR so next line goes to /dev/null
print STDERR "Can you see this?\n";
print "\n";
close STDERR;
# Repoint STDERR to where it normally goes
open (STDERR, ">&", \*OLDER) || die "Can't repoint STDERR";
close OLDER;
# Ensure that everything prints out when expected
select STDERR; $| = 1;
select STDOUT; $| = 1;
# Everything is happy again
print "Now STDERR is back, message here: ";
print STDERR "Cool :-)\n";

---------------- stopstderr ---------------------------

What fun :-)

Perl writing STDERR to a variable

Further to the problem of preventing STDERR from being displayed we wanted to capture the error message in a variable.

---------------- p.pm ---------------------------
package p;

sub dothis
{
print STDERR "There's a problem";
return 2;
}

1;
---------------- p.pm ---------------------------


The program code that temporarily prevents the STDERR from being displayed is as follows;

---------------- stopstderr ---------------------------
#!/usr/bin/perl
# using perl 5.8

use p;

# Open a new file handle to remember where STDERR really points to
open (OLDER, ">&", \*STDERR) || die "Can't dup stderr";
close STDERR;
# Repoint STDERR to a memory location so that we can capture the error message
open (STDERR, ">", \$var) || die "Can't remap STDERR";
print "No message here: ";
# No message printed from the module
my $s=p->dothis();
print "\n";
print "Return value is $s\n";
print "Trying to print to STDERR directly: ";
# No output printed to STDERR so next line goes to /dev/null
print STDERR "Can you see this?\n";
print "\n";
close STDERR;
# Let's print our the message captured in the variable $var even though we closed STDERR
print "The captured error message: $var\n";
# Repoint STDERR to where it normally goes
open (STDERR, ">&", \*OLDER) || die "Can't repoint STDERR";
close OLDER;
# Ensure that everything prints out when expected
select STDERR; $| = 1;
select STDOUT; $| = 1;
# Everything is happy again
print "Now STDERR is back, message here: ";
print STDERR "Cool :-)\n";

---------------- stopstderr ---------------------------


What fun :-)

Example of querying an object from WMI in C#

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Data;
using System.Net;
using System.Net.NetworkInformation;
// These next 2 lines can only be used if you have included a Project --> Reference to System.Management
using System.Management;
using System.Management.Instrumentation;

namespace Test1 {
class Program {
static void Main(string[] args) {
Console.Write("Please enter your name: ");
string name = Console.ReadLine();
Console.WriteLine("Hello {0}", name);
Console.ReadLine();

// Set up the connection to the host
ConnectionOptions oConn = new ConnectionOptions();
//oConn.Username = "";
//oConn.Password = "";
System.Management.ManagementScope oMs = new System.Management.ManagementScope("\\\\WIN-V31ZRUWURFW\\root\\cimv2", oConn);

// Set the query to run
System.Management.ObjectQuery oQuery = new System.Management.ObjectQuery("SELECT * FROM Win32_Desktop");

ManagementObjectSearcher oSearcher = new ManagementObjectSearcher(oMs, oQuery);

// Get results
ManagementObjectCollection oReturnCollection = oSearcher.Get();

foreach (ManagementObject oReturn in oReturnCollection)
{
if ( oReturn["Name"].ToString() == "WIN-V31ZRUWURFW\\Administrator" )
{
Console.WriteLine("Name: {0}", oReturn["Name"].ToString());
Console.WriteLine("ScreenSaver: {0}", oReturn["ScreenSaverExecutable"].ToString());
try {
Console.WriteLine("Wallpaper: {0}", oReturn["Wallpaper"].ToString());
} catch (NullReferenceException e) {
Console.WriteLine("Wallpaper: None installed");
}
}
}
Console.Read();
}
}
}