Vivotek PTZ module

If you've made a patch to quick fix a bug or to add a new feature not yet in the main tree then post it here so others can try it out.
Post Reply
User avatar
Normando
Posts: 219
Joined: Sun Aug 17, 2008 5:34 am
Location: Rosario - Argentina

Vivotek PTZ module

Post by Normando »

Well, this is the vivotek module to control Vivotek PT7135 camera.
Name this file as "VivotekPT7135.pm" and copy under "control" perl modules.

Code: Select all

# ==========================================================================
#
# This module contains the implementation of the Vivotek PT7135 protocol
# It is easy to adapt to other Vivotek cameras. I have found a lot of commands with Wireshark
# This protocol get some info from the camera through receiveCmd function.
# Implement a pseudo diagonal movement
# Where go "presetClear" function from php code?
# Any improve is welcome, and please share it
# Normando Hall nhall[AT]unixlan[DOT]com[DOT]ar
# 


package ZoneMinder::Control::VivotekPT7135;

use 5.006;
use strict;
use warnings;

require ZoneMinder::Base;
require ZoneMinder::Control;

our @ISA = qw(ZoneMinder::Control);

our $VERSION = $ZoneMinder::Base::VERSION;

# ==========================================================================
#
# Vivotek PT7135 Control Protocol
#
# ==========================================================================

use ZoneMinder::Debug qw(:all);
use ZoneMinder::Config qw(:all);

use Time::HiRes qw( usleep );

sub new
{
    my $class = shift;
    my $id = shift;
    my $self = ZoneMinder::Control->new( $id );
    bless( $self, $class );
    srand( time() );
    return $self;
}

our $AUTOLOAD;

sub AUTOLOAD
{
    my $self = shift;
    my $class = ref($self) || croak( "$self not object" );
    my $name = $AUTOLOAD;
    $name =~ s/.*://;
    if ( exists($self->{$name}) )
    {
        return( $self->{$name} );
    }
    Fatal( "Can't access $name member of object of class $class" );
}

sub open
{
    my $self = shift;

    $self->loadMonitor();

    use LWP::UserAgent;
    $self->{ua} = LWP::UserAgent->new;
    $self->{ua}->agent( "ZoneMinder Control Agent/".ZM_VERSION );

    $self->{state} = 'open';
}


sub close
{
    my $self = shift;
    $self->{state} = 'closed';
}

sub printMsg
{
    my $self = shift;
    my $msg = shift;
    my $msg_len = length($msg);

    Debug( $msg."[".$msg_len."]" );
}

sub sendCmd
{
    my $self = shift;
    my $cmd = shift;

    my $result = undef;

    printMsg( $cmd, "Tx" );
    #print( "http://$address/$cmd\n" );
    my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."$cmd" );
    my $res = $self->{ua}->request($req);

    if ( $res->is_success )
    {
        $result = !undef;
    }
    else
    {
        Error( "Error check failed: '".$res->status_line()."'" );
    }

    return( $result );
}

sub receiveCmd
{
    my $self = shift;
    my $cmd = shift;

    my $result = undef;

    printMsg( $cmd, "Rx" );
    #print( "http://$address/$cmd\n" );
    my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."$cmd" );
    my $res = $self->{ua}->request($req);
    my $content = $res->content();
    if ( $res->is_success )
    {
        $result = $content;
    }
    else
    {
        Error( "Error check failed: '".$res->status_line()."'" );
    }

    return( $result );
}

sub reset
{
    my $self = shift;
    Debug( "Camera Reset" );
    my $cmd = "/cgi-bin/admin/setparam.cgi?System_Reset=3";
    $self->sendCmd( $cmd );
}

sub moveMap
{
    my $self = shift;
    my $params = shift;
    my $xcoord = $self->getParam( $params, 'xcoord' );
    my $ycoord = $self->getParam( $params, 'ycoord' );
    my $imagewidth = $self->{Monitor}->{Width};
    my $imageheight = $self->{Monitor}->{Height};
    Debug( "Move Map to $xcoord,$ycoord at $imagewidth/$imageheight" );
    if ( $imagewidth == "640" )
    {
    $xcoord = $xcoord/2;
    $ycoord = $ycoord/2;    
    }
    my $cmd = "/cgi-bin/camctrl.cgi?cam1&x=$xcoord&y=$ycoord";
    $self->sendCmd( $cmd );
}

