93_PWMR.pm : restructured readings

git-svn-id: svn://svn.code.sf.net/p/fhem/code/trunk@9817 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
jamesgo
2015-11-08 09:12:39 +00:00
parent ab11bf79b4
commit cd40448d9c
2 changed files with 147 additions and 78 deletions

View File

@@ -13,6 +13,9 @@
# 13.10.15 GA add event-on-change-reading # 13.10.15 GA add event-on-change-reading
# 14.10.15 GA fix round energyusedp # 14.10.15 GA fix round energyusedp
# 15.10.15 GA add a_regexp_on, a regular expression for the on state of the actor # 15.10.15 GA add a_regexp_on, a regular expression for the on state of the actor
# 05.11.15 GA fix new reading desired-temp-until which substitutes modification date of desired-temp in the future
# events for desired-temp adjusted (no update of timestamp if temperature stays the same)
# module for PWM (Pulse Width Modulation) calculation # module for PWM (Pulse Width Modulation) calculation
# this module defines a room for calculation # this module defines a room for calculation
@@ -107,10 +110,8 @@ PWMR_CalcDesiredTemp($)
{ {
my ($hash) = @_; my ($hash) = @_;
$hash->{STATE} = "Calculating";
if($hash->{INTERVAL} > 0) { if($hash->{INTERVAL} > 0) {
if ($hash->{INTERVAL} eq 300) { if ($hash->{INTERVAL} == 300) {
# align interval to hh:00:ss, hh:05:ss, ... hh:55:ss # align interval to hh:00:ss, hh:05:ss, ... hh:55:ss
my $n = gettimeofday(); my $n = gettimeofday();
@@ -129,21 +130,44 @@ PWMR_CalcDesiredTemp($)
} }
my $name = $hash->{NAME}; my $name = $hash->{NAME};
if ($hash->{READINGS}{"desired-temp"}{TIME} gt TimeNow()) {
Log3 ($hash, 4, "PWMR_CalcDesiredTemp $name: desired-temp was manualy set until ".
$hash->{READINGS}{"desired-temp"}{TIME});
$hash->{STATE} = "ManualSetUntil"; if (defined($hash->{READINGS}{"desired-temp-until"})) {
return undef; if ($hash->{READINGS}{"desired-temp-until"}{VAL} ne "no" ) {
} else {
Log3 ($hash, 4, "PWMR_CalcDesiredTemp $name: calc desired-temp"); if ($hash->{READINGS}{"desired-temp-until"}{VAL} gt TimeNow()) {
Log3 ($hash, 4, "PWMR_CalcDesiredTemp $name: desired-temp was manualy set until ".
$hash->{READINGS}{"desired-temp"}{TIME});
$hash->{STATE} = "ManualSetUntil";
return undef;
}
else
{
readingsSingleUpdate ($hash, "desired-temp-until", "no", 1);
Log3 ($hash, 4, "PWMR_CalcDesiredTemp $name: calc desired-temp");
}
}
} }
#if ($hash->{READINGS}{"desired-temp"}{TIME} gt TimeNow()) {
# Log3 ($hash, 4, "PWMR_CalcDesiredTemp $name: desired-temp was manualy set until ".
# $hash->{READINGS}{"desired-temp"}{TIME});
#
# $hash->{STATE} = "ManualSetUntil";
# return undef;
#} else {
# Log3 ($hash, 4, "PWMR_CalcDesiredTemp $name: calc desired-temp");
#}
#################### ####################
# frost protection # frost protection
if ($hash->{c_frostProtect} > 0) { if ($hash->{c_frostProtect} > 0) {
readingsSingleUpdate ($hash, "desired-temp", $hash->{c_tempFrostProtect}, 1); if ($hash->{READINGS}{"desired-temp"}{VAL} ne $hash->{c_tempFrostProtect}) {
readingsSingleUpdate ($hash, "desired-temp", $hash->{c_tempFrostProtect}, 1);
} else {
readingsSingleUpdate ($hash, "desired-temp", $hash->{c_tempFrostProtect}, 0);
}
#$hash->{READINGS}{"desired-tem"}{TIME} = TimeNow(); #$hash->{READINGS}{"desired-tem"}{TIME} = TimeNow();
#$hash->{READINGS}{"desired-temp"}{VAL} = $hash->{c_tempFrostProtect}; #$hash->{READINGS}{"desired-temp"}{VAL} = $hash->{c_tempFrostProtect};
@@ -160,6 +184,8 @@ PWMR_CalcDesiredTemp($)
if ($hash->{c_autoCalcTemp} > 0) { if ($hash->{c_autoCalcTemp} > 0) {
$hash->{STATE} = "Calculating";
my @time = localtime(); my @time = localtime();
my $wday = $time[6]; my $wday = $time[6];
my $cmptime = sprintf ("%02d%02d", $time[2], $time[1]); my $cmptime = sprintf ("%02d%02d", $time[2], $time[1]);
@@ -202,7 +228,11 @@ PWMR_CalcDesiredTemp($)
Log3 ($hash, 4, "PWMR_CalcDesiredTemp $name: match i:$i $points[$i] ($tempV/$temperature)"); Log3 ($hash, 4, "PWMR_CalcDesiredTemp $name: match i:$i $points[$i] ($tempV/$temperature)");
readingsSingleUpdate ($hash, "desired-temp", $temperature, 1); if ($hash->{READINGS}{"desired-temp"}{VAL} ne $temperature) {
readingsSingleUpdate ($hash, "desired-temp", $temperature, 1);
} else {
readingsSingleUpdate ($hash, "desired-temp", $temperature, 0);
}
#$hash->{READINGS}{"desired-temp"}{TIME} = TimeNow(); #$hash->{READINGS}{"desired-temp"}{TIME} = TimeNow();
#$hash->{READINGS}{"desired-temp"}{VAL} = $temperature; #$hash->{READINGS}{"desired-temp"}{VAL} = $temperature;
@@ -221,7 +251,11 @@ PWMR_CalcDesiredTemp($)
my $act_dtemp = $hash->{READINGS}{"desired-temp"}{VAL}; my $act_dtemp = $hash->{READINGS}{"desired-temp"}{VAL};
Log3 ($hash, 4, "PWMR_CalcDesiredTemp $name: use last value ($act_dtemp)"); Log3 ($hash, 4, "PWMR_CalcDesiredTemp $name: use last value ($act_dtemp)");
readingsSingleUpdate ($hash, "desired-temp", $newTemp, 1); if ($act_dtemp ne $newTemp) {
readingsSingleUpdate ($hash, "desired-temp", $newTemp, 1);
#} else {
# readingsSingleUpdate ($hash, "desired-temp", $newTemp, 0);
}
#$hash->{READINGS}{"desired-temp"}{TIME} = TimeNow(); #$hash->{READINGS}{"desired-temp"}{TIME} = TimeNow();
#$hash->{READINGS}{"desired-temp"}{VAL} = $newTemp; #$hash->{READINGS}{"desired-temp"}{VAL} = $newTemp;
@@ -237,7 +271,7 @@ PWMR_CalcDesiredTemp($)
$hash->{STATE} = "Manual"; $hash->{STATE} = "Manual";
} }
DoTrigger($name, undef); #DoTrigger($name, undef);
return undef; return undef;
} }
@@ -289,7 +323,7 @@ PWMR_Set($@)
# manualTempDuration # manualTempDuration
if ( $cmd eq "manualTempDuration" ) { if ( $cmd eq "manualTempDuration" ) {
readingsSingleUpdate ($hash, "manualTempDuration", $a[2], 0); readingsSingleUpdate ($hash, "manualTempDuration", $a[2], 1);
#$hash->{READINGS}{"manualTempDuration"}{VAL} = $a[2]; #$hash->{READINGS}{"manualTempDuration"}{VAL} = $a[2];
#$hash->{READINGS}{"manualTempDuration"}{TIME} = TimeNow(); #$hash->{READINGS}{"manualTempDuration"}{TIME} = TimeNow();
@@ -311,18 +345,29 @@ PWMR_Set($@)
$duration = int($a[3]) * 60; $duration = int($a[3]) * 60;
} }
#$hash->{READINGS}{$cmd}{TIME} = TimeNow();
# manual set desired-temp will be set for 1 hour (default) # manual set desired-temp will be set for 1 hour (default)
# afterwards it will be overwritten by auto calc # afterwards it will be overwritten by auto calc
my $now = time(); my $now = time();
$hash->{READINGS}{$cmd}{TIME} = FmtDateTime($now + $duration); readingsBeginUpdate ($hash);
$hash->{READINGS}{$cmd}{VAL} = $val; readingsBulkUpdate ($hash, "desired-temp", $a[2]);
if ($hash->{c_autoCalcTemp} == 0) {
$hash->{STATE} = "Manual";
} else {
$hash->{STATE} = "ManualSetUntil";
readingsBulkUpdate ($hash, "desired-temp-until", FmtDateTime($now + $duration));
}
readingsEndUpdate($hash, 1);
$hash->{STATE} = "ManualSetUntil"; #readingsSingleUpdate ($hash, "desired-temp", $a[2], 1);
#$hash->{READINGS}{$cmd}{TIME} = FmtDateTime($now + $duration);
#$hash->{READINGS}{$cmd}{VAL} = $val;
#push @{$hash->{CHANGED}}, "$cmd: $val";
#DoTrigger($hash, undef);
return undef return undef
} }
@@ -526,27 +571,26 @@ PWMR_SetRoom(@)
Log3 ($room, 4, "PWMR_SetRoom $name <$newState>"); Log3 ($room, 4, "PWMR_SetRoom $name <$newState>");
my $nowR = TimeNow(); my $energyused = "";
my $now = time(); if (defined($room->{READINGS}{energyused}{VAL})) {
$energyused = substr ( $room->{READINGS}{energyused}{VAL}, -29);
$room->{READINGS}{energyused}{TIME} = $nowR;
$room->{READINGS}{energyusedp}{TIME} = $nowR;
if (!defined($room->{READINGS}{energyused}{VAL})) {
$room->{READINGS}{energyused}{VAL} = "";
} }
my $energyused = substr ( $room->{READINGS}{energyused}{VAL}, -29);
# newState may be "", "on", "off" # newState may be "", "on", "off"
if ($newState eq "") { if ($newState eq "") {
$energyused = $energyused.substr ( $energyused ,-1); $energyused = $energyused.substr ( $energyused ,-1);
} else { } else {
$energyused = $energyused.($newState eq "on" ? "1" : "0"); $energyused = $energyused.($newState eq "on" ? "1" : "0");
} }
$room->{READINGS}{energyused}{VAL} = $energyused;
$room->{READINGS}{energyusedp}{VAL} = sprintf ("%.2f", ($energyused =~ tr/1//) /30);
readingsBeginUpdate ($room);
readingsBulkUpdate ($room, "energyused", $energyused);
readingsBulkUpdate ($room, "energyusedp", sprintf ("%.2f", ($energyused =~ tr/1//) /30));
readingsEndUpdate($room, 0);
return if ($newState eq ""); if ($newState eq "") {
return;
}
if ($room->{actor}) if ($room->{actor})
{ {
@@ -555,12 +599,8 @@ PWMR_SetRoom(@)
Log3 ($room, 2, "PWMR_SetRoom $room->{NAME}: set $room->{actor} $newState"); Log3 ($room, 2, "PWMR_SetRoom $room->{NAME}: set $room->{actor} $newState");
$room->{actorState} = $newState; $room->{actorState} = $newState;
readingsSingleUpdate ($room, "lastswitch", time(), 1);
$room->{READINGS}{lastswitch}{TIME} = $nowR;
$room->{READINGS}{lastswitch}{VAL} = $now;
push @{$room->{CHANGED}}, "actor $newState";
DoTrigger($name, undef);
} else { } else {
Log3 ($room, 2, "PWMR_SetRoom $name: set $room->{actor} $newState failed ($ret)"); Log3 ($room, 2, "PWMR_SetRoom $name: set $room->{actor} $newState failed ($ret)");
} }
@@ -630,20 +670,17 @@ PWMR_ReadRoom(@)
if (!$room->{READINGS}{"desired-temp"}{TIME}) if (!$room->{READINGS}{"desired-temp"}{TIME})
{ {
$room->{READINGS}{"desired-temp"}{VAL} = 6.0; readingsSingleUpdate ($room, "desired-temp", 6.0, 0);
$room->{READINGS}{"desired-temp"}{TIME} = TimeNow();
} }
if (!$room->{READINGS}{oldpulse}{TIME}) if (!$room->{READINGS}{oldpulse}{TIME})
{ {
$room->{READINGS}{oldpulse}{VAL} = 0.0; readingsSingleUpdate ($room, "oldpulse", 0.0, 0);
$room->{READINGS}{oldpulse}{TIME} = TimeNow();
} }
if (!$room->{READINGS}{lastswitch}{TIME}) if (!$room->{READINGS}{lastswitch}{TIME})
{ {
$room->{READINGS}{lastswitch}{VAL} = time(); readingsSingleUpdate ($room, "lastswitch", time(), 0);
$room->{READINGS}{lastswitch}{TIME} = TimeNow();
} }
$factor = $room->{FACTOR}; $factor = $room->{FACTOR};
@@ -850,6 +887,7 @@ PWMR_Attr(@)
$hash->{c_frostProtect} = 0; $hash->{c_frostProtect} = 0;
} elsif ($attr eq "autoCalcTemp") { } elsif ($attr eq "autoCalcTemp") {
$hash->{c_autoCalcTemp} = 1; $hash->{c_autoCalcTemp} = 1;
$hash->{STATE} = "Calculating";
} }
} }
@@ -871,10 +909,15 @@ PWMR_Attr(@)
} }
} elsif ($attr eq "autoCalcTemp") { # autoCalcTemp 0/1 } elsif ($attr eq "autoCalcTemp") { # autoCalcTemp 0/1
if ($val eq 0 or $val eq 1) { if ($val eq 0) {
$hash->{c_autoCalcTemp} = $val; $hash->{c_autoCalcTemp} = 0;
$hash->{STATE} = "Manual";
} elsif ( $val eq 1) {
$hash->{c_autoCalcTemp} = 1;
$hash->{STATE} = "Calculating";
} elsif ($val eq "") { } elsif ($val eq "") {
$hash->{c_autoCalcTemp} = 1; $hash->{c_autoCalcTemp} = 1;
$hash->{STATE} = "Calculating";
} else { } else {
return "valid values are 0 or 1"; return "valid values are 0 or 1";
} }
@@ -947,12 +990,18 @@ PWMR_Boost(@)
"temp($temperaturV) desired-temp($desiredTemp) -> boost"); "temp($temperaturV) desired-temp($desiredTemp) -> boost");
my $now = time(); my $now = time();
$room->{READINGS}{"desired-temp"}{TIME} = FmtDateTime($now + $boostDuration * 60);
$room->{READINGS}{"desired-temp"}{VAL} = $desiredTemp + $desiredOffset;
my $t = $room->{READINGS}{"desired-temp"}{VAL}; readingsBeginUpdate ($room);
push @{$room->{CHANGED}}, "desired-temp $t"; readingsBulkUpdate ($room, "desired-temp", $desiredTemp + $desiredOffset);
DoTrigger($name, undef); readingsBulkUpdate ($room, "desired-temp-until", FmtDateTime($now + $boostDuration * 60));
readingsEndUpdate($room, 1);
#$room->{READINGS}{"desired-temp"}{TIME} = FmtDateTime($now + $boostDuration * 60);
#$room->{READINGS}{"desired-temp"}{VAL} = $desiredTemp + $desiredOffset;
#my $t = $room->{READINGS}{"desired-temp"}{VAL};
#push @{$room->{CHANGED}}, "desired-temp $t";
#DoTrigger($name, undef);
Log3 ($room, 4, "PWMR_Boost: $name ". Log3 ($room, 4, "PWMR_Boost: $name ".
"set desiredtemp ".$room->{READINGS}{"desired-temp"}{TIME}." ". "set desiredtemp ".$room->{READINGS}{"desired-temp"}{TIME}." ".

View File

@@ -6,6 +6,10 @@
# #
# 21.09.15 GA update, use Log3 # 21.09.15 GA update, use Log3
# 07.10.15 GA initial version published # 07.10.15 GA initial version published
# 13.10.15 GA add event-on-change-reading
# 13.10.15 GA add several readings
# 15.10.15 GA add reading for avg pulses
############################################## ##############################################
# $Id: # $Id:
@@ -42,7 +46,6 @@ sub PWM_Set($@);
sub PWM_Define($$); sub PWM_Define($$);
sub PWM_Calculate($); sub PWM_Calculate($);
sub PWM_Undef($$); sub PWM_Undef($$);
sub PWM_State($$$$);
sub PWM_CalcRoom(@); sub PWM_CalcRoom(@);
my %roomsWaitOffset = (); my %roomsWaitOffset = ();
@@ -57,9 +60,8 @@ PWM_Initialize($)
$hash->{SetFn} = "PWM_Set"; $hash->{SetFn} = "PWM_Set";
$hash->{DefFn} = "PWM_Define"; $hash->{DefFn} = "PWM_Define";
$hash->{UndefFn} = "PWM_Undef"; $hash->{UndefFn} = "PWM_Undef";
#$hash->{StateFn} = "PWM_State";
$hash->{AttrList} = ""; $hash->{AttrList} = "event-on-change-reading";
} }
@@ -77,6 +79,7 @@ PWM_Calculate($)
my %RoomsPulses = (); my %RoomsPulses = ();
my $roomsActive = 0; my $roomsActive = 0;
my $newpulseSum = 0; my $newpulseSum = 0;
my $newpulseMax = 0;
my $wkey = ""; my $wkey = "";
if($hash->{INTERVAL} > 0) { if($hash->{INTERVAL} > 0) {
@@ -85,9 +88,11 @@ PWM_Calculate($)
Log3 ($hash, 3, "PWM_Calculate $name"); Log3 ($hash, 3, "PWM_Calculate $name");
readingsBeginUpdate ($hash);
#$hash->{STATE} = "lastrun: ".TimeNow(); #$hash->{STATE} = "lastrun: ".TimeNow();
#$hash->{STATE} = "calculating"; #$hash->{STATE} = "calculating";
readingsSingleUpdate ($hash, "lastrun", "calculating", 1); readingsBulkUpdate ($hash, "lastrun", "calculating");
$hash->{STATE} = "lastrun: ".$hash->{READINGS}{lastrun}{TIME}; $hash->{STATE} = "lastrun: ".$hash->{READINGS}{lastrun}{TIME};
# loop over all devices # loop over all devices
@@ -127,6 +132,7 @@ PWM_Calculate($)
$roomsActive++; $roomsActive++;
$RoomsPulses{$d} = $newpulse; $RoomsPulses{$d} = $newpulse;
$newpulseSum += $newpulse; $newpulseSum += $newpulse;
$newpulseMax = max($newpulseMax, $newpulse);
# $newstate ne "" -> state changed "on" -> "off" or "off" -> "on" # $newstate ne "" -> state changed "on" -> "off" or "off" -> "on"
if ((int($hash->{MINONOFFTIME}) > 0) && if ((int($hash->{MINONOFFTIME}) > 0) &&
@@ -263,7 +269,6 @@ PWM_Calculate($)
#my $maxRoomsOn = $roomsActive * 0.6; # 11 rooms -> max 6 active #my $maxRoomsOn = $roomsActive * 0.6; # 11 rooms -> max 6 active
#$maxRoomsOn = (8 * 0.7) if ($roomsActive < 8); #$maxRoomsOn = (8 * 0.7) if ($roomsActive < 8);
# HERE
my $maxRoomsOn = $roomsActive - $hash->{NoRoomsToStayOff}; my $maxRoomsOn = $roomsActive - $hash->{NoRoomsToStayOff};
# #
@@ -309,8 +314,8 @@ PWM_Calculate($)
# $minRoomsOn = 0; # $minRoomsOn = 0;
#} #}
# HERE
my $minRoomsOn = $hash->{NoRoomsToStayOn}; my $minRoomsOn = $hash->{NoRoomsToStayOn};
my $minRoomsOnList = "";
if ($minRoomsOn > 0) { if ($minRoomsOn > 0) {
@@ -322,9 +327,11 @@ PWM_Calculate($)
last if ($roomsCounted == $minRoomsOn); last if ($roomsCounted == $minRoomsOn);
Log3 ($hash, 3, "PWM_Calculate: loop $roomsCounted $room $RoomsPulses{$room}"); Log3 ($hash, 3, "PWM_Calculate: loop $roomsCounted $room $RoomsPulses{$room}");
$minRoomsOnList .= "$room,";
$pulseSum += $RoomsPulses{$room}; $pulseSum += $RoomsPulses{$room};
$roomsCounted++; $roomsCounted++;
} }
$minRoomsOnList =~ s/,$//;
#if ($roomsActive == 0 or $hash->{NoRoomsToStayOnThreshold} == 0 or $newpulseSum/$roomsActive < $hash->{NoRoomsToStayOnThreshold}) { #if ($roomsActive == 0 or $hash->{NoRoomsToStayOnThreshold} == 0 or $newpulseSum/$roomsActive < $hash->{NoRoomsToStayOnThreshold}) {
@@ -370,21 +377,35 @@ PWM_Calculate($)
# now process the calculated actions # now process the calculated actions
# #
my $cntRoomsOn = 0;
my $cntRoomsOff = 0;
my $pulseRoomsOn = 0;
my $pulseRoomsOff = 0;
foreach my $roomStay (sort keys %RoomsToStayOff) { foreach my $roomStay (sort keys %RoomsToStayOff) {
PWMR_SetRoom ($defs{$roomStay}, ""); PWMR_SetRoom ($defs{$roomStay}, "");
$cntRoomsOff++;
$pulseRoomsOff += $RoomsPulses{$roomStay};
} }
foreach my $roomStay (sort keys %RoomsToStayOn) { foreach my $roomStay (sort keys %RoomsToStayOn) {
PWMR_SetRoom ($defs{$roomStay}, ""); PWMR_SetRoom ($defs{$roomStay}, "");
$cntRoomsOn++;
$pulseRoomsOn += $RoomsPulses{$roomStay};
} }
foreach my $roomOff (sort keys %RoomsToSwitchOff) { foreach my $roomOff (sort keys %RoomsToSwitchOff) {
PWMR_SetRoom ($defs{$roomOff}, "off"); PWMR_SetRoom ($defs{$roomOff}, "off");
$cntRoomsOff++;
$pulseRoomsOff += $RoomsPulses{$roomOff};
} }
foreach my $roomOn (sort keys %RoomsToSwitchOn) { foreach my $roomOn (sort keys %RoomsToSwitchOn) {
@@ -393,8 +414,27 @@ PWM_Calculate($)
$roomsWaitOffset{$wkey} = 0; $roomsWaitOffset{$wkey} = 0;
PWMR_SetRoom ($defs{$roomOn}, "on"); PWMR_SetRoom ($defs{$roomOn}, "on");
$cntRoomsOn++;
$pulseRoomsOn += $RoomsPulses{$roomOn};
} }
readingsBulkUpdate ($hash, "roomsActive", $roomsActive);
readingsBulkUpdate ($hash, "roomsOn", $cntRoomsOn);
readingsBulkUpdate ($hash, "roomsOff", $cntRoomsOff);
readingsBulkUpdate ($hash, "avgPulseRoomsOn", ($cntRoomsOn > 0 ? sprintf ("%.2f", $pulseRoomsOn / $cntRoomsOn) : 0));
readingsBulkUpdate ($hash, "avgPulseRoomsOff", ($cntRoomsOff > 0 ? sprintf ("%.2f", $pulseRoomsOff /$cntRoomsOff) : 0));
readingsBulkUpdate ($hash, "pulseMax", $newpulseMax);
readingsBulkUpdate ($hash, "pulseSum", $newpulseSum);
if ( $hash->{NoRoomsToStayOn} > 0) {
readingsBulkUpdate ($hash, "roomsToStayOn", $minRoomsOn);
readingsBulkUpdate ($hash, "roomsToStayOnList", $minRoomsOnList);
}
readingsEndUpdate($hash, 1);
# if(!$hash->{LOCAL}) { # if(!$hash->{LOCAL}) {
# DoTrigger($name, undef) if($init_done); # DoTrigger($name, undef) if($init_done);
# } # }
@@ -662,26 +702,6 @@ sub PWM_Undef($$)
return undef; return undef;
}
###################################
sub PWM_State($$$$)
{
my ($hash, $time, $var, $value) = @_;
my $name = $hash->{NAME};
Log3 ($hash, 3, "PWM States $name: $time $var $value");
$hash->{READINGS}{$var}{VAL} = $value;
$hash->{READINGS}{$var}{TIME} = $time;
#if ($var =~ /INTERVAL|SCOPE|CYCLETIME/)
#{
# Log3 ($hash, 3, "PWM States $name: set $var $value");
# $hash->{$var} = $value;
#}
return undef;
} }
1; 1;