Skip to content

Commit

Permalink
Add experimental support for Hitachi A/C 344 bit protocol
Browse files Browse the repository at this point in the history
- Add `sendHitachiAc344` method.
- Extend `decodeHitachiAc()` to handle 344 bits.
- Unit test coverage (and improvements)

For #1134
  • Loading branch information
crankyoldgit committed May 23, 2020
1 parent 494c595 commit 7246401
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 11 deletions.
5 changes: 5 additions & 0 deletions src/IRrecv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,11 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
decodeHitachiAc3(results, offset, kHitachiAc3MinBits))
return true;
#endif // DECODE_HITACHI_AC3
#if DECODE_HITACHI_AC344
// HitachiAC344 should be checked before HitachiAC
DPRINTLN("Attempting Hitachi AC344 decode");
if (decodeHitachiAC(results, offset, kHitachiAc344Bits)) return true;
#endif // DECODE_HITACHI_AC344
#if DECODE_HITACHI_AC2
// HitachiAC2 should be checked before HitachiAC
DPRINTLN("Attempting Hitachi AC2 decode");
Expand Down
15 changes: 13 additions & 2 deletions src/IRremoteESP8266.h
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,13 @@
#define SEND_HITACHI_AC3 _IR_ENABLE_DEFAULT_
#endif // SEND_HITACHI_AC3

#ifndef DECODE_HITACHI_AC344
#define DECODE_HITACHI_AC344 _IR_ENABLE_DEFAULT_
#endif // DECODE_HITACHI_AC344
#ifndef SEND_HITACHI_AC344
#define SEND_HITACHI_AC344 _IR_ENABLE_DEFAULT_
#endif // SEND_HITACHI_AC344

#ifndef DECODE_HITACHI_AC424
#define DECODE_HITACHI_AC424 _IR_ENABLE_DEFAULT_
#endif // DECODE_HITACHI_AC424
Expand Down Expand Up @@ -645,7 +652,8 @@
DECODE_DAIKIN216 || DECODE_SHARP_AC || DECODE_DAIKIN160 || \
DECODE_NEOCLIMA || DECODE_DAIKIN176 || DECODE_DAIKIN128 || \
DECODE_AMCOR || DECODE_DAIKIN152 || DECODE_MITSUBISHI136 || \
DECODE_MITSUBISHI112 || DECODE_HITACHI_AC424 || DECODE_HITACHI_AC3)
DECODE_MITSUBISHI112 || DECODE_HITACHI_AC424 || DECODE_HITACHI_AC3 || \
DECODE_HITACHI_AC344)
#define DECODE_AC true // We need some common infrastructure for decoding A/Cs.
#else
#define DECODE_AC false // We don't need that infrastructure.
Expand Down Expand Up @@ -767,8 +775,9 @@ enum decode_type_t {
MULTIBRACKETS,
CARRIER_AC40,
CARRIER_AC64,
HITACHI_AC344, // 85
// Add new entries before this one, and update it to point to the last entry.
kLastDecodeType = CARRIER_AC64,
kLastDecodeType = HITACHI_AC344,
};