sub moveRelUp
{
    my $self = shift;
    my $params = shift;
    my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
    Debug( "Move Up - Speed $tiltspeed" );
    my $cmd = "/cgi-bin/camctrl.cgi?move=up&speedtilt=$tiltspeed";
    $self->sendCmd( $cmd );
}

sub moveRelDown
{
    my $self = shift;
    my $params = shift;
    my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
    Debug( "Move Down - Speed $tiltspeed" );
    my $cmd = "/cgi-bin/camctrl.cgi?move=down&speedtilt=$tiltspeed";
    $self->sendCmd( $cmd );
}

sub moveRelLeft
{
    my $self = shift;
    my $params = shift;
    my $panspeed = $self->getParam( $params, 'panspeed' );
    Debug( "Move Left - Speed $panspeed" );
    my $cmd = "/cgi-bin/camctrl.cgi?move=left&speedpan=$panspeed";
    $self->sendCmd( $cmd );
}

sub moveRelRight
{
    my $self = shift;
    my $params = shift;
    my $panspeed = $self->getParam( $params, 'panspeed' );
    Debug( "Move Right - Speed $panspeed" );
    my $cmd = "/cgi-bin/camctrl.cgi?move=right&speedpan=$panspeed";
    $self->sendCmd( $cmd );
}

sub moveRelUpRight
{
    my $self = shift;
    my $params = shift;
    my $panspeed = $self->getParam( $params, 'panspeed' );
    my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
    Debug( "Move Up/Right - Speed $tiltspeed/$panspeed" );
    my $cmd = "/cgi-bin/camctrl.cgi?move=right&speedpan=$panspeed";
    $self->sendCmd( $cmd );
    my $cmd = "/cgi-bin/camctrl.cgi?move=up&speedtilt=$tiltspeed";
    $self->sendCmd( $cmd );
}

sub moveRelUpLeft
{
    my $self = shift;
    my $params = shift;
    my $panspeed = $self->getParam( $params, 'panspeed' );
    my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
    Debug( "Step Up/Left - Speed $tiltspeed/$panspeed" );
    my $cmd = "/cgi-bin/camctrl.cgi?move=left&speedpan=$panspeed";
    $self->sendCmd( $cmd );
    my $cmd = "/cgi-bin/camctrl.cgi?move=up&speedtilt=$tiltspeed";
    $self->sendCmd( $cmd );
}

sub moveRelDownRight
{
    my $self = shift;
    my $params = shift;
    my $panspeed = $self->getParam( $params, 'panspeed' );
    my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
    Debug( "Step Down/Right - Speed $tiltspeed/$panspeed" );
    my $cmd = "/cgi-bin/camctrl.cgi?move=right&speedpan=$panspeed";
    $self->sendCmd( $cmd );
    my $cmd = "/cgi-bin/camctrl.cgi?move=down&speedtilt=$tiltspeed";
    $self->sendCmd( $cmd );
}

sub moveRelDownLeft
{
    my $self = shift;
    my $params = shift;
    my $panspeed = $self->getParam( $params, 'panspeed' );
    my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
    Debug( "Step Down/Left - Speed $tiltspeed/$panspeed" );
    my $cmd = "/cgi-bin/camctrl.cgi?move=left&speedpan=$panspeed";
    $self->sendCmd( $cmd );
    my $cmd = "/cgi-bin/camctrl.cgi?move=down&speedtilt=$tiltspeed";
    $self->sendCmd( $cmd );
}

sub whiteAuto
{
    my $self = shift;
    Debug( "White Auto" );
    my $cmd = "/cgi-bin/admin/setparam.cgi?Video_Whitebalance=0";
    $self->sendCmd( $cmd );
}

sub whiteMan
{
    my $self = shift;
    Debug( "White Man" );
    my $cmd = "/cgi-bin/admin/setparam.cgi?Video_Whitebalance=2";
    $self->sendCmd( $cmd );
}

