Rubycam.rb v 1.7 CGI webcam script for use with cqcam, etc

I don’t want to mess with Sourceforge, so consider this my form of
dissemination in case the server disappears some time. Please forward
mods to the email address listed under AUTHOR below. PS: New to ruby
when I wrote it - now have RSI - probably not going to make it very
slick. :wink:

···

#!/usr/bin/env ruby

########################################################################

VERSION: $Id: rubycam.rb,v 1.7 2002/03/22 20:08:52 rubycam Exp $

AUTHOR: Phil Voris

LICENSE: Ruby License - must include this header comment block

http://www.ruby-lang.org/en/LICENSE.txt

DESCRIPTION:

This CGI webcam script attempts to conserve resources by not

creating images more often than the number of seconds indicated by

the refresh setting. Maximum flexibility is given by allowing the

administrator to set the image-producing command line. The

defaults are arranged to use cqcam

(http://www.cs.duke.edu/~reynolds/cqcam/).

REQUIRES: ruby

ruby modules: net/smtp (for error reporting), ftools

rb2html.rb (for viewing source)

some image-grabber, such as cqcam

optionally, some image manipulation software

USAGE:

* Install under cgi-bin or wherever cgi executables are allowed.

* Configure the global config section below.

* Configure the default config section below.

* Optionally create one or more config files to call in the PATH_INFO.

* Ensure that img_file_web_directory exists and is writable by the

web server

* [See end of script for recommendations for config and calling from

html.]

TO DO:

It would be nice to add caching. That is, deliver a header

indicating that the page (the image) hasn’t changed until it

actually does. I attempted this, but found that

HTTP_IF_MODIFIED_SINCE didn’t appear in the environment. I then

attempted to use a session to track if the use had seen the page

with the current image - however sessions weren’t quite working for

me - perhaps someone else can resolve this issue.

########################################################################

#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

GLOBAL CONFIGURATION - EDIT HERE

These options must be set

#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

allow options from URL (true / false)

use_config_files = true

img file directory [relative to DOC_ROOT]

img_file_web_directory = ‘/img/cam’

configuration files directory

config_dir = ‘./config’

directory where rb2html and associated files may be found

(used for /view)

rb2html_directory = ‘./rb2html-1.0’

file base-name

lock_filename = ‘rubycam.lock’

maximum age to keep a lock file (seconds, must exceed refresh time)

max_lockfile_age = 500

shows a little ® which links to the source. Specify the target

frame (’_new’, ‘_self’, etc) or nil to not display it.

source_link_target = ‘_new’

#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

END GLOBAL CONFIGURATION

#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

PER-CAM CONFIGURATION - SET DEFAULTS HERE

- MAY MODIFY IN CONFIG FILES

Anything listed in this section may be set - as below - in a

separate file.

#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

default_cqcam_opts

cmd_line = ‘cqcam -r -q 25 -s 1 -j’

filename for the images

img_filename = ‘plain.jpg’

admin email address

admin_email_address = ‘webmaster@localhost’

page title

title = ‘Rubycam’

background (color)

bgcolor = ‘black’

text (color)

text_color = ‘yellow’

browser refresh length (in seconds)

refresh = 60

img_background_color (color | nil to disable globally)

img_background_color = nil

randomize transparency_background_color (true / false)

use_randomize_img_background_color = false

randomize transparency_background_color (true / false)

use_randomize_text_color = false

match text and img backgrounds - useful for randomization

(true / false)

text_color_matches_img_background_color = false

color for the source link, if it appears (color)

source_link_color = ‘darkred’

#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

END PER-CAM CONFIGURATION

#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

##########################################

PROCESS URL OPTIONS FROM PATH_INFO

##########################################

If the script is called from a URL with path info equal to ‘view’ or

‘get’ the contents of the script will be displayed. ‘get’ results

in text/plain output while view - relying on rb2html - output color-

coded html output with line numbers.

path_info = ENV[‘PATH_INFO’].untaint

if path_info == ‘/get’

Print source

puts( “Content-type: text/plain\n\n” )
IO::foreach( ENV[‘SCRIPT_FILENAME’].untaint ) { |l|
puts l
}
exit
elsif path_info == ‘/view’

Print formatted source

puts( “Content-type: text/html\n\n” )
rb2html_executable = rb2html_directory + ‘/rb2html.rb’
if File::file?( rb2html_executable )
begin
htmlpipe = IO::popen( ‘ruby ’ + rb2html_executable + ’ ’ +
ENV[‘SCRIPT_FILENAME’].untaint )
puts( htmlpipe.readlines() )
rescue SystemCallError
## Mail admin if any errors - if you don’t want mail, change
## the admin address.
require ‘net/smtp’
smtp = Net::SMTP::new( “localhost” )
smtp.start
body = "Error:\nruby " + rb2html_executable + ’ ’ +
ENV[‘SCRIPT_FILENAME’].untaint
smtp.sendmail( body, ‘rubycam_user@localhost’, admin_email_address )
smtp.finish
end
exit
else
puts( “Content-type: text/plain\n\n” )
puts( “Error: cannot execute " + rb2html_executable )
exit
end
elsif path_info != nil
if not File::file?( config_dir + path_info )
## Print error
puts( “Content-type: text/plain\n\n” )
puts( “Error: invalid config file: '” + config_dir + path_info +
”’\n" +
“Set the PATH_INFO (in the url) to a valid config file name.” )
exit
elsif path_info.index( ‘…/’ ) != nil
## Print error
puts( “Content-type: text/plain\n\n” )
puts( “Error: invalid config file: '” + config_dir + path_info +
"’\n" +
"’…/’ not permitted in config file pathname." )
exit
elsif not File::readable?( config_dir + path_info )
## Print error
puts( “Content-type: text/plain\n\n” )
puts( “Error: unreadable config file: '” + config_dir + path_info +
"’" )
exit
else
## Process config file
config_file_string = ''
File::open( config_dir + path_info ).readlines.each do |line|
config_file_string.concat( line )
end
eval config_file_string
end
end

###########################

DETERMINE FILE INFO

###########################

First, we determine the colors to be used for text (the image time)

and for the background of the image (not the page bgcolor).

color_hash = {
0 => ‘white’,
1 => ‘red’,
2 => ‘orange’,
3 => ‘yellow’,
4 => ‘green’,
5 => ‘blue’,
6 => ‘purple’,
7 => ‘lightgreen’,
8 => ‘pink’,
9 => ‘lightyellow’,
10 => ‘lightblue’,
11 => ‘lightgray’,
12 => ‘gray’
}

If img_background_color is set to nil, then no image background

color options will apply.

if img_background_color != nil and
use_randomize_img_background_color
img_background_color = color_hash[rand(13)]
end

If randomization is used for text and image, then the image

background color is used for both.

if use_randomize_text_color and
not text_color_matches_img_background_color
text_color = color_hash[rand(13)]
elsif ( img_background_color != nil ) and
text_color_matches_img_background_color
text_color = img_background_color
end

img_file_webpath = img_file_web_directory + ‘/’ + img_filename
img_file_pathname = ENV[‘DOCUMENT_ROOT’] + img_file_webpath
img_file_pathname.untaint
img_file_tmp_pathname = img_file_pathname + ‘.tmp’

Time

time_now = Time::now

Mtime

if File::exist?( img_file_pathname )
img_file_mtime = File::mtime( img_file_pathname )
img_file_mtime_int = img_file_mtime.to_i
img_file_mtime_string = img_file_mtime.to_s
img_file_age = time_now.to_i - img_file_mtime_int
end

###########################

LOCKFILE CODE

###########################

Lock file name is global - there is only one camera and it can take

only one picture at a time. The lockfile is set during this process.

lock_file_pathname = ENV[‘DOCUMENT_ROOT’] + img_file_web_directory + ‘/’ +
lock_filename
lock_file_pathname.untaint

If the lockfile somehow gets stale, it will be removed.

locked = false
if File::exist?( lock_file_pathname )
if ( File::mtime( lock_file_pathname ) < ( time_now - (
max_lockfile_age ) ) )
File::unlink( lock_file_pathname )
else
locked = true
end
end

###########################

EXECUTE

###########################

If there’s no image, or it’s an old one, and the camera is free,

then we take a new picture.

if ( ( not File::exist?( img_file_pathname ) ) or
( img_file_age >= refresh ) ) and
( not locked )

lockfile = File::new( lock_file_pathname, mode=‘w’ )

begin
## Execute
img_file = File::open( img_file_tmp_pathname, mode=‘w’).write(
IO::popen( cmd_line ).read() )
require 'ftools’
File::mv( img_file_tmp_pathname, img_file_pathname )
File::unlink( lock_file_pathname )
img_file_mtime = Time::now
img_file_mtime_string = img_file_mtime.to_s
rescue SystemCallError
## Mail admin if any errors - if you don’t want mail, change
## the admin address.
require 'net/smtp’
smtp = Net::SMTP::new( “localhost” )
smtp.start
body = “Subject: Error with rubycam\n” +
“Failed to execute:\n” + cmd_line + "\n\nSee logs for details."
smtp.sendmail( body, ‘rubycam_user@localhost’, admin_email_address )
smtp.finish
File::unlink( lock_file_pathname )
end

end

###########################

HTML

###########################

puts( “Content-type: text/html\n” +
'Last-Modified: ’ + img_file_mtime_string + “\n” +
'Expires: ’ + ( img_file_mtime + refresh ).to_s +
"\n\n" )

puts( ‘’ + title + ‘’ +
’’ )

puts( ‘’ )

puts( ‘

<td’ )

if img_background_color != nil
puts( ’ bgcolor="’ + img_background_color + ‘"’ )
end

puts( ‘>

’ )

puts( ‘

’ + img_file_mtime_string + ‘’ )

if source_link_target != nil
puts( ’ ®’ )
end

puts( ‘’ )

###########################

CALLING FROM HTML

###########################

Include the following in your page head:

Call within body of page as:

  • <a

    href=“Javascript:openwin(’/cgi-bin/webcam/rubycam.rb’);”>Webcam

  • <a

    href=“Javascript:openwin(’/cgi-bin/webcam/rubycam.rb/transgif.conf’);”>Psychedelicam

  • <a

    href=“Javascript:openwin(’/cgi-bin/webcam/rubycam.rb/greyjpeg.conf’);”>Greycam

  • Formatted

    Source

  • Source

    ###########################

    CONFIG FILE # 1

    ###########################

    greyjpeg.conf - produces a grey jpeg

    cmd_line = 'cqcam -s 1 | ppmtojpeg --progressive --greyscale

    –optimize --quality=33 --comment=“Made with Rubycam”’

    img_filename = ‘grey.jpg’

    title = ‘Greycam’

    refresh = 60

    ###########################

    CONFIG FILE # 2

    ###########################

    transgif.conf - produces a transparent gif with weird effects

    cmd_line = 'cqcam -s 1 | ppmquant 2 | ppmtogif -transparent grey

    -interlace -sort -comment=“Made with Rubycam”’

    img_filename = ‘transparent.gif’

    title = ‘Psychedelicam’

    refresh = 60

    img_background_color = ‘red’

    use_randomize_img_background_color = true

    use_randomize_text_color = true

    text_color_matches_img_background_color = true

    EOF

    #!/usr/bin/env ruby

    ########################################################################

    VERSION: $Id: rubycam.rb,v 1.7 2002/03/22 20:08:52 pvoris Exp $

    AUTHOR: Phil Voris rubycam@nekophile.com

    LICENSE: Ruby License - must include this header comment block

    http://www.ruby-lang.org/en/LICENSE.txt

    DESCRIPTION:

    This CGI webcam script attempts to conserve resources by not

    creating images more often than the number of seconds indicated by

    the refresh setting. Maximum flexibility is given by allowing the

    administrator to set the image-producing command line. The

    defaults are arranged to use cqcam

    (http://www.cs.duke.edu/~reynolds/cqcam/).

    REQUIRES: ruby

    ruby modules: net/smtp (for error reporting), ftools

    rb2html.rb (for viewing source)

    some image-grabber, such as cqcam

    optionally, some image manipulation software

    USAGE:

    * Install under cgi-bin or wherever cgi executables are allowed.

    * Configure the global config section below.

    * Configure the default config section below.

    * Optionally create one or more config files to call in the PATH_INFO.

    * Ensure that img_file_web_directory exists and is writable by the

    web server

    * [See end of script for recommendations for config and calling from

    html.]

    TO DO:

    It would be nice to add caching. That is, deliver a header

    indicating that the page (the image) hasn’t changed until it

    actually does. I attempted this, but found that

    HTTP_IF_MODIFIED_SINCE didn’t appear in the environment. I then

    attempted to use a session to track if the use had seen the page

    with the current image - however sessions weren’t quite working for

    me - perhaps someone else can resolve this issue.

    ########################################################################

    #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    GLOBAL CONFIGURATION - EDIT HERE

    These options must be set

    #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    allow options from URL (true / false)

    use_config_files = true

    img file directory [relative to DOC_ROOT]

    img_file_web_directory = ‘/img/cam’

    configuration files directory

    config_dir = ‘./config’

    directory where rb2html and associated files may be found

    (used for /view)

    rb2html_directory = ‘./rb2html-1.0’

    file base-name

    lock_filename = ‘rubycam.lock’

    maximum age to keep a lock file (seconds, must exceed refresh time)

    max_lockfile_age = 500

    shows a little ® which links to the source. Specify the target

    frame (’_new’, ‘_self’, etc) or nil to not display it.

    source_link_target = ‘_new’

    #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    END GLOBAL CONFIGURATION

    #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    PER-CAM CONFIGURATION - SET DEFAULTS HERE

    - MAY MODIFY IN CONFIG FILES

    Anything listed in this section may be set - as below - in a

    separate file.

    #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    default_cqcam_opts

    cmd_line = ‘cqcam -r -q 25 -s 1 -j’

    filename for the images

    img_filename = ‘plain.jpg’

    admin email address

    admin_email_address = ‘webmaster@localhost’

    page title

    title = ‘Rubycam’

    background (color)

    bgcolor = ‘black’

    text (color)

    text_color = ‘yellow’

    browser refresh length (in seconds)

    refresh = 60

    img_background_color (color | nil to disable globally)

    img_background_color = nil

    randomize transparency_background_color (true / false)

    use_randomize_img_background_color = false

    randomize transparency_background_color (true / false)

    use_randomize_text_color = false

    match text and img backgrounds - useful for randomization

    (true / false)

    text_color_matches_img_background_color = false

    color for the source link, if it appears (color)

    source_link_color = ‘darkred’

    #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    END PER-CAM CONFIGURATION

    #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    ##########################################

    PROCESS URL OPTIONS FROM PATH_INFO

    ##########################################

    If the script is called from a URL with path info equal to ‘view’ or

    ‘get’ the contents of the script will be displayed. ‘get’ results

    in text/plain output while view - relying on rb2html - output color-

    coded html output with line numbers.

    path_info = ENV[‘PATH_INFO’].untaint

    if path_info == ‘/get’

    Print source

    puts( “Content-type: text/plain\n\n” )
    IO::foreach( ENV[‘SCRIPT_FILENAME’].untaint ) { |l|
    puts l
    }
    exit
    elsif path_info == ‘/view’

    Print formatted source

    puts( “Content-type: text/html\n\n” )
    rb2html_executable = rb2html_directory + ‘/rb2html.rb’
    if File::file?( rb2html_executable )
    begin
    htmlpipe = IO::popen( ‘ruby ’ + rb2html_executable + ’ ’ +
    ENV[‘SCRIPT_FILENAME’].untaint )
    puts( htmlpipe.readlines() )
    rescue SystemCallError
    ## Mail admin if any errors - if you don’t want mail, change
    ## the admin address.
    require ‘net/smtp’
    smtp = Net::SMTP::new( “localhost” )
    smtp.start
    body = "Error:\nruby " + rb2html_executable + ’ ’ +
    ENV[‘SCRIPT_FILENAME’].untaint
    smtp.sendmail( body, ‘rubycam_user@localhost’, admin_email_address )
    smtp.finish
    end
    exit
    else
    puts( “Content-type: text/plain\n\n” )
    puts( “Error: cannot execute " + rb2html_executable )
    exit
    end
    elsif path_info != nil
    if not File::file?( config_dir + path_info )
    ## Print error
    puts( “Content-type: text/plain\n\n” )
    puts( “Error: invalid config file: '” + config_dir + path_info +
    ”’\n" +
    “Set the PATH_INFO (in the url) to a valid config file name.” )
    exit
    elsif path_info.index( ‘…/’ ) != nil
    ## Print error
    puts( “Content-type: text/plain\n\n” )
    puts( “Error: invalid config file: '” + config_dir + path_info +
    "’\n" +
    "’…/’ not permitted in config file pathname." )
    exit
    elsif not File::readable?( config_dir + path_info )
    ## Print error
    puts( “Content-type: text/plain\n\n” )
    puts( “Error: unreadable config file: '” + config_dir + path_info +
    "’" )
    exit
    else
    ## Process config file
    config_file_string = ''
    File::open( config_dir + path_info ).readlines.each do |line|
    config_file_string.concat( line )
    end
    eval config_file_string
    end
    end

    ###########################

    DETERMINE FILE INFO

    ###########################

    First, we determine the colors to be used for text (the image time)

    and for the background of the image (not the page bgcolor).

    color_hash = {
    0 => ‘white’,
    1 => ‘red’,
    2 => ‘orange’,
    3 => ‘yellow’,
    4 => ‘green’,
    5 => ‘blue’,
    6 => ‘purple’,
    7 => ‘lightgreen’,
    8 => ‘pink’,
    9 => ‘lightyellow’,
    10 => ‘lightblue’,
    11 => ‘lightgray’,
    12 => ‘gray’
    }

    If img_background_color is set to nil, then no image background

    color options will apply.

    if img_background_color != nil and
    use_randomize_img_background_color
    img_background_color = color_hash[rand(13)]
    end

    If randomization is used for text and image, then the image

    background color is used for both.

    if use_randomize_text_color and
    not text_color_matches_img_background_color
    text_color = color_hash[rand(13)]
    elsif ( img_background_color != nil ) and
    text_color_matches_img_background_color
    text_color = img_background_color
    end

    img_file_webpath = img_file_web_directory + ‘/’ + img_filename
    img_file_pathname = ENV[‘DOCUMENT_ROOT’] + img_file_webpath
    img_file_pathname.untaint
    img_file_tmp_pathname = img_file_pathname + ‘.tmp’

    Time

    time_now = Time::now

    Mtime

    if File::exist?( img_file_pathname )
    img_file_mtime = File::mtime( img_file_pathname )
    img_file_mtime_int = img_file_mtime.to_i
    img_file_mtime_string = img_file_mtime.to_s
    img_file_age = time_now.to_i - img_file_mtime_int
    end

    ###########################

    LOCKFILE CODE

    ###########################

    Lock file name is global - there is only one camera and it can take

    only one picture at a time. The lockfile is set during this process.

    lock_file_pathname = ENV[‘DOCUMENT_ROOT’] + img_file_web_directory + ‘/’ +
    lock_filename
    lock_file_pathname.untaint

    If the lockfile somehow gets stale, it will be removed.

    locked = false
    if File::exist?( lock_file_pathname )
    if ( File::mtime( lock_file_pathname ) < ( time_now - (
    max_lockfile_age ) ) )
    File::unlink( lock_file_pathname )
    else
    locked = true
    end
    end

    ###########################

    EXECUTE

    ###########################

    If there’s no image, or it’s an old one, and the camera is free,

    then we take a new picture.

    if ( ( not File::exist?( img_file_pathname ) ) or
    ( img_file_age >= refresh ) ) and
    ( not locked )

    lockfile = File::new( lock_file_pathname, mode=‘w’ )

    begin
    ## Execute
    img_file = File::open( img_file_tmp_pathname, mode=‘w’).write(
    IO::popen( cmd_line ).read() )
    require 'ftools’
    File::mv( img_file_tmp_pathname, img_file_pathname )
    File::unlink( lock_file_pathname )
    img_file_mtime = Time::now
    img_file_mtime_string = img_file_mtime.to_s
    rescue SystemCallError
    ## Mail admin if any errors - if you don’t want mail, change
    ## the admin address.
    require 'net/smtp’
    smtp = Net::SMTP::new( “localhost” )
    smtp.start
    body = “Subject: Error with rubycam\n” +
    “Failed to execute:\n” + cmd_line + "\n\nSee logs for details."
    smtp.sendmail( body, ‘rubycam_user@localhost’, admin_email_address )
    smtp.finish
    File::unlink( lock_file_pathname )
    end

    end

    ###########################

    HTML

    ###########################

    puts( “Content-type: text/html\n” +
    'Last-Modified: ’ + img_file_mtime_string + “\n” +
    'Expires: ’ + ( img_file_mtime + refresh ).to_s +
    "\n\n" )

    puts( ‘’ + title + ‘’ +
    ’’ )

    puts( ‘’ )

    puts( ‘

    <td’ )

    if img_background_color != nil
    puts( ’ bgcolor="’ + img_background_color + ‘"’ )
    end

    puts( ‘>

    ’ )

    puts( ‘

    ’ + img_file_mtime_string + ‘’ )

    if source_link_target != nil
    puts( ’ ®’ )
    end

    puts( ‘’ )

    ###########################

    CALLING FROM HTML

    ###########################

    Include the following in your page head:

    Call within body of page as:

    • <a

      href=“Javascript:openwin(’/cgi-bin/webcam/rubycam.rb’);”>Webcam

    • <a

      href=“Javascript:openwin(’/cgi-bin/webcam/rubycam.rb/transgif.conf’);”>Psychedelicam

    • <a

      href=“Javascript:openwin(’/cgi-bin/webcam/rubycam.rb/greyjpeg.conf’);”>Greycam

    • Formatted

      Source

    • Source

      ###########################

      CONFIG FILE # 1

      ###########################

      greyjpeg.conf - produces a grey jpeg

      cmd_line = 'cqcam -s 1 | ppmtojpeg --progressive --greyscale

      –optimize --quality=33 --comment=“Made with Rubycam”’

      img_filename = ‘grey.jpg’

      title = ‘Greycam’

      refresh = 60

      ###########################

      CONFIG FILE # 2

      ###########################

      transgif.conf - produces a transparent gif with weird effects

      cmd_line = 'cqcam -s 1 | ppmquant 2 | ppmtogif -transparent grey

      -interlace -sort -comment=“Made with Rubycam”’

      img_filename = ‘transparent.gif’

      title = ‘Psychedelicam’

      refresh = 60

      img_background_color = ‘red’

      use_randomize_img_background_color = true

      use_randomize_text_color = true

      text_color_matches_img_background_color = true

      EOF

      #!/usr/bin/env ruby

      ########################################################################

      VERSION: $Id: rubycam.rb,v 1.7 2002/03/22 20:08:52 pvoris Exp $

      AUTHOR: Phil Voris rubycam@nekophile.com

      LICENSE: Ruby License - must include this header comment block

      http://www.ruby-lang.org/en/LICENSE.txt

      DESCRIPTION:

      This CGI webcam script attempts to conserve resources by not

      creating images more often than the number of seconds indicated by

      the refresh setting. Maximum flexibility is given by allowing the

      administrator to set the image-producing command line. The

      defaults are arranged to use cqcam

      (http://www.cs.duke.edu/~reynolds/cqcam/).

      REQUIRES: ruby

      ruby modules: net/smtp (for error reporting), ftools

      rb2html.rb (for viewing source)

      some image-grabber, such as cqcam

      optionally, some image manipulation software

      USAGE:

      * Install under cgi-bin or wherever cgi executables are allowed.

      * Configure the global config section below.

      * Configure the default config section below.

      * Optionally create one or more config files to call in the PATH_INFO.

      * Ensure that img_file_web_directory exists and is writable by the

      web server

      * [See end of script for recommendations for config and calling from

      html.]

      TO DO:

      It would be nice to add caching. That is, deliver a header

      indicating that the page (the image) hasn’t changed until it

      actually does. I attempted this, but found that

      HTTP_IF_MODIFIED_SINCE didn’t appear in the environment. I then

      attempted to use a session to track if the use had seen the page

      with the current image - however sessions weren’t quite working for

      me - perhaps someone else can resolve this issue.

      ########################################################################

      #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

      GLOBAL CONFIGURATION - EDIT HERE

      These options must be set

      #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

      allow options from URL (true / false)

      use_config_files = true

      img file directory [relative to DOC_ROOT]

      img_file_web_directory = ‘/img/cam’

      configuration files directory

      config_dir = ‘./config’

      directory where rb2html and associated files may be found

      (used for /view)

      rb2html_directory = ‘./rb2html-1.0’

      file base-name

      lock_filename = ‘rubycam.lock’

      maximum age to keep a lock file (seconds, must exceed refresh time)

      max_lockfile_age = 500

      shows a little ® which links to the source. Specify the target

      frame (’_new’, ‘_self’, etc) or nil to not display it.

      source_link_target = ‘_new’

      #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

      END GLOBAL CONFIGURATION

      #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

      #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

      PER-CAM CONFIGURATION - SET DEFAULTS HERE

      - MAY MODIFY IN CONFIG FILES

      Anything listed in this section may be set - as below - in a

      separate file.

      #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

      default_cqcam_opts

      cmd_line = ‘cqcam -r -q 25 -s 1 -j’

      filename for the images

      img_filename = ‘plain.jpg’

      admin email address

      admin_email_address = ‘webmaster@localhost’

      page title

      title = ‘Rubycam’

      background (color)

      bgcolor = ‘black’

      text (color)

      text_color = ‘yellow’

      browser refresh length (in seconds)

      refresh = 60

      img_background_color (color | nil to disable globally)

      img_background_color = nil

      randomize transparency_background_color (true / false)

      use_randomize_img_background_color = false

      randomize transparency_background_color (true / false)

      use_randomize_text_color = false

      match text and img backgrounds - useful for randomization

      (true / false)

      text_color_matches_img_background_color = false

      color for the source link, if it appears (color)

      source_link_color = ‘darkred’

      #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

      END PER-CAM CONFIGURATION

      #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

      ##########################################

      PROCESS URL OPTIONS FROM PATH_INFO

      ##########################################

      If the script is called from a URL with path info equal to ‘view’ or

      ‘get’ the contents of the script will be displayed. ‘get’ results

      in text/plain output while view - relying on rb2html - output color-

      coded html output with line numbers.

      path_info = ENV[‘PATH_INFO’].untaint

      if path_info == ‘/get’

      Print source

      puts( “Content-type: text/plain\n\n” )
      IO::foreach( ENV[‘SCRIPT_FILENAME’].untaint ) { |l|
      puts l
      }
      exit
      elsif path_info == ‘/view’

      Print formatted source

      puts( “Content-type: text/html\n\n” )
      rb2html_executable = rb2html_directory + ‘/rb2html.rb’
      if File::file?( rb2html_executable )
      begin
      htmlpipe = IO::popen( ‘ruby ’ + rb2html_executable + ’ ’ +
      ENV[‘SCRIPT_FILENAME’].untaint )
      puts( htmlpipe.readlines() )
      rescue SystemCallError
      ## Mail admin if any errors - if you don’t want mail, change
      ## the admin address.
      require ‘net/smtp’
      smtp = Net::SMTP::new( “localhost” )
      smtp.start
      body = "Error:\nruby " + rb2html_executable + ’ ’ +
      ENV[‘SCRIPT_FILENAME’].untaint
      smtp.sendmail( body, ‘rubycam_user@localhost’, admin_email_address )
      smtp.finish
      end
      exit
      else
      puts( “Content-type: text/plain\n\n” )
      puts( “Error: cannot execute " + rb2html_executable )
      exit
      end
      elsif path_info != nil
      if not File::file?( config_dir + path_info )
      ## Print error
      puts( “Content-type: text/plain\n\n” )
      puts( “Error: invalid config file: '” + config_dir + path_info +
      ”’\n" +
      “Set the PATH_INFO (in the url) to a valid config file name.” )
      exit
      elsif path_info.index( ‘…/’ ) != nil
      ## Print error
      puts( “Content-type: text/plain\n\n” )
      puts( “Error: invalid config file: '” + config_dir + path_info +
      "’\n" +
      "’…/’ not permitted in config file pathname." )
      exit
      elsif not File::readable?( config_dir + path_info )
      ## Print error
      puts( “Content-type: text/plain\n\n” )
      puts( “Error: unreadable config file: '” + config_dir + path_info +
      "’" )
      exit
      else
      ## Process config file
      config_file_string = ''
      File::open( config_dir + path_info ).readlines.each do |line|
      config_file_string.concat( line )
      end
      eval config_file_string
      end
      end

      ###########################

      DETERMINE FILE INFO

      ###########################

      First, we determine the colors to be used for text (the image time)

      and for the background of the image (not the page bgcolor).

      color_hash = {
      0 => ‘white’,
      1 => ‘red’,
      2 => ‘orange’,
      3 => ‘yellow’,
      4 => ‘green’,
      5 => ‘blue’,
      6 => ‘purple’,
      7 => ‘lightgreen’,
      8 => ‘pink’,
      9 => ‘lightyellow’,
      10 => ‘lightblue’,
      11 => ‘lightgray’,
      12 => ‘gray’
      }

      If img_background_color is set to nil, then no image background

      color options will apply.

      if img_background_color != nil and
      use_randomize_img_background_color
      img_background_color = color_hash[rand(13)]
      end

      If randomization is used for text and image, then the image

      background color is used for both.

      if use_randomize_text_color and
      not text_color_matches_img_background_color
      text_color = color_hash[rand(13)]
      elsif ( img_background_color != nil ) and
      text_color_matches_img_background_color
      text_color = img_background_color
      end

      img_file_webpath = img_file_web_directory + ‘/’ + img_filename
      img_file_pathname = ENV[‘DOCUMENT_ROOT’] + img_file_webpath
      img_file_pathname.untaint
      img_file_tmp_pathname = img_file_pathname + ‘.tmp’

      Time

      time_now = Time::now

      Mtime

      if File::exist?( img_file_pathname )
      img_file_mtime = File::mtime( img_file_pathname )
      img_file_mtime_int = img_file_mtime.to_i
      img_file_mtime_string = img_file_mtime.to_s
      img_file_age = time_now.to_i - img_file_mtime_int
      end

      ###########################

      LOCKFILE CODE

      ###########################

      Lock file name is global - there is only one camera and it can take

      only one picture at a time. The lockfile is set during this process.

      lock_file_pathname = ENV[‘DOCUMENT_ROOT’] + img_file_web_directory + ‘/’ +
      lock_filename
      lock_file_pathname.untaint

      If the lockfile somehow gets stale, it will be removed.

      locked = false
      if File::exist?( lock_file_pathname )
      if ( File::mtime( lock_file_pathname ) < ( time_now - (
      max_lockfile_age ) ) )
      File::unlink( lock_file_pathname )
      else
      locked = true
      end
      end

      ###########################

      EXECUTE

      ###########################

      If there’s no image, or it’s an old one, and the camera is free,

      then we take a new picture.

      if ( ( not File::exist?( img_file_pathname ) ) or
      ( img_file_age >= refresh ) ) and
      ( not locked )

      lockfile = File::new( lock_file_pathname, mode=‘w’ )

      begin
      ## Execute
      img_file = File::open( img_file_tmp_pathname, mode=‘w’).write(
      IO::popen( cmd_line ).read() )
      require 'ftools’
      File::mv( img_file_tmp_pathname, img_file_pathname )
      File::unlink( lock_file_pathname )
      img_file_mtime = Time::now
      img_file_mtime_string = img_file_mtime.to_s
      rescue SystemCallError
      ## Mail admin if any errors - if you don’t want mail, change
      ## the admin address.
      require 'net/smtp’
      smtp = Net::SMTP::new( “localhost” )
      smtp.start
      body = “Subject: Error with rubycam\n” +
      “Failed to execute:\n” + cmd_line + "\n\nSee logs for details."
      smtp.sendmail( body, ‘rubycam_user@localhost’, admin_email_address )
      smtp.finish
      File::unlink( lock_file_pathname )
      end

      end

      ###########################

      HTML

      ###########################

      puts( “Content-type: text/html\n” +
      'Last-Modified: ’ + img_file_mtime_string + “\n” +
      'Expires: ’ + ( img_file_mtime + refresh ).to_s +
      "\n\n" )

      puts( ‘’ + title + ‘’ +
      ’’ )

      puts( ‘’ )

      puts( ‘

      <td’ )

      if img_background_color != nil
      puts( ’ bgcolor="’ + img_background_color + ‘"’ )
      end

      puts( ‘>

      ’ )

      puts( ‘

      ’ + img_file_mtime_string + ‘’ )

      if source_link_target != nil
      puts( ’ ®’ )
      end

      puts( ‘’ )

      ###########################

      CALLING FROM HTML

      ###########################

      Include the following in your page head:

      Call within body of page as:

      • <a

        href=“Javascript:openwin(’/cgi-bin/webcam/rubycam.rb’);”>Webcam

      • <a

        href=“Javascript:openwin(’/cgi-bin/webcam/rubycam.rb/transgif.conf’);”>Psychedelicam

      • <a

        href=“Javascript:openwin(’/cgi-bin/webcam/rubycam.rb/greyjpeg.conf’);”>Greycam

      • Formatted

        Source

      • Source

        ###########################

        CONFIG FILE # 1

        ###########################

        greyjpeg.conf - produces a grey jpeg

        cmd_line = 'cqcam -s 1 | ppmtojpeg --progressive --greyscale

        –optimize --quality=33 --comment=“Made with Rubycam”’

        img_filename = ‘grey.jpg’

        title = ‘Greycam’

        refresh = 60

        ###########################

        CONFIG FILE # 2

        ###########################

        transgif.conf - produces a transparent gif with weird effects

        cmd_line = 'cqcam -s 1 | ppmquant 2 | ppmtogif -transparent grey

        -interlace -sort -comment=“Made with Rubycam”’

        img_filename = ‘transparent.gif’

        title = ‘Psychedelicam’

        refresh = 60

        img_background_color = ‘red’

        use_randomize_img_background_color = true

        use_randomize_text_color = true

        text_color_matches_img_background_color = true

        EOF

      • Want to clarify that some redundancy existed in that post - the relevant
        portion follows.

        ···

        On Wed, 19 Jun 2002 16:54:21 -0700, Phil wrote:

        I don’t want to mess with Sourceforge, so consider this my form of
        dissemination in case the server disappears some time. Please forward
        mods to the email address listed under AUTHOR below. PS: New to ruby
        when I wrote it - now have RSI - probably not going to make it very
        slick. :wink:


        #!/usr/bin/env ruby

        ########################################################################

        VERSION: $Id: rubycam.rb,v 1.7 2002/03/22 20:08:52 rubycam Exp $

        AUTHOR: Phil Voris ## ## LICENSE: Ruby

        License - must include this header comment block ##
        http://www.ruby-lang.org/en/LICENSE.txt ##

        DESCRIPTION:

        This CGI webcam script attempts to conserve resources by not

        creating images more often than the number of seconds indicated by ##
        the refresh setting. Maximum flexibility is given by allowing the ##
        administrator to set the image-producing command line. The ## defaults
        are arranged to use cqcam ## (http://www.cs.duke.edu/~reynolds/cqcam/).

        REQUIRES: ruby

        ruby modules: net/smtp (for error reporting), ftools

          rb2html.rb (for viewing source) ##           some image-grabber,
        

        such as cqcam ## optionally, some image manipulation software

        USAGE:

        * Install under cgi-bin or wherever cgi executables are allowed. ## *

        Configure the global config section below. ## * Configure the default
        config section below. ## * Optionally create one or more config files to
        call in the PATH_INFO. ## * Ensure that img_file_web_directory exists
        and is writable by the ## web server ## * [See end of script for
        recommendations for config and calling from ## html.]

        TO DO:

        It would be nice to add caching. That is, deliver a header

        indicating that the page (the image) hasn’t changed until it ## actually
        does. I attempted this, but found that ## HTTP_IF_MODIFIED_SINCE didn’t
        appear in the environment. I then ## attempted to use a session to
        track if the use had seen the page ## with the current image - however
        sessions weren’t quite working for ## me - perhaps someone else can
        resolve this issue.
        ########################################################################

        #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> # GLOBAL
        CONFIGURATION - EDIT HERE

        These options must be set

        #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

        allow options from URL (true / false) use_config_files = true

        img file directory [relative to DOC_ROOT] img_file_web_directory =

        ‘/img/cam’

        configuration files directory

        config_dir = ‘./config’

        directory where rb2html and associated files may be found ## (used

        for /view)
        rb2html_directory = ‘./rb2html-1.0’

        file base-name

        lock_filename = ‘rubycam.lock’

        maximum age to keep a lock file (seconds, must exceed refresh time)

        max_lockfile_age = 500

        shows a little (R) which links to the source. Specify the target

        frame (‘_new’, ‘_self’, etc) or nil to not display it.
        source_link_target = ‘_new’

        #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> # END
        GLOBAL CONFIGURATION
        #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

        #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> #
        PER-CAM CONFIGURATION - SET DEFAULTS HERE # - MAY
        MODIFY IN CONFIG FILES #

        Anything listed in this section may be set - as below - in a

        separate file.
        #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

        default_cqcam_opts

        cmd_line = ‘cqcam -r -q 25 -s 1 -j’

        filename for the images

        img_filename = ‘plain.jpg’

        admin email address

        admin_email_address = ‘webmaster@localhost’

        page title

        title = ‘Rubycam’

        background (color)

        bgcolor = ‘black’

        text (color)

        text_color = ‘yellow’

        browser refresh length (in seconds) refresh = 60

        img_background_color (color | nil to disable globally)

        img_background_color = nil

        randomize transparency_background_color (true / false)

        use_randomize_img_background_color = false

        randomize transparency_background_color (true / false)

        use_randomize_text_color = false

        match text and img backgrounds - useful for randomization ## (true /

        false)
        text_color_matches_img_background_color = false

        color for the source link, if it appears (color) source_link_color =

        ‘darkred’

        #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> # END
        PER-CAM CONFIGURATION
        #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

        ########################################## ### PROCESS URL OPTIONS FROM
        PATH_INFO ### ########################################## ## If the
        script is called from a URL with path info equal to ‘view’ or ## ‘get’
        the contents of the script will be displayed. ‘get’ results ## in
        text/plain output while view - relying on rb2html - output color- ##
        coded html output with line numbers. path_info =
        ENV[‘PATH_INFO’].untaint

        if path_info == ‘/get’

        Print source

        puts( “Content-type: text/plain\n\n” ) IO::foreach(
        ENV[‘SCRIPT_FILENAME’].untaint ) { |l|
        puts l
        }
        exit
        elsif path_info == ‘/view’

        Print formatted source

        puts( “Content-type: text/html\n\n” ) rb2html_executable =
        rb2html_directory + ‘/rb2html.rb’ if File::file?( rb2html_executable
        )
        begin
        htmlpipe = IO::popen( ‘ruby ’ + rb2html_executable + ’ ’ +
        ENV[‘SCRIPT_FILENAME’].untaint )
        puts( htmlpipe.readlines() )
        rescue SystemCallError
        ## Mail admin if any errors - if you don’t want mail, change ##
        the admin address.
        require ‘net/smtp’
        smtp = Net::SMTP::new( “localhost” )
        smtp.start
        body = "Error:\nruby " + rb2html_executable + ’ ’ +
        ENV[‘SCRIPT_FILENAME’].untaint
        smtp.sendmail( body, ‘rubycam_user@localhost’,
        admin_email_address ) smtp.finish
        end
        exit
        else
        puts( “Content-type: text/plain\n\n” ) puts( "Error: cannot execute
        " + rb2html_executable ) exit
        end
        elsif path_info != nil
        if not File::file?( config_dir + path_info )
        ## Print error
        puts( “Content-type: text/plain\n\n” ) puts( “Error: invalid config
        file: '” + config_dir + path_info +
        "’\n" +
        “Set the PATH_INFO (in the url) to a valid config file name.” )
        exit
        elsif path_info.index( ‘…/’ ) != nil
        ## Print error
        puts( “Content-type: text/plain\n\n” ) puts( “Error: invalid config
        file: '” + config_dir + path_info +
        “'\n” +
        “‘…/’ not permitted in config file pathname.” )
        exit
        elsif not File::readable?( config_dir + path_info )
        ## Print error
        puts( “Content-type: text/plain\n\n” ) puts( “Error: unreadable
        config file: '” + config_dir + path_info +
        “'” )
        exit
        else
        ## Process config file
        config_file_string = ‘’
        File::open( config_dir + path_info ).readlines.each do |line|
        config_file_string.concat( line )
        end
        eval config_file_string
        end
        end

        ###########################

        DETERMINE FILE INFO

        ###########################

        First, we determine the colors to be used for text (the image time)

        and for the background of the image (not the page bgcolor).

        color_hash = {
        0 => ‘white’,
        1 => ‘red’,
        2 => ‘orange’,
        3 => ‘yellow’,
        4 => ‘green’,
        5 => ‘blue’,
        6 => ‘purple’,
        7 => ‘lightgreen’,
        8 => ‘pink’,
        9 => ‘lightyellow’,
        10 => ‘lightblue’,
        11 => ‘lightgray’,
        12 => ‘gray’
        }
        }

        If img_background_color is set to nil, then no image background

        color options will apply.
        if img_background_color != nil and
        use_randomize_img_background_color
        img_background_color = color_hash[rand(13)]
        end

        If randomization is used for text and image, then the image

        background color is used for both. if use_randomize_text_color and
        not text_color_matches_img_background_color
        text_color = color_hash[rand(13)]
        elsif ( img_background_color != nil ) and
        text_color_matches_img_background_color
        text_color = img_background_color
        end

        img_file_webpath = img_file_web_directory + ‘/’ + img_filename
        img_file_pathname = ENV[‘DOCUMENT_ROOT’] + img_file_webpath
        img_file_pathname.untaint
        img_file_tmp_pathname = img_file_pathname + ‘.tmp’

        Time

        time_now = Time::now

        Mtime

        if File::exist?( img_file_pathname )
        img_file_mtime = File::mtime( img_file_pathname ) img_file_mtime_int
        = img_file_mtime.to_i img_file_mtime_string = img_file_mtime.to_s
        img_file_age = time_now.to_i - img_file_mtime_int
        end

        ###########################

        LOCKFILE CODE

        ###########################

        Lock file name is global - there is only one camera and it can take

        only one picture at a time. The lockfile is set during this process.

        lock_file_pathname = ENV[‘DOCUMENT_ROOT’] + img_file_web_directory + ‘/’
        +
        lock_filename
        lock_file_pathname.untaint

        If the lockfile somehow gets stale, it will be removed. locked =

        false
        if File::exist?( lock_file_pathname )
        if ( File::mtime( lock_file_pathname ) < ( time_now - (
        max_lockfile_age ) ) )
        File::unlink( lock_file_pathname )
        else
        locked = true
        end
        end

        ###########################

        EXECUTE

        ###########################

        If there’s no image, or it’s an old one, and the camera is free,

        then we take a new picture.
        if ( ( not File::exist?( img_file_pathname ) ) or
        ( img_file_age >= refresh ) ) and
        ( not locked )

        lockfile = File::new( lock_file_pathname, mode=‘w’ )

        begin
        ## Execute
        img_file = File::open( img_file_tmp_pathname, mode=‘w’).write(
        IO::popen( cmd_line ).read() )
        require ‘ftools’
        File::mv( img_file_tmp_pathname, img_file_pathname ) File::unlink(
        lock_file_pathname )
        img_file_mtime = Time::now
        img_file_mtime_string = img_file_mtime.to_s
        rescue SystemCallError
        ## Mail admin if any errors - if you don’t want mail, change ## the
        admin address.
        require ‘net/smtp’
        smtp = Net::SMTP::new( “localhost” )
        smtp.start
        body = “Subject: Error with rubycam\n” +
        “Failed to execute:\n” + cmd_line + “\n\nSee logs for details.”
        smtp.sendmail( body, ‘rubycam_user@localhost’, admin_email_address
        ) smtp.finish
        File::unlink( lock_file_pathname )
        end

        end

        ###########################

        HTML

        ###########################

        puts( “Content-type: text/html\n” +
        'Last-Modified: ’ + img_file_mtime_string + “\n” + 'Expires: ’ + (
        img_file_mtime + refresh ).to_s + “\n\n” )

        puts( ‘’ + title + ‘’ +
        ‘’ )

        puts( ‘’ )

        puts( ‘

        <td’ )

        if img_background_color != nil
        puts( ’ bgcolor=“’ + img_background_color + '”’ )
        end

        puts( ‘>

        ’ )

        puts( ‘

        ’ + img_file_mtime_string + ‘’ )

        if source_link_target != nil
        puts( ’ ®’ )
        end

        puts( ‘’ )

        ###########################

        CALLING FROM HTML

        ###########################

        Include the following in your page head: ## ## <script

        language=javascript>

        function openwin(url){

        var hWnd =

        window.open(url,“”,“width=350,height=300,resizable=yes,scrollbars=yes”);

        if (!hWnd.opener) hWnd.opener = self; ## }

        function openminiwin(url){

        var hWnd =

        window.open(url,“”,“width=180,height=140,resizable=yes,scrollbars=yes”);

        if (!hWnd.opener) hWnd.opener = self; ## }

        ## ## Call within body of page as: ## ## ##

        ###########################

        CONFIG FILE # 1

        ###########################

        greyjpeg.conf - produces a grey jpeg # cmd_line = 'cqcam -s 1 |

        ppmtojpeg --progressive --greyscale --optimize --quality=33
        –comment=“Made with Rubycam”’ # img_filename = ‘grey.jpg’ # title =
        ‘Greycam’

        refresh = 60

        ###########################

        CONFIG FILE # 2

        ###########################

        transgif.conf - produces a transparent gif with weird effects

        cmd_line = ‘cqcam -s 1 | ppmquant 2 | ppmtogif -transparent grey
        -interlace -sort -comment=“Made with Rubycam”’ # img_filename =
        ‘transparent.gif’

        title = ‘Psychedelicam’

        refresh = 60

        img_background_color = ‘red’

        use_randomize_img_background_color = true # use_randomize_text_color

        = true

        text_color_matches_img_background_color = true

        EOF