// Message lengths & required repeat values
Expand Down Expand Up @@ -861,6 +870,8 @@ const uint16_t kHitachiAc3StateLength = 27;
const uint16_t kHitachiAc3Bits = kHitachiAc3StateLength * 8;
const uint16_t kHitachiAc3MinStateLength = 15;
const uint16_t kHitachiAc3MinBits = kHitachiAc3MinStateLength * 8;
const uint16_t kHitachiAc344StateLength = 43;
const uint16_t kHitachiAc344Bits = kHitachiAc344StateLength * 8;
const uint16_t kHitachiAc424StateLength = 53;
const uint16_t kHitachiAc424Bits = kHitachiAc424StateLength * 8;
const uint16_t kInaxBits = 24;
Expand Down
7 changes: 7 additions & 0 deletions src/IRsend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
return kHitachiAc2Bits;
case HITACHI_AC3:
return kHitachiAc3Bits;
case HITACHI_AC344:
return kHitachiAc344Bits;
case HITACHI_AC424:
return kHitachiAc424Bits;
case KELVINATOR:
Expand Down Expand Up @@ -1116,6 +1118,11 @@ bool IRsend::send(const decode_type_t type, const unsigned char *state,
sendHitachiAc3(state, nbytes);
break;
#endif // SEND_HITACHI_AC3
#if SEND_HITACHI_AC344
case HITACHI_AC344:
sendHitachiAc344(state, nbytes);
break;
#endif // SEND_HITACHI_AC344
#if SEND_HITACHI_AC424
case HITACHI_AC424:
sendHitachiAc424(state, nbytes);
Expand Down
7 changes: 6 additions & 1 deletion src/IRsend.h
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,12 @@ class IRsend {
const uint16_t nbytes, // No default as there as so many
// different sizes
const uint16_t repeat = kHitachiAcDefaultRepeat);
#endif // SEND_HITACHI_AC3
#endif // SEND_HITACHI_AC344
#if SEND_HITACHI_AC344
void sendHitachiAc344(const unsigned char data[],
const uint16_t nbytes = kHitachiAc344StateLength,
const uint16_t repeat = kHitachiAcDefaultRepeat);
#endif // SEND_HITACHI_AC344
#if SEND_HITACHI_AC424
void sendHitachiAc424(const unsigned char data[],
const uint16_t nbytes = kHitachiAc424StateLength,
Expand Down
1 change: 1 addition & 0 deletions src/IRtext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,5 +257,6 @@ const PROGMEM char *kAllProtocolNamesStr =
D_STR_MULTIBRACKETS "\x0"
D_STR_CARRIER_AC40 "\x0"
D_STR_CARRIER_AC64 "\x0"
D_STR_HITACHI_AC344 "\x0"
// New protocol strings should be added just above this line.
"\x0"; // This string requires double null termination.
1 change: 1 addition & 0 deletions src/IRutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ bool hasACState(const decode_type_t protocol) {
case HITACHI_AC1:
case HITACHI_AC2:
case HITACHI_AC3:
case HITACHI_AC344:
case HITACHI_AC424:
case KELVINATOR:
case MITSUBISHI136:
Expand Down
41 changes: 33 additions & 8 deletions src/ir_Hitachi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ using irutils::minsToString;
using irutils::setBit;
using irutils::setBits;

#if (SEND_HITACHI_AC || SEND_HITACHI_AC2)
#if (SEND_HITACHI_AC || SEND_HITACHI_AC2 || SEND_HITACHI_AC344)
// Send a Hitachi A/C message.
//
// Args:
Expand All @@ -77,7 +77,7 @@ void IRsend::sendHitachiAC(const unsigned char data[], const uint16_t nbytes,
kHitachiAcBitMark, kHitachiAcMinGap, data, nbytes, 38, true,
repeat, 50);
}
#endif // (SEND_HITACHI_AC || SEND_HITACHI_AC2)
#endif // (SEND_HITACHI_AC || SEND_HITACHI_AC2 || SEND_HITACHI_AC344)

#if SEND_HITACHI_AC1
// Send a Hitachi A/C 13-byte message.
Expand Down Expand Up @@ -130,6 +130,24 @@ void IRsend::sendHitachiAC2(const unsigned char data[], const uint16_t nbytes,
}
#endif // SEND_HITACHI_AC2

#if SEND_HITACHI_AC344
/// Send a Hitachi A/C 43-byte message.
/// Basically the same as sendHitatchiAC() except different size.
/// For devices:
/// Hitachi A/C Remote: RAS-22NK
/// Status: Beta / Probably works.
/// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1134
/// @param data An array of bytes containing the IR command.
/// @param nbytes Nr. of bytes of data in the array.
/// @param repeat Nr. of times the message is to be repeated. (Default = 0).
void IRsend::sendHitachiAc344(const unsigned char data[], const uint16_t nbytes,
const uint16_t repeat) {
if (nbytes < kHitachiAc344StateLength)
return; // Not enough bytes to send a proper message.
sendHitachiAC(data, nbytes, repeat);
}
#endif // SEND_HITACHI_AC344

// Class for handling the remote control on a Hitachi 28 byte A/C message.
// Inspired by:
// https://github.com/ToniA/arduino-heatpumpir/blob/master/HitachiHeatpumpIR.cpp
Expand Down Expand Up @@ -716,15 +734,17 @@ String IRHitachiAc1::toString(void) {
return result;
}

#if (DECODE_HITACHI_AC || DECODE_HITACHI_AC1 || DECODE_HITACHI_AC2)
#if (DECODE_HITACHI_AC || DECODE_HITACHI_AC1 || DECODE_HITACHI_AC2 || \
DECODE_HITACHI_AC344)
// Decode the supplied Hitachi A/C message.
//
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// offset: The starting index to use when attempting to decode the raw data.
// Typically/Defaults to kStartOffset.
// nbits: The number of data bits to expect.
// Typically kHitachiAcBits, kHitachiAc1Bits, kHitachiAc2Bits
// Typically kHitachiAcBits, kHitachiAc1Bits, kHitachiAc2Bits,
// kHitachiAc344Bits
// strict: Flag indicating if we should perform strict matching.
// Returns:
// boolean: True if it can decode it, false if it can't.
Expand All @@ -746,6 +766,7 @@ bool IRrecv::decodeHitachiAC(decode_results *results, uint16_t offset,
case kHitachiAcBits:
case kHitachiAc1Bits:
case kHitachiAc2Bits:
case kHitachiAc344Bits:
break; // Okay to continue.
default:
return false; // Not strictly a Hitachi message.
Expand Down Expand Up @@ -782,22 +803,26 @@ bool IRrecv::decodeHitachiAC(decode_results *results, uint16_t offset,
// Success
switch (nbits) {
case kHitachiAc1Bits:
results->decode_type = HITACHI_AC1;
results->decode_type = decode_type_t::HITACHI_AC1;
break;
case kHitachiAc2Bits:
results->decode_type = HITACHI_AC2;
results->decode_type = decode_type_t::HITACHI_AC2;
break;
case kHitachiAc344Bits:
results->decode_type = decode_type_t::HITACHI_AC344;
break;
case kHitachiAcBits:
default:
results->decode_type = HITACHI_AC;
results->decode_type = decode_type_t::HITACHI_AC;
}
results->bits = nbits;
// No need to record the state as we stored it as we decoded it.
// As we use result->state, we don't record value, address, or command as it
// is a union data type.
return true;
}
#endif // (DECODE_HITACHI_AC || DECODE_HITACHI_AC1 || DECODE_HITACHI_AC2)
#endif // (DECODE_HITACHI_AC || DECODE_HITACHI_AC1 || DECODE_HITACHI_AC2 ||
// DECODE_HITACHI_AC344)

#if SEND_HITACHI_AC424
// Send HITACHI_AC424 messages
Expand Down
1 change: 1 addition & 0 deletions src/ir_Hitachi.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
// Brand: Hitachi, Model: PC-LH3B (HITACHI_AC3)
// Brand: Hitachi, Model: KAZE-312KSDP A/C (HITACHI_AC1)
// Brand: Hitachi, Model: R-LT0541-HTA/Y.K.1.1-1 V2.3 remote (HITACHI_AC1)
// Brand: Hitachi, Model: RAS-22NK remote (HITACHI_AC344)

#ifndef IR_HITACHI_H_
#define IR_HITACHI_H_
Expand Down
3 changes: 3 additions & 0 deletions src/locale/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,9 @@
#ifndef D_STR_HITACHI_AC3
#define D_STR_HITACHI_AC3 "HITACHI_AC3"
#endif // D_STR_HITACHI_AC3
#ifndef D_STR_HITACHI_AC344
#define D_STR_HITACHI_AC344 "HITACHI_AC344"
#endif // D_STR_HITACHI_AC344
#ifndef D_STR_HITACHI_AC424
#define D_STR_HITACHI_AC424 "HITACHI_AC424"
#endif // D_STR_HITACHI_AC424
Expand Down
120 changes: 120 additions & 0 deletions test/ir_Hitachi_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -811,16 +811,28 @@ TEST(TestUtils, Housekeeping) {
ASSERT_EQ(decode_type_t::HITACHI_AC, strToDecodeType("HITACHI_AC"));
ASSERT_TRUE(hasACState(decode_type_t::HITACHI_AC));
ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::HITACHI_AC));
ASSERT_EQ(kHitachiAcBits,
IRsend::defaultBits(decode_type_t::HITACHI_AC));
ASSERT_EQ(kNoRepeat,
IRsend::minRepeats(decode_type_t::HITACHI_AC));

ASSERT_EQ("HITACHI_AC1", typeToString(decode_type_t::HITACHI_AC1));
ASSERT_EQ(decode_type_t::HITACHI_AC1, strToDecodeType("HITACHI_AC1"));
ASSERT_TRUE(hasACState(decode_type_t::HITACHI_AC1));
ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::HITACHI_AC1));
ASSERT_EQ(kHitachiAc1Bits,
IRsend::defaultBits(decode_type_t::HITACHI_AC1));
ASSERT_EQ(kNoRepeat,
IRsend::minRepeats(decode_type_t::HITACHI_AC1));