sub In
{
    my $self = shift;
    Debug( "White In" );
    my $cmd = "/cgi-bin/admin/setparam.cgi?Video_Whitebalance=1";
    $self->sendCmd( $cmd );
}

sub Out
{
    my $self = shift;
    Debug( "White Out" );
    my $cmd = "/cgi-bin/admin/setparam.cgi?Video_Whitebalance=3";
    $self->sendCmd( $cmd );
}

sub presetClear
{
    my $self = shift;
    my $params = shift;
    my $preset = $self->getParam( $params, 'preset' );
    my $preset = ( $preset - 1 );
    Debug( "Clear Preset $preset" );
    my $cmd = "/cgi-bin/admin/preset.cgi?delpos=$preset&Submit=Delete";
    $self->sendCmd( $cmd );
}

sub presetSet
{
    my $self = shift;
    my $params = shift;
    my $preset = $self->getParam( $params, 'preset' );
    my $preset = ( $preset - 1 );
    my $cmd = "/cgi-bin/admin/getparam.cgi?camctrl_axisx";
    my $rx = $self->receiveCmd( $cmd );
    my ($axisx) = $rx =~ /([-0-9]+)/;
    my $cmd = "/cgi-bin/admin/getparam.cgi?camctrl_axisy";
    my $rx = $self->receiveCmd( $cmd );
    my ($axisy) = $rx =~ /([-0-9]+)/;
    Debug( "Set Preset $preset at $axisx and $axisy" );
    my $cmd = "/cgi-bin/admin/setparam.cgi?camctrl_presetname_$preset=$preset&camctrl_presetpan_$preset=$axisx&camctrl_presettilt_$preset=$axisy";
    $self->sendCmd( $cmd );
}

sub presetGoto
{
    my $self = shift;
    my $params = shift;
    my $preset = $self->getParam( $params, 'preset' );
    my $preset = ( $preset - 1 );
    Debug( "Goto Preset $preset" );
    my $cmd = "/cgi-bin/recall.cgi?recall=$preset";
    $self->sendCmd( $cmd );
}

sub presetHome
{
    my $self = shift;
    Debug( "Home Preset" );
    my $cmd = "/cgi-bin/camctrl.cgi?move=home";
    $self->sendCmd( $cmd );
}

1;
__END__
Under control tab of your monitor:

Code: Select all

Controllable: check
Control Device: none
Control Address: the camera IP, or user:pass@camera_ip
Return Location: Home
Leave other as default

Then click on "Edit" link at "Control Type" to create the new control module in the db.

At the new window click at the "Create New Control" button.

Code: Select all

MAIN:

Name: Vivotek PT7135
Type: Remote
Protocol: VivotekPT7135
Can Reset: Check


MOVE

Can Move: check
Can Move Diagonally: check
Can Move Mapped: check
Can Move Relative: check

PAN

Can Pan: check
Has Pan Speed: check
Min Pan Speed: -5
Max Pan Speed: 5

TILT

Can Tilt: check
Has Tilt Speed: check
Min Tilt Speed: -5
Max Tilt Speed: 5

WHITE

Can White Balance: check
Can Auto White Bal.: check

PRESETS

Has Presets: check
Num Presets: 20
Can Set Presets: check

Then, save and refresh you "Control Capabilities" window, and then close.

At your monitor window, refresh and selec from the pull-down list "Vivotek PT7135" at the "Control Type" field.

Save and enjoy
Last edited by Normando on Wed Sep 10, 2008 3:04 am, edited 2 times in total.
User avatar
Normando
Posts: 219
Joined: Sun Aug 17, 2008 5:34 am
Location: Rosario - Argentina

Post by Normando »

BTW: where go "presetClear" command? I have searched in the php files, and there is no exist. How to add this command/button?
User avatar
Normando
Posts: 219
Joined: Sun Aug 17, 2008 5:34 am
Location: Rosario - Argentina

Post by Normando »

Because Relative Diagonal Movements can't supply 'panspeed' or 'tiltspeed' parameter nor 'panstep' nor 'step' nor 'speed' (in don't know why), you sould modify the four relative diagonal functions to something like this. I give you an example for "moveRelUpRight":

Code: Select all

sub moveRelUpRight
{
    my $self = shift;
    my $params = shift;
#    my $panspeed = $self->getParam( $params, 'panspeed' );
#    my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
    my $panspeed = 0;
    my $tiltspeed = 0;
    Debug( "Move Up/Right - Speed $tiltspeed/$panspeed" );
    my $cmd = "/cgi-bin/camctrl.cgi?move=right&speedpan=$panspeed";
    $self->sendCmd( $cmd );
    my $cmd = "/cgi-bin/camctrl.cgi?move=up&speedtilt=$tiltspeed";
    $self->sendCmd( $cmd );
}
johnnytolengo
Posts: 184
Joined: Tue Oct 14, 2008 5:59 pm

Post by johnnytolengo »

Thank for your effort , the script looks good. I have some questions.

Is it this camera a good choice?

I am looking arround cameras, this one is cheaper than other ones and looks good, my point is I don't want to buy something which will not work with zoneminder.

What about the image quality?

thank you in advance.


Compatriota tolengo desde Czech, gracias.
renemorenotx
Posts: 2
Joined: Sat Nov 28, 2009 4:20 am

SD7151 PTZ Zoneminder Control

Post by renemorenotx »

I Added the Control type like instructed on top. Where do I save the .pm file.
The only file I see is in /usr/bin zmcontrol.pl file. Do I edit this file?
A little new to zoneminder.
Notice: Undefined index: WhiteRoot in /usr/share/zoneminder/skins/classic/includes/control_functions.php on line 86

Notice: Undefined index: WhiteRoot in /usr/share/zoneminder/skins/classic/includes/control_functions.php on line 87
In
White
Out
Pan/Tilt- I get this when I hit control tab under source when I look at the video feed.
ilios
Posts: 20
Joined: Sun Jun 20, 2010 5:28 pm

control module

Post by ilios »

does your module apply also to vivotek ptz7131?

http://www.vivotek.com/products/model.p ... era=pz7131

i have tied following your instruction butt no success...

can you please help to make the ptz control work on that camera?

thanksa lot!!
merlino63
Posts: 6
Joined: Thu May 20, 2010 7:56 pm

Vivotek PZ7131.pm

Post by merlino63 »

This is .pm file for IP CAM Vivotek PZ7131
# ==========================================================================
#
# This module contains the implementation of the Vivotek PT7135 protocol
# It is easy to adapt to other Vivotek cameras. I have found a lot of commands with Wireshark
# This protocol get some info from the camera through receiveCmd function.
# Implement a pseudo diagonal movement
# Where go "presetClear" function from php code?
# Any improve is welcome, and please share it
# Normando Hall nhall[AT]unixlan[DOT]com[DOT]ar
#


package ZoneMinder::Control::VivotekPT7131;

use 5.006;
use strict;
use warnings;

require ZoneMinder::Base;
require ZoneMinder::Control;

our @ISA = qw(ZoneMinder::Control);

our $VERSION = $ZoneMinder::Base::VERSION;

# ==========================================================================
#
# Vivotek PZ7131 Control Protocol
#
# ==========================================================================

use ZoneMinder::Debug qw(:all);
use ZoneMinder::Config qw(:all);

use Time::HiRes qw( usleep );

sub new
{
my $class = shift;
my $id = shift;
my $self = ZoneMinder::Control->new( $id );
bless( $self, $class );
srand( time() );
return $self;
}

our $AUTOLOAD;

sub AUTOLOAD
{
my $self = shift;
my $class = ref($self) || croak( "$self not object" );
my $name = $AUTOLOAD;
$name =~ s/.*://;
if ( exists($self->{$name}) )
{
return( $self->{$name} );
}
Fatal( "Can't access $name member of object of class $class" );
}

sub open
{
my $self = shift;

$self->loadMonitor();

use LWP::UserAgent;
$self->{ua} = LWP::UserAgent->new;
$self->{ua}->agent( "ZoneMinder Control Agent/".ZM_VERSION );

$self->{state} = 'open';
}