ASSERT_EQ("HITACHI_AC2", typeToString(decode_type_t::HITACHI_AC2));
ASSERT_EQ(decode_type_t::HITACHI_AC2, strToDecodeType("HITACHI_AC2"));
ASSERT_TRUE(hasACState(decode_type_t::HITACHI_AC2));
ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::HITACHI_AC2));
ASSERT_EQ(kHitachiAc2Bits,
IRsend::defaultBits(decode_type_t::HITACHI_AC2));
ASSERT_EQ(kNoRepeat,
IRsend::minRepeats(decode_type_t::HITACHI_AC2));

ASSERT_EQ("HITACHI_AC3", typeToString(decode_type_t::HITACHI_AC3));
ASSERT_EQ(decode_type_t::HITACHI_AC3, strToDecodeType("HITACHI_AC3"));
Expand All @@ -831,6 +843,19 @@ TEST(TestUtils, Housekeeping) {
ASSERT_EQ(decode_type_t::HITACHI_AC424, strToDecodeType("HITACHI_AC424"));
ASSERT_TRUE(hasACState(decode_type_t::HITACHI_AC424));
ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::HITACHI_AC424));
ASSERT_EQ(kHitachiAc424Bits,
IRsend::defaultBits(decode_type_t::HITACHI_AC424));
ASSERT_EQ(kNoRepeat,
IRsend::minRepeats(decode_type_t::HITACHI_AC424));