sub close
{
my $self = shift;
$self->{state} = 'closed';
}

sub printMsg
{
my $self = shift;
my $msg = shift;
my $msg_len = length($msg);

Debug( $msg."[".$msg_len."]" );
}

sub sendCmd
{
my $self = shift;
my $cmd = shift;

my $result = undef;

printMsg( $cmd, "Tx" );
#print( "http://$address/$cmd\n" );
my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."$cmd" );
my $res = $self->{ua}->request($req);

if ( $res->is_success )
{
$result = !undef;
}
else
{
Error( "Error check failed: '".$res->status_line()."'" );
}

return( $result );
}

sub receiveCmd
{
my $self = shift;
my $cmd = shift;

my $result = undef;

printMsg( $cmd, "Rx" );
#print( "http://$address/$cmd\n" );
my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."$cmd" );
my $res = $self->{ua}->request($req);
my $content = $res->content();
if ( $res->is_success )
{
$result = $content;
}
else
{
Error( "Error check failed: '".$res->status_line()."'" );
}

return( $result );
}

sub reset
{
my $self = shift;
Debug( "Camera Reset" );
my $cmd = "/cgi-bin/admin/setparam.cgi?reset=3";
$self->sendCmd( $cmd );
}

sub moveMap
{
my $self = shift;
my $params = shift;
my $xcoord = $self->getParam( $params, 'xcoord' );
my $ycoord = $self->getParam( $params, 'ycoord' );
my $imagewidth = $self->{Monitor}->{Width};
my $imageheight = $self->{Monitor}->{Height};
Debug( "Move Map to $xcoord,$ycoord at $imagewidth/$imageheight" );
if ( $imagewidth == "640" )
{
$xcoord = $xcoord/2;
$ycoord = $ycoord/2;
}
my $cmd = "/cgi-bin/viewer/camctrl.cgi?channel=0&cameraid=1&vx=$xcoord&vy=$ycoord&vs=3";
$self->sendCmd( $cmd );
}

sub moveRelUp
{
my $self = shift;
my $params = shift;
my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
Debug( "Move Up - Speed $tiltspeed" );
my $cmd = "/cgi-bin/viewer/camctrl.cgi?move=up&tiltspeed=$tiltspeed";
$self->sendCmd( $cmd );
}

sub moveRelDown
{
my $self = shift;
my $params = shift;
my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
Debug( "Move Down - Speed $tiltspeed" );
my $cmd = "/cgi-bin/viewer/camctrl.cgi?move=down&tiltspeed=$tiltspeed";
$self->sendCmd( $cmd );
}

sub moveRelLeft
{
my $self = shift;
my $params = shift;
my $panspeed = $self->getParam( $params, 'panspeed' );
Debug( "Move Left - Speed $panspeed" );
my $cmd = "/cgi-bin/viewer/camctrl.cgi?move=left&panspeed=$panspeed";
$self->sendCmd( $cmd );
}

sub moveRelRight
{
my $self = shift;
my $params = shift;
my $panspeed = $self->getParam( $params, 'panspeed' );
Debug( "Move Right - Speed $panspeed" );
my $cmd = "/cgi-bin/viewer/camctrl.cgi?move=right&panspeed=$panspeed";
$self->sendCmd( $cmd );
}

sub moveRelUpRight
{
my $self = shift;
my $params = shift;
my $panspeed = $self->getParam( $params, 'panspeed' );
my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
Debug( "Move Up/Right - Speed $tiltspeed/$panspeed" );
my $cmd = "/cgi-bin/viewer/camctrl.cgi?move=right&panspeed=$panspeed";
$self->sendCmd( $cmd );
my $cmd = "/cgi-bin/viewer/camctrl.cgi?move=up&tiltspeed=$tiltspeed";
$self->sendCmd( $cmd );
}

sub moveRelUpLeft
{
my $self = shift;
my $params = shift;
my $panspeed = $self->getParam( $params, 'panspeed' );
my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
Debug( "Step Up/Left - Speed $tiltspeed/$panspeed" );
my $cmd = "/cgi-bin/viewer/camctrl.cgi?move=left&panspeed=$panspeed";
$self->sendCmd( $cmd );
my $cmd = "/cgi-bin/viewer/camctrl.cgi?move=up&tiltspeed=$tiltspeed";
$self->sendCmd( $cmd );
}

sub moveRelDownRight
{
my $self = shift;
my $params = shift;
my $panspeed = $self->getParam( $params, 'panspeed' );
my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
Debug( "Step Down/Right - Speed $tiltspeed/$panspeed" );
my $cmd = "/cgi-bin/viewer/camctrl.cgi?move=right&panspeed=$panspeed";
$self->sendCmd( $cmd );
my $cmd = "/cgi-bin/viewer/camctrl.cgi?move=down&tiltspeed=$tiltspeed";
$self->sendCmd( $cmd );
}

sub moveRelDownLeft
{
my $self = shift;
my $params = shift;
my $panspeed = $self->getParam( $params, 'panspeed' );
my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
Debug( "Step Down/Left - Speed $tiltspeed/$panspeed" );
my $cmd = "/cgi-bin/viewer/camctrl.cgi?move=left&panspeed=$panspeed";
$self->sendCmd( $cmd );
my $cmd = "/cgi-bin/viewer/camctrl.cgi?move=down&stiltspeed=$tiltspeed";
$self->sendCmd( $cmd );
}

sub whiteAuto
{
my $self = shift;
Debug( "White Auto" );
my $cmd = "/cgi-bin/admin/setparam.cgi?whitebalance=auto";
$self->sendCmd( $cmd );
}

sub whiteMan
{
my $self = shift;
Debug( "White Man" );
my $cmd = "/cgi-bin/admin/setparam.cgi?whitebalance=2";
$self->sendCmd( $cmd );
}

sub In
{
my $self = shift;
Debug( "White In" );
my $cmd = "/cgi-bin/admin/setparam.cgi?whitebalance=1";
$self->sendCmd( $cmd );
}

sub Out
{
my $self = shift;
Debug( "White Out" );
my $cmd = "/cgi-bin/admin/setparam.cgi?whitebalance=3";
$self->sendCmd( $cmd );
}

sub presetClear
{
my $self = shift;
my $params = shift;
my $preset = $self->getParam( $params, 'preset' );
my $preset = ( $preset - 1 );
Debug( "Clear Preset $preset" );
my $cmd = "/cgi-bin/operator/ePreset.cgi?channel=0&delpos=$preset&Submit=Delete";
$self->sendCmd( $cmd );
}

sub presetSet
{
my $self = shift;
my $params = shift;
my $preset = $self->getParam( $params, 'preset' );
my $preset = ( $preset - 1 );
my $cmd = "/cgi-bin/admin/getparam.cgi?axisx";
my $rx = $self->receiveCmd( $cmd );
my ($axisx) = $rx =~ /([-0-9]+)/;
my $cmd = "/cgi-bin/admin/getparam.cgi?axisy";
my $rx = $self->receiveCmd( $cmd );
my ($axisy) = $rx =~ /([-0-9]+)/;
Debug( "Set Preset $preset at $axisx and $axisy" );
my $cmd = "/cgi-bin/operator/ePreset.cgi?preset_i'$preset=$preset'_name&preset_i'$preset=$axisx'_pos&preset_i'$preset=$axisy'_size";
$self->sendCmd( $cmd );
}

sub presetGoto
{
my $self = shift;
my $params = shift;
my $preset = $self->getParam( $params, 'preset' );
my $preset = ( $preset - 1 );
Debug( "Goto Preset $preset" );
my $cmd = "/cgi-bin/camctrl/eRecall.cgi?channel=0&Recall=$preset";
$self->sendCmd( $cmd );
}

sub presetHome
{
my $self = shift;
Debug( "Home Preset" );
my $cmd = "/cgi-bin/viewer/camctrl.cgi?move=home";
$self->sendCmd( $cmd );
}

1;
__END__

===============================================


Zoom parameter are not correct but i correct it fast
Bye
Post Reply