ASSERT_EQ("HITACHI_AC344", typeToString(decode_type_t::HITACHI_AC344));
ASSERT_EQ(decode_type_t::HITACHI_AC344, strToDecodeType("HITACHI_AC344"));
ASSERT_TRUE(hasACState(decode_type_t::HITACHI_AC344));
ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::HITACHI_AC344));
ASSERT_EQ(kHitachiAc344Bits,
IRsend::defaultBits(decode_type_t::HITACHI_AC344));
ASSERT_EQ(kNoRepeat,
IRsend::minRepeats(decode_type_t::HITACHI_AC344));
}

// Decode a 'real' HitachiAc424 message.
Expand Down Expand Up @@ -1801,3 +1826,98 @@ TEST(TestIRHitachiAc1Class, FanSpeedInDryMode) {
"On Timer: Off, Off Timer: Off",
ac.toString());
}

// Decode a 'real' HitachiAc344 message.
TEST(TestDecodeHitachiAc344, RealExample) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();

uint8_t expected[kHitachiAc344StateLength] = {
0x80, 0x08, 0x00, 0x02, 0xFD, 0xFF, 0x00, 0x33, 0xCC, 0x19, 0xE6, 0xC8,
0x37, 0x16, 0xE9, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
0xFF, 0xC8, 0x37, 0x8F, 0x70, 0x00, 0xFF, 0x00, 0xFF, 0x01, 0xFE, 0xC0,
0x3F, 0x04, 0xFB, 0x00, 0xFF, 0x00, 0xFF};

// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1134#issue-622516158
const uint16_t rawData[691] = {3410, 1624, 482, 1226, 458, 464, 458, 462, 456,
464, 460, 460, 462, 460, 460, 462, 460, 460, 460, 462, 460, 462, 456, 466,
458, 462, 456, 1228, 462, 460, 460, 462, 460, 462, 458, 462, 456, 466,
456, 464, 458, 464, 456, 466, 460, 460, 460, 462, 460, 460, 458, 464, 456,
464, 458, 464, 456, 464, 460, 462, 454, 466, 458, 1226, 460, 462, 456,
1226, 456, 1230, 456, 1228, 456, 1230, 458, 1228, 456, 1228, 456, 464,
456, 1230, 454, 1230, 458, 1228, 458, 1226, 454, 1230, 454, 1230, 454,
1230, 458, 1228, 458, 1230, 452, 468, 456, 464, 454, 468, 456, 464, 418,
502, 456, 466, 458, 464, 458, 462, 458, 464, 454, 468, 456, 1230, 454,
1230, 454, 466, 456, 464, 456, 1228, 456, 1230, 456, 1230, 456, 1230, 456,
464, 458, 464, 458, 1228, 456, 1230, 456, 464, 454, 466, 456, 466, 456,
464, 458, 462, 458, 1228, 458, 1228, 458, 464, 454, 468, 456, 1228, 458,
1228, 458, 1228, 456, 1228, 456, 464, 454, 468, 456, 1228, 458, 1226, 458,
464, 458, 1226, 456, 1230, 454, 468, 458, 462, 452, 1232, 460, 462, 458,
460, 460, 462, 456, 466, 458, 462, 456, 1230, 456, 1228, 460, 462, 460,
1226, 458, 1228, 458, 1226, 460, 460, 456, 468, 458, 464, 456, 1226, 460,
462, 458, 1228, 456, 1228, 458, 462, 462, 1224, 460, 1226, 458, 1226, 460,
464, 458, 1228, 456, 462, 460, 462, 460, 1226, 460, 460, 462, 460, 458,
462, 458, 462, 456, 464, 460, 460, 462, 460, 462, 460, 460, 1224, 462,
1224, 462, 1224, 458, 1226, 462, 1224, 460, 1224, 400, 1284, 446, 1240,
446, 476, 458, 462, 464, 458, 462, 460, 460, 460, 458, 462, 462, 462, 456,
464, 460, 1226, 460, 1226, 460, 1224, 462, 1224, 460, 1224, 460, 1224,
460, 1224, 462, 1224, 462, 460, 460, 462, 460, 460, 458, 464, 458, 462,
458, 464, 458, 462, 460, 460, 462, 1224, 460, 1226, 458, 1228, 456, 1226,
462, 1222, 460, 1228, 458, 1226, 460, 1226, 460, 460, 458, 462, 460, 462,
460, 460, 460, 462, 460, 462, 458, 464, 460, 458, 460, 1226, 456, 1228,
462, 1224, 460, 1224, 458, 1228, 458, 1226, 458, 1228, 462, 1224, 460,
462, 460, 462, 458, 464, 460, 460, 456, 466, 458, 462, 460, 460, 462,
458, 460, 1224, 460, 1224, 458, 1226, 460, 1224, 460, 1226, 460, 1226,
458, 1228, 456, 1230, 456, 1228, 462, 1224, 460, 460, 458, 462, 458,
1228, 456, 466, 458, 462, 454, 468, 458, 462, 458, 462, 460, 1226, 456,
1228, 458, 464, 420, 1264, 458, 1228, 458, 1228, 456, 1228, 454, 468, 456,
464, 456, 466, 456, 1228, 460, 1226, 456, 1230, 456, 1228, 456, 464, 456,
1230, 458, 1226, 458, 1226, 452, 468, 456, 466, 376, 546, 456, 466, 456,
464, 456, 466, 458, 464, 458, 464, 456, 466, 424, 496, 456, 464, 416, 504,
454, 1230, 454, 1232, 456, 1228, 456, 1228, 456, 1230, 456, 1230, 454,
1230, 460, 1226, 426, 496, 424, 496, 456, 466, 374, 546, 454, 468, 374,
544, 458, 464, 456, 464, 458, 1228, 424, 1262, 454, 1232, 426, 1258, 458,
1228, 426, 1260, 454, 1230, 456, 1228, 426, 496, 374, 546, 426, 494, 426,
496, 424, 496, 426, 496, 424, 496, 456, 1230, 456, 1230, 456, 1228, 458,
1228, 456, 1230, 456, 1230, 456, 1230, 424, 1260, 458, 464, 426, 1258,
456, 1230, 422, 500, 456, 466, 418, 504, 424, 496, 426, 496, 456, 464,
420, 500, 454, 468, 456, 1230, 424, 1260, 420, 1264, 422, 1264, 418,
1266, 420, 1264, 420, 500, 456, 466, 426, 494, 454, 468, 456, 464, 420,
1266, 452, 470, 454, 466, 374, 1310, 456, 1228, 456, 1230, 452, 1232, 420,
1266, 424, 498, 456, 1230, 456, 1230, 456, 466, 450, 470, 456, 464, 376,
546, 456, 466, 422, 498, 426, 496, 458, 464, 424, 1260, 454, 1232, 454,
1232, 454, 1232, 458, 1228, 422, 1262, 456, 1228, 454, 1230, 456, 468,
416, 504, 422, 498, 424, 498, 454, 466, 456, 466, 422, 500, 456, 466, 374,
1310, 418, 1266, 424, 1262, 422, 1262, 376, 1310, 376, 1308, 422, 1264,
424, 1262, 350}; // UNKNOWN 919B8582

irsend.reset();
irsend.sendRaw(rawData, 691, kHitachiAcFreq);
irsend.makeDecodeResult();
EXPECT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(HITACHI_AC344, irsend.capture.decode_type);
ASSERT_EQ(kHitachiAc344Bits, irsend.capture.bits);
EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
}

// Decode a synthetic HitachiAc344 message.
TEST(TestDecodeHitachiAc344, SyntheticExample) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();

uint8_t expected[kHitachiAc344StateLength] = {
0x80, 0x08, 0x00, 0x02, 0xFD, 0xFF, 0x00, 0x33, 0xCC, 0x19, 0xE6, 0xC8,
0x37, 0x16, 0xE9, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
0xFF, 0xC8, 0x37, 0x8F, 0x70, 0x00, 0xFF, 0x00, 0xFF, 0x01, 0xFE, 0xC0,
0x3F, 0x04, 0xFB, 0x00, 0xFF, 0x00, 0xFF};

irsend.reset();
irsend.sendHitachiAc344(expected);
irsend.makeDecodeResult();
EXPECT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(HITACHI_AC344, irsend.capture.decode_type);
ASSERT_EQ(kHitachiAc344Bits, irsend.capture.bits);
EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
}

0 comments on commit 7246401

Please sign in to comment.