From d9ae0f8b1ddb28ad4995caf89874cab71d1ea5f2 Mon Sep 17 00:00:00 2001 From: heXor Date: Sat, 2 Sep 2017 03:10:20 +0300 Subject: [PATCH 01/11] bug fix: memory leak update - use Lazarus 1.6 and Synapse40 (folder 'synapse' not need) --- TMQTTClient/MQTT.pas | 4 ++-- TMQTTClient/MQTTReadThread.pas | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/TMQTTClient/MQTT.pas b/TMQTTClient/MQTT.pas index 01f98a7..b3efe5c 100644 --- a/TMQTTClient/MQTT.pas +++ b/TMQTTClient/MQTT.pas @@ -270,7 +270,7 @@ TMQTTClient = class(TObject) FReadThread.waitFor; FSocket.CloseSocket; FisConnected := False; - FSocket := nil; + FreeAndNil(FSocket); end else Result := False; end; @@ -293,7 +293,7 @@ TMQTTClient = class(TObject) if FSocket <> nil then begin FSocket.CloseSocket; - FSocket := nil; + FreeAndNil(FSocket); end; FisConnected := False; end; diff --git a/TMQTTClient/MQTTReadThread.pas b/TMQTTClient/MQTTReadThread.pas index 4bf4821..dd6e323 100644 --- a/TMQTTClient/MQTTReadThread.pas +++ b/TMQTTClient/MQTTReadThread.pas @@ -34,7 +34,7 @@ interface uses -SysUtils, Classes, blcksock, BaseUnix; + SysUtils, Classes, blcksock, synsock; type TBytes = array of Byte; @@ -191,7 +191,7 @@ TMQTTReadThread = class(TThread) CurrentMessage.Data := nil; CurrentMessage.FixedHeader := FPSocket^.RecvByte(1000); - if (FPSocket^.LastError = ESysETIMEDOUT) then continue; + if (FPSocket^.LastError = WSAETIMEDOUT) then continue; if (FPSocket^.LastError <> 0) then rxState := RX_ERROR else @@ -200,7 +200,7 @@ TMQTTReadThread = class(TThread) RX_LENGTH: begin digit := FPSocket^.RecvByte(1000); - if (FPSocket^.LastError = ESysETIMEDOUT) then continue; + if (FPSocket^.LastError = WSAETIMEDOUT) then continue; if (FPSocket^.LastError <> 0) then rxState := RX_ERROR else From 6fa69e11d8f48bcde59abc0db0fd3b445fb10a43 Mon Sep 17 00:00:00 2001 From: heXor Date: Thu, 7 Sep 2017 03:31:09 +0300 Subject: [PATCH 02/11] bug fix: mem leak bug fix: potential infinity loop --- TMQTTClient/MQTT.pas | 6 ++++++ TMQTTClient/MQTTReadThread.pas | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/TMQTTClient/MQTT.pas b/TMQTTClient/MQTT.pas index b3efe5c..9cc34e9 100644 --- a/TMQTTClient/MQTT.pas +++ b/TMQTTClient/MQTT.pas @@ -492,6 +492,12 @@ TMQTTClient = class(TObject) destructor TMQTTClient.Destroy; begin + if isConnected then + begin + FReadThread.Terminate; + FReadThread.WaitFor; + //ForceDisconnect; + end; FSocket.free; FMessageQueue.free; FMessageAckQueue.free; diff --git a/TMQTTClient/MQTTReadThread.pas b/TMQTTClient/MQTTReadThread.pas index dd6e323..ce5a65d 100644 --- a/TMQTTClient/MQTTReadThread.pas +++ b/TMQTTClient/MQTTReadThread.pas @@ -161,7 +161,7 @@ TMQTTReadThread = class(TThread) //sleep(1); // Send CONNECT message - while true do + while not self.Terminated do begin writeln('loop...'); SocketWrite(Data); From c8e6b3515b0004aa7542dbecd63a919f0b54cba7 Mon Sep 17 00:00:00 2001 From: heXor Date: Mon, 11 Sep 2017 12:12:35 +0300 Subject: [PATCH 03/11] bug fix: AV --- TMQTTClient/MQTT.pas | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/TMQTTClient/MQTT.pas b/TMQTTClient/MQTT.pas index 9cc34e9..c3f0e81 100644 --- a/TMQTTClient/MQTT.pas +++ b/TMQTTClient/MQTT.pas @@ -492,13 +492,14 @@ TMQTTClient = class(TObject) destructor TMQTTClient.Destroy; begin - if isConnected then + if (isConnected) and (FReadThread <> nil) then begin FReadThread.Terminate; FReadThread.WaitFor; - //ForceDisconnect; + //note: free is not needed - the FreeOnTerminate mode is enabled end; - FSocket.free; + if FSocket <> nil then + FreeAndNil(FSocket); FMessageQueue.free; FMessageAckQueue.free; DoneCriticalSection(FCritical); From 3e9ad7e3556bdd6667b910aee2f2b2c555b6d2a9 Mon Sep 17 00:00:00 2001 From: heXor Date: Tue, 12 Sep 2017 13:53:54 +0300 Subject: [PATCH 04/11] bug fix: Hang on call "Dissconect" (one hangup for ~50-100 disconnects). bug fix: AV then thread terminating but socket already free in TMQTTClient. change Socket owner - move from TMQTTClient to TMQTTReadThread. remove strange "PTCPBlockSocket = ^TTCPBlockSocket" (the class is already pointer) change "SocketWrite" - remove duplicate code in TMQTTClient. TMQTTReadThread.Execute add "try-finally". TMQTTClient.OnRTTerminate add "FReadThread := nil" and "FisConnected := false". --- TMQTTClient/MQTT.pas | 66 ++++++++++++++++------------------ TMQTTClient/MQTTReadThread.pas | 55 +++++++++++++++------------- 2 files changed, 62 insertions(+), 59 deletions(-) diff --git a/TMQTTClient/MQTT.pas b/TMQTTClient/MQTT.pas index c3f0e81..0ecc8a6 100644 --- a/TMQTTClient/MQTT.pas +++ b/TMQTTClient/MQTT.pas @@ -103,7 +103,6 @@ TMQTTClient = class(TObject) FHostname : ansistring; FPort : Integer; FReadThread : TMQTTReadThread; - FSocket : TTCPBlockSocket; FMessageID : integer; FisConnected : boolean; FReaderThreadRunning: boolean; @@ -223,24 +222,21 @@ TMQTTClient = class(TObject) begin if FReaderThreadRunning = false then begin - if FSocket = nil then - begin - - // Create a socket. - FSocket := TTCPBlockSocket.Create; - FSocket.nonBlockMode := true; // We really don't want sending on - FSocket.NonblockSendTimeout := 1; // the socket to block our main thread. - // Create and start RX thread - FReadThread := TMQTTReadThread.Create(@FSocket, FHostname, FPort); - FReadThread.OnConnAck := @OnRTConnAck; - FReadThread.OnPublish := @OnRTPublish; - FReadThread.OnPublish := @OnRTPublish; - FReadThread.OnPingResp := @OnRTPingResp; - FReadThread.OnSubAck := @OnRTSubAck; - FReadThread.OnTerminate := @OnRTTerminate; - FReadThread.Start; - FReaderThreadRunning := true; - end; + // Create and start RX thread + if FReadThread <> nil then + begin + FReadThread.OnTerminate := nil; + FreeAndNil(FReadThread); + end; + FReadThread := TMQTTReadThread.Create(FHostname, FPort); + FReadThread.OnConnAck := @OnRTConnAck; + FReadThread.OnPublish := @OnRTPublish; + FReadThread.OnPublish := @OnRTPublish; + FReadThread.OnPingResp := @OnRTPingResp; + FReadThread.OnSubAck := @OnRTSubAck; + FReadThread.OnTerminate := @OnRTTerminate; + FReadThread.Start; + FReaderThreadRunning := true; end; end; @@ -266,11 +262,17 @@ TMQTTClient = class(TObject) Data[1] := 0; if SocketWrite(Data) then begin - Result := True; - FReadThread.waitFor; - FSocket.CloseSocket; FisConnected := False; - FreeAndNil(FSocket); + if FReadThread <> nil then + begin + //todo: collect all terminate code (connect, Disconnect, ForceDisconnect) to one point + FReadThread.OnTerminate := nil; + FReadThread.Terminate; + FReadThread := nil; + //todo: the probability of a hang? + //FReadThread.waitFor; + end; + Result := True; end else Result := False; end; @@ -287,14 +289,10 @@ TMQTTClient = class(TObject) writeln('TMQTTClient.ForceDisconnect'); if FReadThread <> nil then begin + FReadThread.OnTerminate := nil; FReadThread.Terminate; FReadThread := nil; end; - if FSocket <> nil then - begin - FSocket.CloseSocket; - FreeAndNil(FSocket); - end; FisConnected := False; end; @@ -306,7 +304,11 @@ TMQTTClient = class(TObject) ------------------------------------------------------------------------------*} procedure TMQTTClient.OnRTTerminate(Sender: TObject); begin + //todo: on terminating - need disable this object + FReadThread := nil; FReaderThreadRunning := false; + FisConnected := false; + WriteLn('TMQTTClient.OnRTTerminate: Thread.Terminated.'); end; @@ -498,8 +500,6 @@ TMQTTClient = class(TObject) FReadThread.WaitFor; //note: free is not needed - the FreeOnTerminate mode is enabled end; - if FSocket <> nil then - FreeAndNil(FSocket); FMessageQueue.free; FMessageAckQueue.free; DoneCriticalSection(FCritical); @@ -539,11 +539,7 @@ TMQTTClient = class(TObject) Result := False; // Returns whether the Data was successfully written to the socket. if isConnected then - begin - sentData := FSocket.SendBuffer(Pointer(Data), Length(Data)); - if sentData = Length(Data) then Result := True - else Result := False; - end; + Result := FReadThread.SocketWrite(Data); end; function StrToBytes(str: ansistring; perpendLength: boolean): TUTF8Text; diff --git a/TMQTTClient/MQTTReadThread.pas b/TMQTTClient/MQTTReadThread.pas index ce5a65d..6a5ea3d 100644 --- a/TMQTTClient/MQTTReadThread.pas +++ b/TMQTTClient/MQTTReadThread.pas @@ -48,8 +48,6 @@ TMQTTMessage = record type TRxStates = (RX_START, RX_FIXED_HEADER, RX_LENGTH, RX_DATA, RX_ERROR); - PTCPBlockSocket = ^TTCPBlockSocket; - TRemainingLength = Array of Byte; TUTF8Text = Array of Byte; @@ -65,7 +63,6 @@ TMQTTReadThread = class(TThread) FClientID: ansistring; FHostname: ansistring; FPort: integer; - FPSocket: PTCPBlockSocket; CurrentMessage: TMQTTMessage; // Events FConnAckEvent: TConnAckEvent; @@ -83,13 +80,16 @@ TMQTTReadThread = class(TThread) // This is our data processing and event firing command. procedure HandleData; - function SocketWrite(Data: TBytes): boolean; protected procedure Execute; override; - public - constructor Create(Socket: PTCPBlockSocket; Hostname: ansistring; Port: integer); + public + //todo: change Socket resurse working + FPSocket: TTCPBlockSocket; + function SocketWrite(Data: TBytes): boolean; + + constructor Create(Hostname: ansistring; Port: integer); property OnConnAck : TConnAckEvent read FConnAckEvent write FConnAckEvent; property OnPublish : TPublishEvent read FPublishEvent write FPublishEvent; property OnPingResp : TPingRespEvent read FPingRespEvent write FPingRespEvent; @@ -105,7 +105,7 @@ TMQTTReadThread = class(TThread) { TMQTTReadThread } - constructor TMQTTReadThread.Create(Socket: PTCPBlockSocket; HostName: ansistring; Port: integer) + constructor TMQTTReadThread.Create(HostName: ansistring; Port: integer) ; begin inherited Create(true); @@ -115,7 +115,6 @@ TMQTTReadThread = class(TThread) // Create a Default ClientID as a default. Can be overridden with TMQTTClient.ClientID any time before connection. FClientID := 'dMQTTClientx' + IntToStr(Random(1000) + 1); - FPSocket := Socket; FHostname := Hostname; FPort := Port; FreeOnTerminate := true; @@ -136,14 +135,18 @@ TMQTTReadThread = class(TThread) error: integer; begin rxState := RX_START; - + try + // Create a socket. + FPSocket := TTCPBlockSocket.Create; + FPSocket.nonBlockMode := true; // We really don't want sending on + FPSocket.NonblockSendTimeout := 1; // the socket to block our main thread. while not self.Terminated do begin case rxState of RX_START: begin // Make the socket connection - FPSocket^.Connect(FHostname, IntToStr(FPort)); + FPSocket.Connect(FHostname, IntToStr(FPort)); // Build CONNECT message FH := FixedHeader(MQTT.CONNECT, 0, 0, 0); @@ -155,8 +158,8 @@ TMQTTReadThread = class(TThread) RL := RemainingLength(Length(VH) + Length(Payload)); Data := BuildCommand(FH, RL, VH, Payload); - writeln('RX_START: ', FPSocket^.LastErrorDesc); - writeln('RX_START: ', FPSocket^.LastError); + writeln('RX_START: ', FPSocket.LastErrorDesc); + writeln('RX_START: ', FPSocket.LastError); //sleep(1); @@ -165,8 +168,8 @@ TMQTTReadThread = class(TThread) begin writeln('loop...'); SocketWrite(Data); - error := FPSocket^.LastError; - writeln('RX_START: ', FPSocket^.LastErrorDesc); + error := FPSocket.LastError; + writeln('RX_START: ', FPSocket.LastErrorDesc); writeln('RX_START: ', error); if error = 0 then begin @@ -190,18 +193,18 @@ TMQTTReadThread = class(TThread) remainingLengthx := 0; CurrentMessage.Data := nil; - CurrentMessage.FixedHeader := FPSocket^.RecvByte(1000); - if (FPSocket^.LastError = WSAETIMEDOUT) then continue; - if (FPSocket^.LastError <> 0) then + CurrentMessage.FixedHeader := FPSocket.RecvByte(1000); + if (FPSocket.LastError = WSAETIMEDOUT) then continue; + if (FPSocket.LastError <> 0) then rxState := RX_ERROR else rxState := RX_LENGTH; end; RX_LENGTH: begin - digit := FPSocket^.RecvByte(1000); - if (FPSocket^.LastError = WSAETIMEDOUT) then continue; - if (FPSocket^.LastError <> 0) then + digit := FPSocket.RecvByte(1000); + if (FPSocket.LastError = WSAETIMEDOUT) then continue; + if (FPSocket.LastError <> 0) then rxState := RX_ERROR else begin @@ -218,8 +221,8 @@ TMQTTReadThread = class(TThread) RX_DATA: begin SetLength(CurrentMessage.Data, remainingLengthx); - FPSocket^.RecvBufferEx(Pointer(CurrentMessage.Data), remainingLengthx, 1000); - if (FPSocket^.LastError <> 0) then + FPSocket.RecvBufferEx(Pointer(CurrentMessage.Data), remainingLengthx, 1000); + if (FPSocket.LastError <> 0) then rxState := RX_ERROR else begin @@ -234,6 +237,10 @@ TMQTTReadThread = class(TThread) end; end; end; + finally + FPSocket.CloseSocket(); + FreeAndNil(FPSocket); + end; // try end; procedure TMQTTReadThread.HandleData; @@ -326,12 +333,12 @@ TMQTTReadThread = class(TThread) Result := False; // Returns whether the Data was successfully written to the socket. - while not FPSocket^.CanWrite(0) do + while not FPSocket.CanWrite(0) do begin sleep(100); end; - sentData := FPSocket^.SendBuffer(Pointer(Data), Length(Data)); + sentData := FPSocket.SendBuffer(Pointer(Data), Length(Data)); if sentData = Length(Data) then Result := True end; From f5ddc0cf0d6617703f8fa42aa269227c7200a593 Mon Sep 17 00:00:00 2001 From: heXor Date: Tue, 12 Sep 2017 23:44:51 +0300 Subject: [PATCH 05/11] new feature: support "retain" flag in TPublishEvent (OnPublish). "function FixedHeader" - remove mathematics, add boolean function. --- TMQTTClient/MQTT.pas | 21 +++++++++++---------- TMQTTClient/MQTTReadThread.pas | 16 ++++++++++++++-- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/TMQTTClient/MQTT.pas b/TMQTTClient/MQTT.pas index 0ecc8a6..9a63cb8 100644 --- a/TMQTTClient/MQTT.pas +++ b/TMQTTClient/MQTT.pas @@ -45,6 +45,7 @@ interface Reserved0, // 0 Reserved CONNECT, // 1 Client request to connect to Broker CONNACK, // 2 Connect Acknowledgment + // PUBLISH Control Packet is sent from a Client to a Server or from Server to a Client to transport an Application Message. PUBLISH, // 3 Publish message PUBACK, // 4 Publish Acknowledgment PUBREC, // 5 Publish Received (assured delivery part 1) @@ -131,7 +132,7 @@ TMQTTClient = class(TObject) procedure OnRTPingResp(Sender: TObject); procedure OnRTSubAck(Sender: TObject; MessageID: integer; GrantedQoS: integer); procedure OnRTUnSubAck(Sender: TObject; MessageID: integer); - procedure OnRTPublish(Sender: TObject; topic, payload: ansistring); + procedure OnRTPublish(Sender: TObject; topic, payload: ansistring; retain: boolean); procedure OnRTTerminate (Sender: TObject); @@ -163,9 +164,7 @@ TMQTTClient = class(TObject) end; // Message Component Build helpers - function FixedHeader(MessageType: TMQTTMessageType; Dup: Word; Qos: Word; Retain: Word): - Byte - ; + function FixedHeader(MessageType: TMQTTMessageType; Dup, Qos, Retain: byte): Byte; // Variable Header per command creation funcs function VariableHeaderConnect(KeepAlive: Word): TBytes; @@ -507,13 +506,15 @@ TMQTTClient = class(TObject) end; function FixedHeader(MessageType: TMQTTMessageType; Dup, Qos, - Retain: Word): Byte; + Retain: byte): Byte; begin { Fixed Header Spec: - bit |7 6 5 4 | |3 | |2 1 | | 0 | - byte 1 |Message Type| |DUP flag| |QoS level| |RETAIN| } - Result := (Ord(MessageType) * 16) + (Dup * 8) + (Qos * 2) + (Retain * 1); + byte 1 bits |7 6 5 4 | 3 | 2 1 | 0 | + fields |Message Type| DUP flag | QoS level| RETAIN| +} + Result := Byte(Ord(MessageType) shl 4) or (Dup shl 3) or (Qos shl 1) or (Retain shl 0); + //todo: OLD code: Result := (Ord(MessageType) * 16) + (Dup * 8) + (Qos * 2) + (Retain * 1); end; function TMQTTClient.GetMessageID: TBytes; @@ -731,11 +732,11 @@ TMQTTClient = class(TObject) end; end; - procedure TMQTTClient.OnRTPublish(Sender: TObject; topic, payload: ansistring); + procedure TMQTTClient.OnRTPublish(Sender: TObject; topic, payload: ansistring; retain: boolean); begin if Assigned(OnPublish) then begin - OnPublish(Self, topic, payload); + OnPublish(Self, topic, payload, retain); end else begin diff --git a/TMQTTClient/MQTTReadThread.pas b/TMQTTClient/MQTTReadThread.pas index 6a5ea3d..2e02e1c 100644 --- a/TMQTTClient/MQTTReadThread.pas +++ b/TMQTTClient/MQTTReadThread.pas @@ -53,7 +53,7 @@ TMQTTMessage = record TUTF8Text = Array of Byte; TConnAckEvent = procedure (Sender: TObject; ReturnCode: integer) of object; - TPublishEvent = procedure (Sender: TObject; topic, payload: ansistring) of object; + TPublishEvent = procedure (Sender: TObject; topic, payload: ansistring; retain: boolean) of object; TPingRespEvent = procedure (Sender: TObject) of object; TSubAckEvent = procedure (Sender: TObject; MessageID: integer; GrantedQoS: integer) of object; TUnSubAckEvent = procedure (Sender: TObject; MessageID: integer) of object; @@ -103,6 +103,16 @@ TMQTTReadThread = class(TThread) uses MQTT; + procedure SetBit(var Value: byte; const Index: Byte; const State: Boolean); inline; + begin + Value := (Value and ((byte(1) shl Index) xor High(byte))) or (byte(State) shl Index); + end; + + function GetBit(const Value: byte; const Index: Byte): Boolean; inline; + begin + Result := ((Value shr Index) and 1) = 1; + end; + { TMQTTReadThread } constructor TMQTTReadThread.Create(HostName: ansistring; Port: integer) @@ -249,6 +259,7 @@ TMQTTReadThread = class(TThread) MessageType: Byte; DataLen: integer; QoS: integer; + Retain: boolean; Topic: ansistring; Payload: ansistring; ResponseVH: TBytes; @@ -271,6 +282,7 @@ TMQTTReadThread = class(TThread) else if (MessageType = Ord(MQTT.PUBLISH)) then begin + Retain := GetBit(CurrentMessage.FixedHeader, 0); // Read the Length Bytes DataLen := BytesToStrLength(Copy(CurrentMessage.Data, 0, 2)); // Get the Topic @@ -278,7 +290,7 @@ TMQTTReadThread = class(TThread) // Get the Payload SetString(Payload, PChar(@CurrentMessage.Data[2 + DataLen]), (Length(CurrentMessage.Data) - 2 - DataLen)); - if Assigned(OnPublish) then OnPublish(Self, Topic, Payload); + if Assigned(OnPublish) then OnPublish(Self, Topic, Payload, retain); end else if (MessageType = Ord(MQTT.SUBACK)) then From cdf685b8509ef141c54b097dd39c010977333574 Mon Sep 17 00:00:00 2001 From: heXor Date: Thu, 14 Sep 2017 00:59:05 +0300 Subject: [PATCH 06/11] add to MQTTMessage and MessageQueue retain flag --- TMQTTClient/MQTT.pas | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/TMQTTClient/MQTT.pas b/TMQTTClient/MQTT.pas index 9a63cb8..66f829a 100644 --- a/TMQTTClient/MQTT.pas +++ b/TMQTTClient/MQTT.pas @@ -62,16 +62,21 @@ interface ); // The message class definition + + { TMQTTMessage } + TMQTTMessage = class private FTopic : ansistring; FPayload : ansistring; + FRetain : boolean; public property Topic : ansistring read FTopic; property PayLoad : ansistring read FPayload; + property Retain : boolean read FRetain; - constructor Create(const topic_ : ansistring; const payload_ : ansistring); + constructor Create(const topic_ : ansistring; const payload_ : ansistring; const retain_: boolean); end; // The acknowledgement class definition @@ -193,11 +198,13 @@ TMQTTClient = class(TObject) implementation - constructor TMQTTMessage.Create(const Topic_ : ansistring; const Payload_ : ansistring); + constructor TMQTTMessage.Create(const topic_: ansistring; + const payload_: ansistring; const retain_: boolean); begin // Save the passed parameters FTopic := Topic_; FPayload := Payload_; + FRetain := retain_; end; constructor TMQTTMessageAck.Create(const messageType_ : TMQTTMessageType; @@ -743,7 +750,7 @@ TMQTTClient = class(TObject) // Protected code. EnterCriticalSection (FCritical); try - FMessageQueue.Push (TMQTTMessage.Create(topic, payload)); + FMessageQueue.Push (TMQTTMessage.Create(topic, payload, retain)); finally LeaveCriticalSection (FCritical); end; From 460772692fa73629c6792e461d65a858ccbcc742 Mon Sep 17 00:00:00 2001 From: heXor Date: Sat, 16 Sep 2017 19:59:31 +0300 Subject: [PATCH 07/11] add 'todo' --- TMQTTClient/MQTT.pas | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/TMQTTClient/MQTT.pas b/TMQTTClient/MQTT.pas index 66f829a..9cdedb6 100644 --- a/TMQTTClient/MQTT.pas +++ b/TMQTTClient/MQTT.pas @@ -599,12 +599,22 @@ TMQTTClient = class(TObject) function VariableHeaderConnect(KeepAlive: Word): TBytes; - const + const + //todo: version update! MQIsdp->MQTT. version 4! MQTT_PROTOCOL = 'MQIsdp'; MQTT_VERSION = 3; var Qos, Retain: word; +{todo: connect flags +7 User Name Flag +6 Password Flag +5 Will Retain +4 Will QoS +3 Will QoS +2 Will Flag +1 Clean Session +0 Reserved } iByteIndex: integer; ProtoBytes: TUTF8Text; begin From 91a1c98d3c05ae7f7b41cad9b7c00e516c9bf02b Mon Sep 17 00:00:00 2001 From: heXor Date: Sun, 17 Sep 2017 03:01:23 +0300 Subject: [PATCH 08/11] JEDI Code Formating (lazarus feature) (see: https://github.com/ZiCog/mqtt-free-pascal/issues/5 ) --- TMQTTClient/MQTT.pas | 1322 +++++++++++++++----------------- TMQTTClient/MQTTReadThread.pas | 574 +++++++------- 2 files changed, 919 insertions(+), 977 deletions(-) diff --git a/TMQTTClient/MQTT.pas b/TMQTTClient/MQTT.pas index 9cdedb6..28b66e2 100644 --- a/TMQTTClient/MQTT.pas +++ b/TMQTTClient/MQTT.pas @@ -35,317 +35,286 @@ interface -uses -SysUtils, blcksock, contnrs, MQTTReadThread; - -type +uses + SysUtils, blcksock, contnrs, MQTTReadThread; +type // Message type. 4 Bit unsigned. TMQTTMessageType = ( - Reserved0, // 0 Reserved - CONNECT, // 1 Client request to connect to Broker - CONNACK, // 2 Connect Acknowledgment - // PUBLISH Control Packet is sent from a Client to a Server or from Server to a Client to transport an Application Message. - PUBLISH, // 3 Publish message - PUBACK, // 4 Publish Acknowledgment - PUBREC, // 5 Publish Received (assured delivery part 1) - PUBREL, // 6 Publish Release (assured delivery part 2) - PUBCOMP, // 7 Publish Complete (assured delivery part 3) - SUBSCRIBE, // 8 Client Subscribe request - SUBACK, // 9 Subscribe Acknowledgment - UNSUBSCRIBE, // 10 Client Unsubscribe request - UNSUBACK, // 11 Unsubscribe Acknowledgment - PINGREQ, // 12 PING Request - PINGRESP, // 13 PING Response - DISCONNECT, // 14 Client is Disconnecting - Reserved15 // 15 Reserved - ); + Reserved0, // 0 Reserved + CONNECT, // 1 Client request to connect to Broker + CONNACK, // 2 Connect Acknowledgment + // PUBLISH Control Packet is sent from a Client to a Server or from Server to a Client to transport an Application Message. + PUBLISH, // 3 Publish message + PUBACK, // 4 Publish Acknowledgment + PUBREC, // 5 Publish Received (assured delivery part 1) + PUBREL, // 6 Publish Release (assured delivery part 2) + PUBCOMP, // 7 Publish Complete (assured delivery part 3) + SUBSCRIBE, // 8 Client Subscribe request + SUBACK, // 9 Subscribe Acknowledgment + UNSUBSCRIBE, // 10 Client Unsubscribe request + UNSUBACK, // 11 Unsubscribe Acknowledgment + PINGREQ, // 12 PING Request + PINGRESP, // 13 PING Response + DISCONNECT, // 14 Client is Disconnecting + Reserved15 // 15 Reserved + ); // The message class definition - - { TMQTTMessage } - TMQTTMessage = class - private - FTopic : ansistring; - FPayload : ansistring; - FRetain : boolean; - - public - property Topic : ansistring read FTopic; - property PayLoad : ansistring read FPayload; - property Retain : boolean read FRetain; - - constructor Create(const topic_ : ansistring; const payload_ : ansistring; const retain_: boolean); - end; - - // The acknowledgement class definition - TMQTTMessageAck = class - private - FMessageType : TMQTTMessageType; - FMessageId : integer; - FReturnCode : integer; - FQos : integer; - public - property messageType : TMQTTMessageType read FMessageType; - property messageId : integer read FMessageId; - property returnCode : integer read FReturnCode; - property qos : integer read FQos; - - constructor Create(const messageType_ : TMQTTMessageType; - const messageId_ : integer; - const returnCode_ : integer; - const qos_ : integer); - end; - - TRemainingLength = Array of Byte; - TUTF8Text = Array of Byte; - - PMQTTClient = ^TMQTTClient; - - TMQTTClient = class(TObject) - private - FClientID : ansistring; - FHostname : ansistring; - FPort : Integer; - FReadThread : TMQTTReadThread; - FMessageID : integer; - FisConnected : boolean; - FReaderThreadRunning: boolean; - - FConnAckEvent : TConnAckEvent; - FPublishEvent : TPublishEvent; - FPingRespEvent : TPingRespEvent; - FSubAckEvent : TSubAckEvent; - FUnSubAckEvent : TUnSubAckEvent; - - FCritical : TRTLCriticalSection; - FMessageQueue : TQueue; - FMessageAckQueue : TQueue; - - // Gets a next Message ID and increases the Message ID Increment - function GetMessageID: TBytes; - function VariableHeaderPublish(topic: ansistring): TBytes; - function VariableHeaderSubscribe: TBytes; - function VariableHeaderUnsubscribe: TBytes; - // Internally Write the provided data to the Socket. Wrapper function. - function SocketWrite(Data: TBytes): boolean; - - // These are chained event handlers from the ReceiveThread. They trigger the - // public TMQTTClient.On*** handlers. - procedure OnRTConnAck(Sender: TObject; ReturnCode: integer); - procedure OnRTPingResp(Sender: TObject); - procedure OnRTSubAck(Sender: TObject; MessageID: integer; GrantedQoS: integer); - procedure OnRTUnSubAck(Sender: TObject; MessageID: integer); - procedure OnRTPublish(Sender: TObject; topic, payload: ansistring; retain: boolean); - procedure OnRTTerminate (Sender: TObject); - - - public - function isConnected: boolean; - procedure Connect; - function Disconnect: boolean; - procedure ForceDisconnect; - function Publish(Topic: ansistring; sPayload: ansistring): boolean; - overload; - function Publish(Topic: ansistring; sPayload: ansistring; Retain: boolean): boolean; - overload; - function Subscribe(Topic: ansistring): integer; - function Unsubscribe(Topic: ansistring): integer; - function PingReq: boolean; - function getMessage : TMQTTMessage; - function getMessageAck : TMQTTMessageAck; - constructor Create(Hostname: ansistring; Port: integer); - overload; - destructor Destroy; - override; - - property ClientID : ansistring read FClientID write FClientID; - property OnConnAck : TConnAckEvent read FConnAckEvent write FConnAckEvent; - property OnPublish : TPublishEvent read FPublishEvent write FPublishEvent; - property OnPingResp : TPingRespEvent read FPingRespEvent write FPingRespEvent; - property OnSubAck : TSubAckEvent read FSubAckEvent write FSubAckEvent; - property OnUnSubAck : TUnSubAckEvent read FUnSubAckEvent write FUnSubAckEvent; - end; - - // Message Component Build helpers - function FixedHeader(MessageType: TMQTTMessageType; Dup, Qos, Retain: byte): Byte; - - // Variable Header per command creation funcs - function VariableHeaderConnect(KeepAlive: Word): TBytes; - - // Takes a ansistring and converts to An Array of Bytes preceded by 2 Length Bytes. - function StrToBytes(str: ansistring; perpendLength: boolean): TUTF8Text; - - procedure CopyIntoArray(var DestArray: array of Byte; SourceArray: array of Byte; StartIndex - : - integer); - - // Byte Array Helper Functions - procedure AppendArray(var Dest: TUTF8Text; Source: array of Byte); - - - - - // Helper Function - Puts the seperate component together into an Array of Bytes for transmission - function BuildCommand(FixedHead: Byte; RemainL: TRemainingLength; VariableHead: TBytes; - Payload: - array of Byte): TBytes; - - // Calculates the Remaining Length bytes of the FixedHeader as per the spec. - function RemainingLength(MessageLength: Integer): TRemainingLength; - - - implementation - - constructor TMQTTMessage.Create(const topic_: ansistring; - const payload_: ansistring; const retain_: boolean); - begin - // Save the passed parameters - FTopic := Topic_; - FPayload := Payload_; - FRetain := retain_; - end; - - constructor TMQTTMessageAck.Create(const messageType_ : TMQTTMessageType; - const messageId_ : integer; - const returnCode_ : integer; - const qos_ : integer); - begin - FMessageType := messageType_; - FMessageId := messageId_; - FReturnCode := returnCode_; - FQos := qos_; - end; - + private + FTopic: ansistring; + FPayload: ansistring; + FRetain: boolean; + + public + property Topic: ansistring read FTopic; + property PayLoad: ansistring read FPayload; + property Retain: boolean read FRetain; + + constructor Create(const topic_: ansistring; const payload_: ansistring; + const retain_: boolean); + end; + + // The acknowledgement class definition + TMQTTMessageAck = class + private + FMessageType: TMQTTMessageType; + FMessageId: integer; + FReturnCode: integer; + FQos: integer; + public + property messageType: TMQTTMessageType read FMessageType; + property messageId: integer read FMessageId; + property returnCode: integer read FReturnCode; + property qos: integer read FQos; + + constructor Create(const messageType_: TMQTTMessageType; + const messageId_: integer; const returnCode_: integer; const qos_: integer); + end; + + TRemainingLength = array of byte; + TUTF8Text = array of byte; + + PMQTTClient = ^TMQTTClient; + + // Main object - MQTT client implementation + TMQTTClient = class(TObject) + private + FClientID: ansistring; + FHostname: ansistring; + FPort: integer; + FReadThread: TMQTTReadThread; + FMessageID: integer; + FisConnected: boolean; + FReaderThreadRunning: boolean; + + FConnAckEvent: TConnAckEvent; + FPublishEvent: TPublishEvent; + FPingRespEvent: TPingRespEvent; + FSubAckEvent: TSubAckEvent; + FUnSubAckEvent: TUnSubAckEvent; + + FCritical: TRTLCriticalSection; + FMessageQueue: TQueue; + FMessageAckQueue: TQueue; + + // Gets a next Message ID and increases the Message ID Increment + function GetMessageID: TBytes; + function VariableHeaderPublish(topic: ansistring): TBytes; + function VariableHeaderSubscribe: TBytes; + function VariableHeaderUnsubscribe: TBytes; + // Internally Write the provided data to the Socket. Wrapper function. + function SocketWrite(Data: TBytes): boolean; + + // These are chained event handlers from the ReceiveThread. They trigger the + // public TMQTTClient.On*** handlers. + procedure OnRTConnAck(Sender: TObject; ReturnCode: integer); + procedure OnRTPingResp(Sender: TObject); + procedure OnRTSubAck(Sender: TObject; MessageID: integer; GrantedQoS: integer); + procedure OnRTUnSubAck(Sender: TObject; MessageID: integer); + procedure OnRTPublish(Sender: TObject; topic, payload: ansistring; + retain: boolean); + procedure OnRTTerminate(Sender: TObject); + + public + function isConnected: boolean; + procedure Connect; + function Disconnect: boolean; + procedure ForceDisconnect; + function Publish(Topic: ansistring; sPayload: ansistring): boolean; overload; + function Publish(Topic: ansistring; sPayload: ansistring; + Retain: boolean): boolean; overload; + function Subscribe(Topic: ansistring): integer; + function Unsubscribe(Topic: ansistring): integer; + function PingReq: boolean; + function getMessage: TMQTTMessage; + function getMessageAck: TMQTTMessageAck; + constructor Create(Hostname: ansistring; Port: integer); overload; + destructor Destroy; override; + + property ClientID: ansistring read FClientID write FClientID; + property OnConnAck: TConnAckEvent read FConnAckEvent write FConnAckEvent; + property OnPublish: TPublishEvent read FPublishEvent write FPublishEvent; + property OnPingResp: TPingRespEvent read FPingRespEvent write FPingRespEvent; + property OnSubAck: TSubAckEvent read FSubAckEvent write FSubAckEvent; + property OnUnSubAck: TUnSubAckEvent read FUnSubAckEvent write FUnSubAckEvent; + end; + +// Message Component Build helpers +function FixedHeader(MessageType: TMQTTMessageType; Dup, Qos, Retain: byte): byte; + +// Variable Header per command creation funcs +function VariableHeaderConnect(KeepAlive: word): TBytes; + +// Takes a ansistring and converts to An Array of Bytes preceded by 2 Length Bytes. +function StrToBytes(str: ansistring; perpendLength: boolean): TUTF8Text; + +procedure CopyIntoArray(var DestArray: array of byte; SourceArray: array of byte; + StartIndex: integer); + +// Byte Array Helper Functions +procedure AppendArray(var Dest: TUTF8Text; Source: array of byte); + +// Helper Function - Puts the seperate component together into an Array of Bytes for transmission +function BuildCommand(FixedHead: byte; RemainL: TRemainingLength; + VariableHead: TBytes; Payload: array of byte): TBytes; + +// Calculates the Remaining Length bytes of the FixedHeader as per the spec. +function RemainingLength(MessageLength: integer): TRemainingLength; + + +implementation + + +constructor TMQTTMessage.Create(const topic_: ansistring; + const payload_: ansistring; const retain_: boolean); +begin + // Save the passed parameters + FTopic := Topic_; + FPayload := Payload_; + FRetain := retain_; +end; + +constructor TMQTTMessageAck.Create(const messageType_: TMQTTMessageType; + const messageId_: integer; const returnCode_: integer; const qos_: integer); +begin + FMessageType := messageType_; + FMessageId := messageId_; + FReturnCode := returnCode_; + FQos := qos_; +end; {*------------------------------------------------------------------------------ Instructs the Client to try to connect to the server at TMQTTClient.Hostname and TMQTTClient.Port and then to send the initial CONNECT message as required by the protocol. Check for a CONACK message to verify successful connection. ------------------------------------------------------------------------------*} - procedure TMQTTClient.Connect; - begin - if FReaderThreadRunning = false then - begin - // Create and start RX thread - if FReadThread <> nil then - begin - FReadThread.OnTerminate := nil; - FreeAndNil(FReadThread); - end; - FReadThread := TMQTTReadThread.Create(FHostname, FPort); - FReadThread.OnConnAck := @OnRTConnAck; - FReadThread.OnPublish := @OnRTPublish; - FReadThread.OnPublish := @OnRTPublish; - FReadThread.OnPingResp := @OnRTPingResp; - FReadThread.OnSubAck := @OnRTSubAck; - FReadThread.OnTerminate := @OnRTTerminate; - FReadThread.Start; - FReaderThreadRunning := true; - end; - end; - - - - +procedure TMQTTClient.Connect; +begin + if FReaderThreadRunning = False then + begin + // Create and start RX thread + if FReadThread <> nil then + begin + FReadThread.OnTerminate := nil; + FreeAndNil(FReadThread); + end; + FReadThread := TMQTTReadThread.Create(FHostname, FPort); + FReadThread.OnConnAck := @OnRTConnAck; + FReadThread.OnPublish := @OnRTPublish; + FReadThread.OnPublish := @OnRTPublish; + FReadThread.OnPingResp := @OnRTPingResp; + FReadThread.OnSubAck := @OnRTSubAck; + FReadThread.OnTerminate := @OnRTTerminate; + FReadThread.Start; + FReaderThreadRunning := True; + end; +end; {*------------------------------------------------------------------------------ Sends the DISCONNECT packets and then Disconnects gracefully from the server which it is currently connected to. @return Returns whether the Data was written successfully to the socket. ------------------------------------------------------------------------------*} - function TMQTTClient.Disconnect: boolean; - - var - Data: TBytes; - begin - writeln('TMQTTClient.Disconnect'); - Result := False; - - SetLength(Data, 2); - Data[0] := FixedHeader(MQTT.DISCONNECT, 0, 0, 0); - Data[1] := 0; - if SocketWrite(Data) then - begin - FisConnected := False; - if FReadThread <> nil then - begin - //todo: collect all terminate code (connect, Disconnect, ForceDisconnect) to one point - FReadThread.OnTerminate := nil; - FReadThread.Terminate; - FReadThread := nil; - //todo: the probability of a hang? - //FReadThread.waitFor; - end; - Result := True; - end - else Result := False; - end; - - - - +function TMQTTClient.Disconnect: boolean; +var + Data: TBytes; +begin + writeln('TMQTTClient.Disconnect'); + Result := False; + + SetLength(Data, 2); + Data[0] := FixedHeader(MQTT.DISCONNECT, 0, 0, 0); + Data[1] := 0; + if SocketWrite(Data) then + begin + FisConnected := False; + if FReadThread <> nil then + begin + //todo: collect all terminate code (connect, Disconnect, ForceDisconnect) to one point + FReadThread.OnTerminate := nil; + FReadThread.Terminate; + FReadThread := nil; + //todo: the probability of a hang? + //FReadThread.waitFor; + end; + Result := True; + end + else + Result := False; +end; {*------------------------------------------------------------------------------ Terminate the reader thread and close the socket forcibly. ------------------------------------------------------------------------------*} - procedure TMQTTClient.ForceDisconnect; - begin - writeln('TMQTTClient.ForceDisconnect'); - if FReadThread <> nil then - begin - FReadThread.OnTerminate := nil; - FReadThread.Terminate; - FReadThread := nil; - end; - FisConnected := False; - end; - - - +procedure TMQTTClient.ForceDisconnect; +begin + writeln('TMQTTClient.ForceDisconnect'); + if FReadThread <> nil then + begin + FReadThread.OnTerminate := nil; + FReadThread.Terminate; + FReadThread := nil; + end; + FisConnected := False; +end; {*------------------------------------------------------------------------------ Call back for reader thread termination. ------------------------------------------------------------------------------*} - procedure TMQTTClient.OnRTTerminate(Sender: TObject); - begin - //todo: on terminating - need disable this object - FReadThread := nil; - FReaderThreadRunning := false; - FisConnected := false; - WriteLn('TMQTTClient.OnRTTerminate: Thread.Terminated.'); - end; - - - +procedure TMQTTClient.OnRTTerminate(Sender: TObject); +begin + //todo: on terminating - need disable this object + FReadThread := nil; + FReaderThreadRunning := False; + FisConnected := False; + WriteLn('TMQTTClient.OnRTTerminate: Thread.Terminated.'); +end; {*------------------------------------------------------------------------------ Sends a PINGREQ to the server informing it that the client is alice and that it should send a PINGRESP back in return. @return Returns whether the Data was written successfully to the socket. ------------------------------------------------------------------------------*} - function TMQTTClient.PingReq: boolean; - - var - FH: Byte; - RL: Byte; - Data: TBytes; - begin - Result := False; - - SetLength(Data, 2); - FH := FixedHeader(MQTT.PINGREQ, 0, 0, 0); - RL := 0; - Data[0] := FH; - Data[1] := RL; - if SocketWrite(Data) then Result := True - else Result := False; - end; - - - - +function TMQTTClient.PingReq: boolean; +var + FH: byte; + RL: byte; + Data: TBytes; +begin + Result := False; + + SetLength(Data, 2); + FH := FixedHeader(MQTT.PINGREQ, 0, 0, 0); + RL := 0; + Data[0] := FH; + Data[1] := RL; + if SocketWrite(Data) then + Result := True + else + Result := False; +end; {*------------------------------------------------------------------------------ Publishes a message sPayload to the Topic on the remote broker with the retain flag @@ -355,30 +324,27 @@ TMQTTClient = class(TObject) @param Retain Should this message be retained for clients connecting subsequently @return Returns whether the Data was written successfully to the socket. ------------------------------------------------------------------------------*} - function TMQTTClient.Publish(Topic, sPayload: ansistring; Retain: boolean): boolean; - - var - Data: TBytes; - FH: Byte; - RL: TRemainingLength; - VH: TBytes; - Payload: TUTF8Text; - begin - Result := False; - - FH := FixedHeader(MQTT.PUBLISH, 0, 0, Ord(Retain)); - VH := VariableHeaderPublish(Topic); - SetLength(Payload, 0); - AppendArray(Payload, StrToBytes(sPayload, false)); - RL := RemainingLength(Length(VH) + Length(Payload)); - Data := BuildCommand(FH, RL, VH, Payload); - if SocketWrite(Data) then Result := True - else Result := False; - end; - - - - +function TMQTTClient.Publish(Topic, sPayload: ansistring; Retain: boolean): boolean; +var + Data: TBytes; + FH: byte; + RL: TRemainingLength; + VH: TBytes; + Payload: TUTF8Text; +begin + Result := False; + + FH := FixedHeader(MQTT.PUBLISH, 0, 0, Ord(Retain)); + VH := VariableHeaderPublish(Topic); + SetLength(Payload, 0); + AppendArray(Payload, StrToBytes(sPayload, False)); + RL := RemainingLength(Length(VH) + Length(Payload)); + Data := BuildCommand(FH, RL, VH, Payload); + if SocketWrite(Data) then + Result := True + else + Result := False; +end; {*------------------------------------------------------------------------------ Publishes a message sPayload to the Topic on the remote broker with the retain flag @@ -387,14 +353,10 @@ TMQTTClient = class(TObject) @param sPayload The Actual Payload of the message eg 18 degrees celcius @return Returns whether the Data was written successfully to the socket. ------------------------------------------------------------------------------*} - function TMQTTClient.Publish(Topic, sPayload: ansistring): boolean; - begin - Result := Publish(Topic, sPayload, False); - end; - - - - +function TMQTTClient.Publish(Topic, sPayload: ansistring): boolean; +begin + Result := Publish(Topic, sPayload, False); +end; {*------------------------------------------------------------------------------ Subscribe to Messages published to the topic specified. Only accepts 1 topic per @@ -403,32 +365,27 @@ TMQTTClient = class(TObject) @return Returns the Message ID used to send the message for the purpose of comparing it to the Message ID used later in the SUBACK event handler. ------------------------------------------------------------------------------*} - function TMQTTClient.Subscribe(Topic: ansistring): integer; - - var - Data: TBytes; - FH: Byte; - RL: TRemainingLength; - VH: TBytes; - Payload: TUTF8Text; - begin - FH := FixedHeader(MQTT.SUBSCRIBE, 0, 1, 0); - VH := VariableHeaderSubscribe; - Result := (FMessageID - 1); - SetLength(Payload, 0); - AppendArray(Payload, StrToBytes(Topic, true)); - // Append a new Byte to Add the Requested QoS Level for that Topic - SetLength(Payload, Length(Payload) + 1); - // Always Append Requested QoS Level 0 - Payload[Length(Payload) - 1] := $0; - RL := RemainingLength(Length(VH) + Length(Payload)); - Data := BuildCommand(FH, RL, VH, Payload); - SocketWrite(Data); - end; - - - - +function TMQTTClient.Subscribe(Topic: ansistring): integer; +var + Data: TBytes; + FH: byte; + RL: TRemainingLength; + VH: TBytes; + Payload: TUTF8Text; +begin + FH := FixedHeader(MQTT.SUBSCRIBE, 0, 1, 0); + VH := VariableHeaderSubscribe; + Result := (FMessageID - 1); + SetLength(Payload, 0); + AppendArray(Payload, StrToBytes(Topic, True)); + // Append a new Byte to Add the Requested QoS Level for that Topic + SetLength(Payload, Length(Payload) + 1); + // Always Append Requested QoS Level 0 + Payload[Length(Payload) - 1] := $0; + RL := RemainingLength(Length(VH) + Length(Payload)); + Data := BuildCommand(FH, RL, VH, Payload); + SocketWrite(Data); +end; {*------------------------------------------------------------------------------ Unsubscribe to Messages published to the topic specified. Only accepts 1 topic per @@ -437,28 +394,23 @@ TMQTTClient = class(TObject) @return Returns the Message ID used to send the message for the purpose of comparing it to the Message ID used later in the UNSUBACK event handler. ------------------------------------------------------------------------------*} - function TMQTTClient.Unsubscribe(Topic: ansistring): integer; - - var - Data: TBytes; - FH: Byte; - RL: TRemainingLength; - VH: TBytes; - Payload: TUTF8Text; - begin - FH := FixedHeader(MQTT.UNSUBSCRIBE, 0, 0, 0); - VH := VariableHeaderUnsubscribe; - Result := (FMessageID - 1); - SetLength(Payload, 0); - AppendArray(Payload, StrToBytes(Topic, true)); - RL := RemainingLength(Length(VH) + Length(Payload)); - Data := BuildCommand(FH, RL, VH, Payload); - SocketWrite(Data); - end; - - - - +function TMQTTClient.Unsubscribe(Topic: ansistring): integer; +var + Data: TBytes; + FH: byte; + RL: TRemainingLength; + VH: TBytes; + Payload: TUTF8Text; +begin + FH := FixedHeader(MQTT.UNSUBSCRIBE, 0, 0, 0); + VH := VariableHeaderUnsubscribe; + Result := (FMessageID - 1); + SetLength(Payload, 0); + AppendArray(Payload, StrToBytes(Topic, True)); + RL := RemainingLength(Length(VH) + Length(Payload)); + Data := BuildCommand(FH, RL, VH, Payload); + SocketWrite(Data); +end; {*------------------------------------------------------------------------------ Not Reliable. This is a leaky abstraction. The Core Socket components can only @@ -467,14 +419,10 @@ TMQTTClient = class(TObject) TMQTTClient.Connect and .Disconnect methods. @return Returns whether the internal connected flag is set or not. ------------------------------------------------------------------------------*} - function TMQTTClient.isConnected: boolean; - begin - Result := FisConnected; - end; - - - - +function TMQTTClient.isConnected: boolean; +begin + Result := FisConnected; +end; {*------------------------------------------------------------------------------ Component Constructor, @@ -482,130 +430,124 @@ TMQTTClient = class(TObject) @param Port Port of the MQTT Server @return Instance ------------------------------------------------------------------------------*} - constructor TMQTTClient.Create(Hostname: ansistring; Port: integer); - begin - inherited Create; - Randomize; - -// Create a Default ClientID as a default. Can be overridden with TMQTTClient.ClientID any time before connection. - FClientID := 'dMQTTClient' + IntToStr(Random(1000) + 1); - FHostname := Hostname; - FPort := Port; - FMessageID := 1; - FReaderThreadRunning := false; - InitCriticalSection(FCritical); - FMessageQueue := TQueue.Create; - FMessageAckQueue := TQueue.Create; - end; - - destructor TMQTTClient.Destroy; - begin - if (isConnected) and (FReadThread <> nil) then - begin - FReadThread.Terminate; - FReadThread.WaitFor; - //note: free is not needed - the FreeOnTerminate mode is enabled - end; - FMessageQueue.free; - FMessageAckQueue.free; - DoneCriticalSection(FCritical); - inherited; - end; - - function FixedHeader(MessageType: TMQTTMessageType; Dup, Qos, - Retain: byte): Byte; - begin - +constructor TMQTTClient.Create(Hostname: ansistring; Port: integer); +begin + inherited Create; + Randomize; + + // Create a Default ClientID as a default. Can be overridden with TMQTTClient.ClientID any time before connection. + FClientID := 'dMQTTClient' + IntToStr(Random(1000) + 1); + FHostname := Hostname; + FPort := Port; + FMessageID := 1; + FReaderThreadRunning := False; + InitCriticalSection(FCritical); + FMessageQueue := TQueue.Create; + FMessageAckQueue := TQueue.Create; +end; + +destructor TMQTTClient.Destroy; +begin + if (isConnected) and (FReadThread <> nil) then + begin + FReadThread.Terminate; + FReadThread.WaitFor; + //note: free is not needed - the FreeOnTerminate mode is enabled + end; + FMessageQueue.Free; + FMessageAckQueue.Free; + DoneCriticalSection(FCritical); + inherited; +end; + +function FixedHeader(MessageType: TMQTTMessageType; Dup, Qos, Retain: byte): byte; +begin { Fixed Header Spec: byte 1 bits |7 6 5 4 | 3 | 2 1 | 0 | fields |Message Type| DUP flag | QoS level| RETAIN| } - Result := Byte(Ord(MessageType) shl 4) or (Dup shl 3) or (Qos shl 1) or (Retain shl 0); - //todo: OLD code: Result := (Ord(MessageType) * 16) + (Dup * 8) + (Qos * 2) + (Retain * 1); - end; + Result := byte(Ord(MessageType) shl 4) or (Dup shl 3) or (Qos shl 1) or + (Retain shl 0); + //todo: OLD code: Result := (Ord(MessageType) * 16) + (Dup * 8) + (Qos * 2) + (Retain * 1); +end; - function TMQTTClient.GetMessageID: TBytes; - begin - Assert((FMessageID > Low(Word)), 'Message ID too low'); - Assert((FMessageID < High(Word)), 'Message ID has gotten too big'); +function TMQTTClient.GetMessageID: TBytes; +begin + Assert((FMessageID > Low(word)), 'Message ID too low'); + Assert((FMessageID < High(word)), 'Message ID has gotten too big'); { FMessageID is initialised to 1 upon TMQTTClient.Create The Message ID is a 16-bit unsigned integer, which typically increases by exactly one from one message to the next, but is not required to do so. The two bytes of the Message ID are ordered as MSB, followed by LSB (big-endian).} - SetLength(Result, 2); - Result[0] := Hi(FMessageID); - Result[1] := Lo(FMessageID); - Inc(FMessageID); - end; - - function TMQTTClient.SocketWrite(Data: TBytes): boolean; - - var - sentData: integer; - begin - Result := False; - // Returns whether the Data was successfully written to the socket. - if isConnected then - Result := FReadThread.SocketWrite(Data); - end; - - function StrToBytes(str: ansistring; perpendLength: boolean): TUTF8Text; - - var - i, offset: integer; - begin + SetLength(Result, 2); + Result[0] := Hi(FMessageID); + Result[1] := Lo(FMessageID); + Inc(FMessageID); +end; + +function TMQTTClient.SocketWrite(Data: TBytes): boolean; +var + sentData: integer; +begin + Result := False; + // Returns whether the Data was successfully written to the socket. + if isConnected then + Result := FReadThread.SocketWrite(Data); +end; + +function StrToBytes(str: ansistring; perpendLength: boolean): TUTF8Text; +var + i, offset: integer; +begin { This is a UTF-8 hack to give 2 Bytes of Length followed by the string itself. } - if perpendLength then - begin - SetLength(Result, Length(str) + 2); - Result[0] := Length(str) div 256; - Result[1] := Length(str) mod 256; - offset := 1; - end - else - begin - SetLength(Result, Length(str)); - offset := -1; - end; - for I := 1 to Length(str) do - Result[i + offset] := ord(str[i]); - end; - - function RemainingLength(MessageLength: Integer): TRemainingLength; - - var - byteindex: integer; - digit: integer; - begin - SetLength(Result, 1); - byteindex := 0; - while (MessageLength > 0) do - begin - digit := MessageLength mod 128; - MessageLength := MessageLength div 128; - if MessageLength > 0 then - begin - digit := digit or $80; - end; - Result[byteindex] := digit; - if MessageLength > 0 then - begin - inc(byteindex); - SetLength(Result, Length(Result) + 1); - end; - end; - end; - - function VariableHeaderConnect(KeepAlive: Word): TBytes; - - const - //todo: version update! MQIsdp->MQTT. version 4! - MQTT_PROTOCOL = 'MQIsdp'; - MQTT_VERSION = 3; - - var - Qos, Retain: word; + if perpendLength then + begin + SetLength(Result, Length(str) + 2); + Result[0] := Length(str) div 256; + Result[1] := Length(str) mod 256; + offset := 1; + end + else + begin + SetLength(Result, Length(str)); + offset := -1; + end; + for I := 1 to Length(str) do + Result[i + offset] := Ord(str[i]); +end; + +function RemainingLength(MessageLength: integer): TRemainingLength; +var + byteindex: integer; + digit: integer; +begin + SetLength(Result, 1); + byteindex := 0; + while (MessageLength > 0) do + begin + digit := MessageLength mod 128; + MessageLength := MessageLength div 128; + if MessageLength > 0 then + begin + digit := digit or $80; + end; + Result[byteindex] := digit; + if MessageLength > 0 then + begin + Inc(byteindex); + SetLength(Result, Length(Result) + 1); + end; + end; +end; + +function VariableHeaderConnect(KeepAlive: word): TBytes; +const + //todo: version update! MQIsdp->MQTT. version 4! + MQTT_PROTOCOL = 'MQIsdp'; + MQTT_VERSION = 3; +var + Qos, Retain: word; {todo: connect flags 7 User Name Flag 6 Password Flag @@ -615,213 +557,215 @@ TMQTTClient = class(TObject) 2 Will Flag 1 Clean Session 0 Reserved } - iByteIndex: integer; - ProtoBytes: TUTF8Text; - begin - // Set the Length of our variable header array. - SetLength(Result, 12); - iByteIndex := 0; - // Put out Protocol string in there. - ProtoBytes := StrToBytes(MQTT_PROTOCOL, true); - CopyIntoArray(Result, ProtoBytes, iByteIndex); - Inc(iByteIndex, Length(ProtoBytes)); - // Version Number = 3 - Result[iByteIndex] := MQTT_VERSION; - Inc(iByteIndex); - // Connect Flags - Qos := 0; - Retain := 0; - Result[iByteIndex] := 0; - Result[iByteIndex] := (Retain * 32) + (Qos * 16) + (1 * 4) + (1 * 2); - Inc(iByteIndex); - Result[iByteIndex] := 0; - Inc(iByteIndex); - Result[iByteIndex] := KeepAlive; - end; - - function TMQTTClient.VariableHeaderPublish(topic: ansistring): TBytes; - var - BytesTopic: TUTF8Text; - begin - BytesTopic := StrToBytes(Topic, true); - SetLength(Result, Length(BytesTopic)); - CopyIntoArray(Result, BytesTopic, 0); - end; - - function TMQTTClient.VariableHeaderSubscribe: TBytes; - begin - Result := GetMessageID; - end; - - function TMQTTClient.VariableHeaderUnsubscribe: TBytes; - begin - Result := GetMessageID; - end; - - procedure CopyIntoArray(var DestArray: array of Byte; - SourceArray: array of Byte; - StartIndex: integer); - begin - Assert(StartIndex >= 0); - // WARNING! move causes range check error if source length is zero. - if Length(SourceArray) > 0 then - Move(SourceArray[0], DestArray[StartIndex], Length(SourceArray)); - end; - - procedure AppendArray(var Dest: TUTF8Text; Source: array of Byte); - - var - DestLen: Integer; - begin - // WARNING: move causes range check error if source length is zero! - if Length(Source) > 0 then - begin - DestLen := Length(Dest); - SetLength(Dest, DestLen + Length(Source)); - Move(Source, Dest[DestLen], Length(Source)); - end; - end; - - function BuildCommand(FixedHead: Byte; RemainL: TRemainingLength; - VariableHead: TBytes; Payload: array of Byte): TBytes; - - var - iNextIndex: integer; - begin - // Attach Fixed Header (1 byte) - iNextIndex := 0; - SetLength(Result, 1); - Result[iNextIndex] := FixedHead; - - // Attach RemainingLength (1-4 bytes) - iNextIndex := Length(Result); - SetLength(Result, Length(Result) + Length(RemainL)); - CopyIntoArray(Result, RemainL, iNextIndex); - - // Attach Variable Head - iNextIndex := Length(Result); - SetLength(Result, Length(Result) + Length(VariableHead)); - CopyIntoArray(Result, VariableHead, iNextIndex); - - // Attach Payload. - iNextIndex := Length(Result); - SetLength(Result, Length(Result) + Length(Payload)); - CopyIntoArray(Result, Payload, iNextIndex); - end; - - procedure TMQTTClient.OnRTConnAck(Sender: TObject; ReturnCode: integer); - begin - if ReturnCode = 0 then - begin - FisConnected := true; - end; - if Assigned(OnConnAck) then - begin - OnConnAck(Self, ReturnCode); - end - else - begin - // Protected code. - EnterCriticalSection (FCritical); - try - FMessageAckQueue.Push (TMQTTMessageAck.Create(CONNACK, 0, ReturnCode, 0)); - finally - LeaveCriticalSection (FCritical); - end; - end; - end; - - procedure TMQTTClient.OnRTPingResp(Sender: TObject); - begin - if Assigned(OnPingResp) then - begin - OnPingResp(Self); - end - else - begin - // Protected code. - EnterCriticalSection (FCritical); - try - FMessageAckQueue.Push (TMQTTMessageAck.Create(PINGRESP, 0, 0, 0)); - finally - LeaveCriticalSection (FCritical); - end; - end; - end; - - procedure TMQTTClient.OnRTPublish(Sender: TObject; topic, payload: ansistring; retain: boolean); - begin - if Assigned(OnPublish) then - begin - OnPublish(Self, topic, payload, retain); - end - else - begin - // Protected code. - EnterCriticalSection (FCritical); - try - FMessageQueue.Push (TMQTTMessage.Create(topic, payload, retain)); - finally - LeaveCriticalSection (FCritical); - end; - end; - end; - - procedure TMQTTClient.OnRTSubAck(Sender: TObject; MessageID: integer; GrantedQoS: integer); - begin - if Assigned(OnSubAck) then - begin - OnSubAck(Self, MessageID, GrantedQoS); - end - else - begin - // Protected code. - EnterCriticalSection (FCritical); - try - FMessageAckQueue.Push (TMQTTMessageAck.Create(SUBACK, MessageID, 0, GrantedQos)); - finally - LeaveCriticalSection (FCritical); - end; - end; - end; - - procedure TMQTTClient.OnRTUnSubAck(Sender: TObject; MessageID: integer); - begin - if Assigned(OnUnSubAck) then - begin - OnUnSubAck(Self, MessageID); - end - else - begin - // Protected code. - EnterCriticalSection (FCritical); - try - FMessageAckQueue.Push (TMQTTMessageAck.Create(SUBACK, MessageID, 0, 0)); - finally - LeaveCriticalSection (FCritical); - end; - end; - end; - - function TMQTTClient.getMessage: TMQTTMessage; - begin - // Protected code. - EnterCriticalSection (FCritical); - try - Result := TMQTTMessage(FMessageQueue.Pop); - finally - LeaveCriticalSection (FCritical); - end; - end; - - function TMQTTClient.getMessageAck: TMQTTMessageAck; - begin - // Protected code. - EnterCriticalSection (FCritical); - try - Result := TMQTTMessageAck(FMessageAckQueue.Pop); - finally - LeaveCriticalSection (FCritical); - end; - end; + iByteIndex: integer; + ProtoBytes: TUTF8Text; +begin + // Set the Length of our variable header array. + SetLength(Result, 12); + iByteIndex := 0; + // Put out Protocol string in there. + ProtoBytes := StrToBytes(MQTT_PROTOCOL, True); + CopyIntoArray(Result, ProtoBytes, iByteIndex); + Inc(iByteIndex, Length(ProtoBytes)); + // Version Number = 3 + Result[iByteIndex] := MQTT_VERSION; + Inc(iByteIndex); + // Connect Flags + Qos := 0; + Retain := 0; + Result[iByteIndex] := 0; + Result[iByteIndex] := (Retain * 32) + (Qos * 16) + (1 * 4) + (1 * 2); + Inc(iByteIndex); + Result[iByteIndex] := 0; + Inc(iByteIndex); + Result[iByteIndex] := KeepAlive; +end; + +function TMQTTClient.VariableHeaderPublish(topic: ansistring): TBytes; +var + BytesTopic: TUTF8Text; +begin + BytesTopic := StrToBytes(Topic, True); + SetLength(Result, Length(BytesTopic)); + CopyIntoArray(Result, BytesTopic, 0); +end; + +function TMQTTClient.VariableHeaderSubscribe: TBytes; +begin + Result := GetMessageID; +end; + +function TMQTTClient.VariableHeaderUnsubscribe: TBytes; +begin + Result := GetMessageID; +end; + +procedure CopyIntoArray(var DestArray: array of byte; SourceArray: array of byte; + StartIndex: integer); +begin + Assert(StartIndex >= 0); + // WARNING! move causes range check error if source length is zero. + if Length(SourceArray) > 0 then + Move(SourceArray[0], DestArray[StartIndex], Length(SourceArray)); +end; + +procedure AppendArray(var Dest: TUTF8Text; Source: array of byte); + +var + DestLen: integer; +begin + // WARNING: move causes range check error if source length is zero! + if Length(Source) > 0 then + begin + DestLen := Length(Dest); + SetLength(Dest, DestLen + Length(Source)); + Move(Source, Dest[DestLen], Length(Source)); + end; +end; + +function BuildCommand(FixedHead: byte; RemainL: TRemainingLength; + VariableHead: TBytes; Payload: array of byte): TBytes; +var + iNextIndex: integer; +begin + // Attach Fixed Header (1 byte) + iNextIndex := 0; + SetLength(Result, 1); + Result[iNextIndex] := FixedHead; + + // Attach RemainingLength (1-4 bytes) + iNextIndex := Length(Result); + SetLength(Result, Length(Result) + Length(RemainL)); + CopyIntoArray(Result, RemainL, iNextIndex); + + // Attach Variable Head + iNextIndex := Length(Result); + SetLength(Result, Length(Result) + Length(VariableHead)); + CopyIntoArray(Result, VariableHead, iNextIndex); + + // Attach Payload. + iNextIndex := Length(Result); + SetLength(Result, Length(Result) + Length(Payload)); + CopyIntoArray(Result, Payload, iNextIndex); +end; + +procedure TMQTTClient.OnRTConnAck(Sender: TObject; ReturnCode: integer); +begin + if ReturnCode = 0 then + begin + FisConnected := True; + end; + if Assigned(OnConnAck) then + begin + OnConnAck(Self, ReturnCode); + end + else + begin + // Protected code. + EnterCriticalSection(FCritical); + try + FMessageAckQueue.Push(TMQTTMessageAck.Create(CONNACK, 0, ReturnCode, 0)); + finally + LeaveCriticalSection(FCritical); + end; + end; +end; + +procedure TMQTTClient.OnRTPingResp(Sender: TObject); +begin + if Assigned(OnPingResp) then + begin + OnPingResp(Self); + end + else + begin + // Protected code. + EnterCriticalSection(FCritical); + try + FMessageAckQueue.Push(TMQTTMessageAck.Create(PINGRESP, 0, 0, 0)); + finally + LeaveCriticalSection(FCritical); + end; + end; +end; + +procedure TMQTTClient.OnRTPublish(Sender: TObject; topic, payload: ansistring; + retain: boolean); +begin + if Assigned(OnPublish) then + begin + OnPublish(Self, topic, payload, retain); + end + else + begin + // Protected code. + EnterCriticalSection(FCritical); + try + FMessageQueue.Push(TMQTTMessage.Create(topic, payload, retain)); + finally + LeaveCriticalSection(FCritical); + end; + end; +end; + +procedure TMQTTClient.OnRTSubAck(Sender: TObject; MessageID: integer; + GrantedQoS: integer); +begin + if Assigned(OnSubAck) then + begin + OnSubAck(Self, MessageID, GrantedQoS); + end + else + begin + // Protected code. + EnterCriticalSection(FCritical); + try + FMessageAckQueue.Push(TMQTTMessageAck.Create(SUBACK, MessageID, + 0, GrantedQos)); + finally + LeaveCriticalSection(FCritical); + end; + end; +end; + +procedure TMQTTClient.OnRTUnSubAck(Sender: TObject; MessageID: integer); +begin + if Assigned(OnUnSubAck) then + begin + OnUnSubAck(Self, MessageID); + end + else + begin + // Protected code. + EnterCriticalSection(FCritical); + try + FMessageAckQueue.Push(TMQTTMessageAck.Create(SUBACK, MessageID, 0, 0)); + finally + LeaveCriticalSection(FCritical); + end; + end; +end; + +function TMQTTClient.getMessage: TMQTTMessage; +begin + // Protected code. + EnterCriticalSection(FCritical); + try + Result := TMQTTMessage(FMessageQueue.Pop); + finally + LeaveCriticalSection(FCritical); + end; +end; + +function TMQTTClient.getMessageAck: TMQTTMessageAck; +begin + // Protected code. + EnterCriticalSection(FCritical); + try + Result := TMQTTMessageAck(FMessageAckQueue.Pop); + finally + LeaveCriticalSection(FCritical); + end; +end; + end. diff --git a/TMQTTClient/MQTTReadThread.pas b/TMQTTClient/MQTTReadThread.pas index 2e02e1c..215d056 100644 --- a/TMQTTClient/MQTTReadThread.pas +++ b/TMQTTClient/MQTTReadThread.pas @@ -32,326 +32,324 @@ interface - -uses +uses SysUtils, Classes, blcksock, synsock; +type + TBytes = array of byte; -type TBytes = array of Byte; - -type +type TMQTTMessage = record - FixedHeader: Byte; + FixedHeader: byte; RL: TBytes; Data: TBytes; end; -type TRxStates = (RX_START, RX_FIXED_HEADER, RX_LENGTH, RX_DATA, RX_ERROR); +type + TRxStates = (RX_START, RX_FIXED_HEADER, RX_LENGTH, RX_DATA, RX_ERROR); - TRemainingLength = Array of Byte; + TRemainingLength = array of byte; - TUTF8Text = Array of Byte; + TUTF8Text = array of byte; - TConnAckEvent = procedure (Sender: TObject; ReturnCode: integer) of object; - TPublishEvent = procedure (Sender: TObject; topic, payload: ansistring; retain: boolean) of object; - TPingRespEvent = procedure (Sender: TObject) of object; - TSubAckEvent = procedure (Sender: TObject; MessageID: integer; GrantedQoS: integer) of object; - TUnSubAckEvent = procedure (Sender: TObject; MessageID: integer) of object; + TConnAckEvent = procedure(Sender: TObject; ReturnCode: integer) of object; + TPublishEvent = procedure(Sender: TObject; topic, payload: ansistring; + retain: boolean) of object; + TPingRespEvent = procedure(Sender: TObject) of object; + TSubAckEvent = procedure(Sender: TObject; MessageID: integer; + GrantedQoS: integer) of object; + TUnSubAckEvent = procedure(Sender: TObject; MessageID: integer) of object; TMQTTReadThread = class(TThread) - private - FClientID: ansistring; - FHostname: ansistring; - FPort: integer; - CurrentMessage: TMQTTMessage; - // Events - FConnAckEvent: TConnAckEvent; - FPublishEvent: TPublishEvent; - FPingRespEvent: TPingRespEvent; - FSubAckEvent: TSubAckEvent; - FUnSubAckEvent: TUnSubAckEvent; - - - - -// Takes a 2 Byte Length array and returns the length of the ansistring it preceeds as per the spec. - function BytesToStrLength(LengthBytes: TBytes): integer; - - // This is our data processing and event firing command. - procedure HandleData; - - - protected - procedure Execute; + private + FClientID: ansistring; + FHostname: ansistring; + FPort: integer; + CurrentMessage: TMQTTMessage; + // Events + FConnAckEvent: TConnAckEvent; + FPublishEvent: TPublishEvent; + FPingRespEvent: TPingRespEvent; + FSubAckEvent: TSubAckEvent; + FUnSubAckEvent: TUnSubAckEvent; + + // Takes a 2 Byte Length array and returns the length of the ansistring it preceeds as per the spec. + function BytesToStrLength(LengthBytes: TBytes): integer; + + // This is our data processing and event firing command. + procedure HandleData; + protected + procedure Execute; override; - public - //todo: change Socket resurse working - FPSocket: TTCPBlockSocket; - function SocketWrite(Data: TBytes): boolean; - - constructor Create(Hostname: ansistring; Port: integer); - property OnConnAck : TConnAckEvent read FConnAckEvent write FConnAckEvent; - property OnPublish : TPublishEvent read FPublishEvent write FPublishEvent; - property OnPingResp : TPingRespEvent read FPingRespEvent write FPingRespEvent; - property OnSubAck : TSubAckEvent read FSubAckEvent write FSubAckEvent; - property OnUnSubAck : TUnSubAckEvent read FUnSubAckEvent write FUnSubAckEvent; - end; + public + //todo: change Socket resurse working + FPSocket: TTCPBlockSocket; + function SocketWrite(Data: TBytes): boolean; + + constructor Create(Hostname: ansistring; Port: integer); + property OnConnAck: TConnAckEvent read FConnAckEvent write FConnAckEvent; + property OnPublish: TPublishEvent read FPublishEvent write FPublishEvent; + property OnPingResp: TPingRespEvent read FPingRespEvent write FPingRespEvent; + property OnSubAck: TSubAckEvent read FSubAckEvent write FSubAckEvent; + property OnUnSubAck: TUnSubAckEvent read FUnSubAckEvent write FUnSubAckEvent; + end; - implementation +implementation +uses + MQTT; - uses - MQTT; +procedure SetBit(var Value: byte; const Index: byte; const State: boolean); inline; +begin + Value := (Value and ((byte(1) shl Index) xor High(byte))) or + (byte(State) shl Index); +end; - procedure SetBit(var Value: byte; const Index: Byte; const State: Boolean); inline; - begin - Value := (Value and ((byte(1) shl Index) xor High(byte))) or (byte(State) shl Index); - end; - - function GetBit(const Value: byte; const Index: Byte): Boolean; inline; - begin - Result := ((Value shr Index) and 1) = 1; - end; +function GetBit(const Value: byte; const Index: byte): boolean; inline; +begin + Result := ((Value shr Index) and 1) = 1; +end; { TMQTTReadThread } - constructor TMQTTReadThread.Create(HostName: ansistring; Port: integer) - ; - begin - inherited Create(true); - - - - -// Create a Default ClientID as a default. Can be overridden with TMQTTClient.ClientID any time before connection. - FClientID := 'dMQTTClientx' + IntToStr(Random(1000) + 1); - FHostname := Hostname; - FPort := Port; - FreeOnTerminate := true; - end; - - procedure TMQTTReadThread.Execute; - - var - rxState: TRxStates; - remainingLengthx: integer; - digit: integer; - multiplier: integer; - Data: TBytes; - RL: TRemainingLength; - VH: TBytes; - FH: Byte; - Payload: TUTF8Text; - error: integer; - begin - rxState := RX_START; - try - // Create a socket. - FPSocket := TTCPBlockSocket.Create; - FPSocket.nonBlockMode := true; // We really don't want sending on - FPSocket.NonblockSendTimeout := 1; // the socket to block our main thread. - while not self.Terminated do - begin - case rxState of - RX_START: - begin - // Make the socket connection - FPSocket.Connect(FHostname, IntToStr(FPort)); - - // Build CONNECT message - FH := FixedHeader(MQTT.CONNECT, 0, 0, 0); - VH := VariableHeaderConnect(40); - SetLength(Payload, 0); - AppendArray(Payload, StrToBytes(FClientID, true)); - AppendArray(Payload, StrToBytes('lwt', true)); - AppendArray(Payload, StrToBytes(FClientID + ' died', true)); - RL := RemainingLength(Length(VH) + Length(Payload)); - Data := BuildCommand(FH, RL, VH, Payload); - - writeln('RX_START: ', FPSocket.LastErrorDesc); - writeln('RX_START: ', FPSocket.LastError); - - //sleep(1); - - // Send CONNECT message - while not self.Terminated do - begin - writeln('loop...'); - SocketWrite(Data); - error := FPSocket.LastError; - writeln('RX_START: ', FPSocket.LastErrorDesc); - writeln('RX_START: ', error); - if error = 0 then - begin - rxState := RX_FIXED_HEADER; - break; - end - else - begin - if error = 110 then - begin - continue; - end; - rxState := RX_ERROR; - break; - end; - end; - end; - RX_FIXED_HEADER: - begin - multiplier := 1; - remainingLengthx := 0; - CurrentMessage.Data := nil; - - CurrentMessage.FixedHeader := FPSocket.RecvByte(1000); - if (FPSocket.LastError = WSAETIMEDOUT) then continue; - if (FPSocket.LastError <> 0) then - rxState := RX_ERROR - else - rxState := RX_LENGTH; - end; - RX_LENGTH: - begin - digit := FPSocket.RecvByte(1000); - if (FPSocket.LastError = WSAETIMEDOUT) then continue; - if (FPSocket.LastError <> 0) then - rxState := RX_ERROR - else - begin - remainingLengthx := remainingLengthx + (digit and 127) * multiplier; - if (digit and 128) > 0 then - begin - multiplier := multiplier * 128; - rxState := RX_LENGTH; - end - else - rxState := RX_DATA; - end; - end; - RX_DATA: - begin - SetLength(CurrentMessage.Data, remainingLengthx); - FPSocket.RecvBufferEx(Pointer(CurrentMessage.Data), remainingLengthx, 1000); - if (FPSocket.LastError <> 0) then - rxState := RX_ERROR - else - begin - HandleData; - rxState := RX_FIXED_HEADER; - end; - end; - RX_ERROR: - begin - // Quit the loop, terminating the thread. - break; - end; - end; - end; - finally - FPSocket.CloseSocket(); - FreeAndNil(FPSocket); - end; // try - end; - - procedure TMQTTReadThread.HandleData; - - var - MessageType: Byte; - DataLen: integer; - QoS: integer; - Retain: boolean; - Topic: ansistring; - Payload: ansistring; - ResponseVH: TBytes; - ConnectReturn: Integer; +constructor TMQTTReadThread.Create(HostName: ansistring; Port: integer); +begin + inherited Create(True); + + // Create a Default ClientID as a default. Can be overridden with TMQTTClient.ClientID any time before connection. + FClientID := 'dMQTTClientx' + IntToStr(Random(1000) + 1); + FHostname := Hostname; + FPort := Port; + FreeOnTerminate := True; +end; + +procedure TMQTTReadThread.Execute; +var + rxState: TRxStates; + remainingLengthx: integer; + digit: integer; + multiplier: integer; + Data: TBytes; + RL: TRemainingLength; + VH: TBytes; + FH: byte; + Payload: TUTF8Text; + error: integer; +begin + rxState := RX_START; + try + // Create a socket. + FPSocket := TTCPBlockSocket.Create; + FPSocket.nonBlockMode := True; // We really don't want sending on + FPSocket.NonblockSendTimeout := 1; + // the socket to block our main thread. + while not self.Terminated do begin - if (CurrentMessage.FixedHeader <> 0) then + case rxState of + RX_START: begin - MessageType := CurrentMessage.FixedHeader shr 4; - - if (MessageType = Ord(MQTT.CONNACK)) then + // Make the socket connection + FPSocket.Connect(FHostname, IntToStr(FPort)); + + // Build CONNECT message + FH := FixedHeader(MQTT.CONNECT, 0, 0, 0); + VH := VariableHeaderConnect(40); + SetLength(Payload, 0); + AppendArray(Payload, StrToBytes(FClientID, True)); + AppendArray(Payload, StrToBytes('lwt', True)); + AppendArray(Payload, StrToBytes(FClientID + ' died', True)); + RL := RemainingLength(Length(VH) + Length(Payload)); + Data := BuildCommand(FH, RL, VH, Payload); + + writeln('RX_START: ', FPSocket.LastErrorDesc); + writeln('RX_START: ', FPSocket.LastError); + + //sleep(1); + + // Send CONNECT message + while not self.Terminated do + begin + writeln('loop...'); + SocketWrite(Data); + error := FPSocket.LastError; + writeln('RX_START: ', FPSocket.LastErrorDesc); + writeln('RX_START: ', error); + if error = 0 then begin - // Check if we were given a Connect Return Code. - // Any return code except 0 is an Error - if ((Length(CurrentMessage.Data) > 0) and (Length(CurrentMessage.Data) < 4)) then - begin - ConnectReturn := CurrentMessage.Data[1]; - if Assigned(OnConnAck) then OnConnAck(Self, ConnectReturn); - end; + rxState := RX_FIXED_HEADER; + break; end - else - if (MessageType = Ord(MQTT.PUBLISH)) then + else + begin + if error = 110 then begin - Retain := GetBit(CurrentMessage.FixedHeader, 0); - // Read the Length Bytes - DataLen := BytesToStrLength(Copy(CurrentMessage.Data, 0, 2)); - // Get the Topic - SetString(Topic, PChar(@CurrentMessage.Data[2]), DataLen); - // Get the Payload - SetString(Payload, PChar(@CurrentMessage.Data[2 + DataLen]), - (Length(CurrentMessage.Data) - 2 - DataLen)); - if Assigned(OnPublish) then OnPublish(Self, Topic, Payload, retain); - end + continue; + end; + rxState := RX_ERROR; + break; + end; + end; + end; + RX_FIXED_HEADER: + begin + multiplier := 1; + remainingLengthx := 0; + CurrentMessage.Data := nil; + + CurrentMessage.FixedHeader := FPSocket.RecvByte(1000); + if (FPSocket.LastError = WSAETIMEDOUT) then + continue; + if (FPSocket.LastError <> 0) then + rxState := RX_ERROR else - if (MessageType = Ord(MQTT.SUBACK)) then - begin - // Reading the Message ID - ResponseVH := Copy(CurrentMessage.Data, 0, 2); - DataLen := BytesToStrLength(ResponseVH); - // Next Read the Granted QoS - QoS := 0; - if (Length(CurrentMessage.Data) - 2) > 0 then - begin - ResponseVH := Copy(CurrentMessage.Data, 2, 1); - QoS := ResponseVH[0]; - end; - if Assigned(OnSubAck) then OnSubAck(Self, DataLen, QoS); - end + rxState := RX_LENGTH; + end; + RX_LENGTH: + begin + digit := FPSocket.RecvByte(1000); + if (FPSocket.LastError = WSAETIMEDOUT) then + continue; + if (FPSocket.LastError <> 0) then + rxState := RX_ERROR else - if (MessageType = Ord(MQTT.UNSUBACK)) then - begin - // Read the Message ID for the event handler - ResponseVH := Copy(CurrentMessage.Data, 0, 2); - DataLen := BytesToStrLength(ResponseVH); - if Assigned(OnUnSubAck) then OnUnSubAck(Self, DataLen); - end + begin + remainingLengthx := + remainingLengthx + (digit and 127) * multiplier; + if (digit and 128) > 0 then + begin + multiplier := multiplier * 128; + rxState := RX_LENGTH; + end + else + rxState := RX_DATA; + end; + end; + RX_DATA: + begin + SetLength(CurrentMessage.Data, remainingLengthx); + FPSocket.RecvBufferEx(Pointer(CurrentMessage.Data), + remainingLengthx, 1000); + if (FPSocket.LastError <> 0) then + rxState := RX_ERROR else - if (MessageType = Ord(MQTT.PINGRESP)) then - begin - if Assigned(OnPingResp) then OnPingResp(Self); - end; + begin + HandleData; + rxState := RX_FIXED_HEADER; + end; end; + RX_ERROR: + begin + // Quit the loop, terminating the thread. + break; + end; + end; end; - - function TMQTTReadThread.BytesToStrLength(LengthBytes: TBytes): integer; - begin - Assert(Length(LengthBytes) = 2, - - - - 'TMQTTReadThread: UTF-8 Length Bytes preceeding the text must be 2 Bytes in Legnth' - ); - - Result := 0; - Result := LengthBytes[0] shl 8; - Result := Result + LengthBytes[1]; - end; - - function TMQTTReadThread.SocketWrite(Data: TBytes): boolean; - - var - sentData: integer; + finally + FPSocket.CloseSocket(); + FreeAndNil(FPSocket); + end; // try +end; + +procedure TMQTTReadThread.HandleData; +var + MessageType: byte; + DataLen: integer; + QoS: integer; + Retain: boolean; + Topic: ansistring; + Payload: ansistring; + ResponseVH: TBytes; + ConnectReturn: integer; +begin + if (CurrentMessage.FixedHeader <> 0) then + begin + MessageType := CurrentMessage.FixedHeader shr 4; + + if (MessageType = Ord(MQTT.CONNACK)) then begin - Result := False; - // Returns whether the Data was successfully written to the socket. - - while not FPSocket.CanWrite(0) do + // Check if we were given a Connect Return Code. + // Any return code except 0 is an Error + if ((Length(CurrentMessage.Data) > 0) and + (Length(CurrentMessage.Data) < 4)) then begin - sleep(100); + ConnectReturn := CurrentMessage.Data[1]; + if Assigned(OnConnAck) then + OnConnAck(Self, ConnectReturn); end; + end + else + if (MessageType = Ord(MQTT.PUBLISH)) then + begin + Retain := GetBit(CurrentMessage.FixedHeader, 0); + // Read the Length Bytes + DataLen := BytesToStrLength(Copy(CurrentMessage.Data, 0, 2)); + // Get the Topic + SetString(Topic, PChar(@CurrentMessage.Data[2]), DataLen); + // Get the Payload + SetString(Payload, PChar(@CurrentMessage.Data[2 + DataLen]), + (Length(CurrentMessage.Data) - 2 - DataLen)); + if Assigned(OnPublish) then + OnPublish(Self, Topic, Payload, retain); + end + else + if (MessageType = Ord(MQTT.SUBACK)) then + begin + // Reading the Message ID + ResponseVH := Copy(CurrentMessage.Data, 0, 2); + DataLen := BytesToStrLength(ResponseVH); + // Next Read the Granted QoS + QoS := 0; + if (Length(CurrentMessage.Data) - 2) > 0 then + begin + ResponseVH := Copy(CurrentMessage.Data, 2, 1); + QoS := ResponseVH[0]; + end; + if Assigned(OnSubAck) then + OnSubAck(Self, DataLen, QoS); + end + else + if (MessageType = Ord(MQTT.UNSUBACK)) then + begin + // Read the Message ID for the event handler + ResponseVH := Copy(CurrentMessage.Data, 0, 2); + DataLen := BytesToStrLength(ResponseVH); + if Assigned(OnUnSubAck) then + OnUnSubAck(Self, DataLen); + end + else + if (MessageType = Ord(MQTT.PINGRESP)) then + begin + if Assigned(OnPingResp) then + OnPingResp(Self); + end; + end; +end; + +function TMQTTReadThread.BytesToStrLength(LengthBytes: TBytes): integer; +begin + Assert(Length(LengthBytes) = 2, + 'TMQTTReadThread: UTF-8 Length Bytes preceeding the text must be 2 Bytes in Legnth'); + + Result := 0; + Result := LengthBytes[0] shl 8; + Result := Result + LengthBytes[1]; +end; + +function TMQTTReadThread.SocketWrite(Data: TBytes): boolean; +var + sentData: integer; +begin + Result := False; + // Returns whether the Data was successfully written to the socket. + + while not FPSocket.CanWrite(0) do + begin + sleep(100); + end; - sentData := FPSocket.SendBuffer(Pointer(Data), Length(Data)); - if sentData = Length(Data) then - Result := True - end; - end. + sentData := FPSocket.SendBuffer(Pointer(Data), Length(Data)); + if sentData = Length(Data) then + Result := True; +end; + +end. From d97380165448fe7ff8596a26e91da3d983b9e744 Mon Sep 17 00:00:00 2001 From: heXor Date: Sun, 17 Sep 2017 03:10:56 +0300 Subject: [PATCH 09/11] add new example, update old example. Example compiled in Lazarus 1.6 with laz_synapse package. (you can get laz_synapse in Online Package Manager or download from official site). --- examples/embeddedApp/embeddedApp.lpi | 116 ++++++++++++++ examples/embeddedApp/embeddedApp.pas | 33 +++- examples/fpcConsole/fpcConsoleMQTT.lpi | 133 ++++++++++++++++ examples/fpcConsole/fpcConsoleMQTT.pas | 201 +++++++++++++++++++++++++ 4 files changed, 475 insertions(+), 8 deletions(-) create mode 100644 examples/embeddedApp/embeddedApp.lpi create mode 100644 examples/fpcConsole/fpcConsoleMQTT.lpi create mode 100644 examples/fpcConsole/fpcConsoleMQTT.pas diff --git a/examples/embeddedApp/embeddedApp.lpi b/examples/embeddedApp/embeddedApp.lpi new file mode 100644 index 0000000..65509bf --- /dev/null +++ b/examples/embeddedApp/embeddedApp.lpi @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + <UseAppBundle Value="False"/> + <ResourceType Value="res"/> + </General> + <BuildModes Count="2"> + <Item1 Name="debug" Default="True"/> + <Item2 Name="release"> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="embeddedApp"/> + </Target> + <SearchPaths> + <OtherUnitFiles Value="..\..\TMQTTClient"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Linking> + <Debugging> + <GenerateDebugInfo Value="False"/> + </Debugging> + </Linking> + <Other> + <CustomOptions Value="-dUseCThreads"/> + </Other> + </CompilerOptions> + </Item2> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + <RunParams> + <local> + <FormatVersion Value="1"/> + </local> + </RunParams> + <RequiredPackages Count="1"> + <Item1> + <PackageName Value="laz_synapse"/> + </Item1> + </RequiredPackages> + <Units Count="3"> + <Unit0> + <Filename Value="embeddedApp.pas"/> + <IsPartOfProject Value="True"/> + </Unit0> + <Unit1> + <Filename Value="..\..\TMQTTClient\MQTT.pas"/> + <IsPartOfProject Value="True"/> + </Unit1> + <Unit2> + <Filename Value="..\..\TMQTTClient\MQTTReadThread.pas"/> + <IsPartOfProject Value="True"/> + </Unit2> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="embeddedApp"/> + </Target> + <SearchPaths> + <OtherUnitFiles Value="..\..\TMQTTClient"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <IncludeAssertionCode Value="True"/> + </SyntaxOptions> + </Parsing> + <CodeGeneration> + <Checks> + <IOChecks Value="True"/> + <RangeChecks Value="True"/> + <OverflowChecks Value="True"/> + </Checks> + <VerifyObjMethodCallValidity Value="True"/> + </CodeGeneration> + <Linking> + <Debugging> + <UseHeaptrc Value="True"/> + <TrashVariables Value="True"/> + </Debugging> + </Linking> + <Other> + <CustomOptions Value="-dUseCThreads"/> + </Other> + </CompilerOptions> + <Debugging> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/examples/embeddedApp/embeddedApp.pas b/examples/embeddedApp/embeddedApp.pas index c1809a3..e392afb 100644 --- a/examples/embeddedApp/embeddedApp.pas +++ b/examples/embeddedApp/embeddedApp.pas @@ -38,10 +38,20 @@ // cthreads is required to get the MQTTReadThread working. -uses cthreads, Classes, MQTT, sysutils; +uses + {$IFDEF UNIX} {$IFDEF UseCThreads} + cthreads, {$ENDIF} {$ENDIF} + Classes, MQTT, laz_synapse, sysutils; // The major states of the application. +const + pubTimerInterval = 60*10; // 60 - 1 minute + pingTimerInterval = 10*10; // 10 - ping every 10 sec + MQTT_Server = '192.168.1.19'; + MQTT_Topic = '/jack/says'; + //MQTT_Server = '192.168.0.26'; + type TembeddedAppStates = ( CONNECT, WAIT_CONNECT, @@ -53,7 +63,7 @@ // Define class for the embedded application TembeddedApp = object strict - private + private MQTTClient: TMQTTClient; pingCounter : integer; pingTimer : integer; @@ -61,7 +71,8 @@ message : ansistring; pubTimer : integer; connectTimer : integer; - public + public + terminate: boolean; procedure run (); end; @@ -78,9 +89,9 @@ 'All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy.' ; - MQTTClient := TMQTTClient.Create('192.168.0.26', 1883); + MQTTClient := TMQTTClient.Create(MQTT_Server, 1883); - while true do + while not terminate do begin case state of CONNECT : @@ -106,9 +117,9 @@ RUNNING : begin // Publish stuff - if pubTimer mod 1 = 0 then + if pubTimer mod pubTimerInterval = 0 then begin - if not MQTTClient.Publish('/jack/says/', message) then + if not MQTTClient.Publish(MQTT_Topic, message) then begin writeln ('embeddedApp: Error: Publish Failed.'); state := FAILING; @@ -149,6 +160,9 @@ begin writeln ('getMessage: ' + msg.topic + ' Payload: ' + msg.payload); + if msg.PayLoad = 'stop' then + terminate := true; + // Important to free messages here. msg.free; end; @@ -165,7 +179,7 @@ if ack.returnCode = 0 then begin // Make subscriptions - MQTTClient.Subscribe('/jack/says/'); + MQTTClient.Subscribe(MQTT_Topic); // Enter the running state state := RUNNING; end @@ -202,6 +216,9 @@ // Yawn. sleep(100); end; + + MQTTClient.ForceDisconnect; + FreeAndNil(MQTTClient); end; var diff --git a/examples/fpcConsole/fpcConsoleMQTT.lpi b/examples/fpcConsole/fpcConsoleMQTT.lpi new file mode 100644 index 0000000..61576b1 --- /dev/null +++ b/examples/fpcConsole/fpcConsoleMQTT.lpi @@ -0,0 +1,133 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <ProjectOptions> + <Version Value="10"/> + <PathDelim Value="\"/> + <General> + <Flags> + <MainUnitHasCreateFormStatements Value="False"/> + <MainUnitHasScaledStatement Value="False"/> + </Flags> + <SessionStorage Value="InProjectDir"/> + <MainUnit Value="0"/> + <Title Value="fpcConsoleMQTT"/> + <UseAppBundle Value="False"/> + <ResourceType Value="res"/> + </General> + <BuildModes Count="2"> + <Item1 Name="debug_wnd_x86" Default="True"/> + <Item2 Name="debug_lnx_arm"> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="fpcConsoleMQTT"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value="..\..\TMQTTClient"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <IncludeAssertionCode Value="True"/> + </SyntaxOptions> + </Parsing> + <CodeGeneration> + <Checks> + <IOChecks Value="True"/> + <RangeChecks Value="True"/> + <OverflowChecks Value="True"/> + </Checks> + <VerifyObjMethodCallValidity Value="True"/> + <TargetCPU Value="arm"/> + <TargetOS Value="linux"/> + </CodeGeneration> + <Linking> + <Debugging> + <UseHeaptrc Value="True"/> + <TrashVariables Value="True"/> + </Debugging> + </Linking> + <Other> + <CustomOptions Value="-dUseCThreads"/> + </Other> + </CompilerOptions> + </Item2> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + <RunParams> + <local> + <FormatVersion Value="1"/> + </local> + </RunParams> + <RequiredPackages Count="1"> + <Item1> + <PackageName Value="laz_synapse"/> + </Item1> + </RequiredPackages> + <Units Count="3"> + <Unit0> + <Filename Value="fpcConsoleMQTT.pas"/> + <IsPartOfProject Value="True"/> + </Unit0> + <Unit1> + <Filename Value="..\..\TMQTTClient\MQTT.pas"/> + <IsPartOfProject Value="True"/> + </Unit1> + <Unit2> + <Filename Value="..\..\TMQTTClient\MQTTReadThread.pas"/> + <IsPartOfProject Value="True"/> + </Unit2> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="fpcConsoleMQTT"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value="..\..\TMQTTClient"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <IncludeAssertionCode Value="True"/> + </SyntaxOptions> + </Parsing> + <CodeGeneration> + <Checks> + <IOChecks Value="True"/> + <RangeChecks Value="True"/> + <OverflowChecks Value="True"/> + </Checks> + <VerifyObjMethodCallValidity Value="True"/> + </CodeGeneration> + <Linking> + <Debugging> + <UseHeaptrc Value="True"/> + <TrashVariables Value="True"/> + </Debugging> + </Linking> + <Other> + <CustomOptions Value="-dUseCThreads"/> + </Other> + </CompilerOptions> + <Debugging> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/examples/fpcConsole/fpcConsoleMQTT.pas b/examples/fpcConsole/fpcConsoleMQTT.pas new file mode 100644 index 0000000..75fbf3f --- /dev/null +++ b/examples/fpcConsole/fpcConsoleMQTT.pas @@ -0,0 +1,201 @@ +program fpcConsoleMQTT; + +{$mode objfpc}{$H+} + +uses {$IFDEF UNIX} {$IFDEF UseCThreads} + cthreads, {$ENDIF} {$ENDIF} + Classes, + SysUtils, + CustApp { you can add units after this }, + //old: CRT, + MQTT, + syncobjs, // TCriticalSection + fptimer; + +const + MQTT_Server = 'orangepi.lan'; + +type + { TMQTTGate } + + TMQTTGate = class(TCustomApplication) + protected + MQTTClient: TMQTTClient; + + SyncCode: TCriticalSection; + TimerTick: TFPTimer; + cnt: integer; + + // Unsafe events! Called from MQTT thread (TMQTTReadThread) + procedure OnConnAck(Sender: TObject; ReturnCode: integer); + procedure OnPingResp(Sender: TObject); + procedure OnSubAck(Sender: TObject; MessageID: integer; GrantedQoS: integer); + procedure OnUnSubAck(Sender: TObject); + procedure OnPublish(Sender: TObject; topic, payload: ansistring; isRetain: boolean); + + procedure OnTimerTick(Sender: TObject); + procedure DoRun; override; + public + procedure WriteHelp; virtual; + end; + +{old: const + { ^C } + //ContrBreakSIG = ^C; // yes, its valid string! (OMG!) + //ContrBreakSIG = #$03; +} + +function NewTimer(Intr: integer; Proc: TNotifyEvent; AEnable: boolean = false): TFPTimer; +begin + Result := TFPTimer.Create(nil); + Result.UseTimerThread:=false; + Result.Interval := Intr; + Result.OnTimer := Proc; + Result.Enabled := AEnable; +end; + +{ TMQTTGate } + +procedure TMQTTGate.OnConnAck(Sender: TObject; ReturnCode: integer); +begin + SyncCode.Enter; + writeln('ConnAck'); + SyncCode.Leave; +end; + +procedure TMQTTGate.OnPingResp(Sender: TObject); +begin + SyncCode.Enter; + writeln('PingResp'); + SyncCode.Leave; +end; + +procedure TMQTTGate.OnSubAck(Sender: TObject; MessageID: integer; GrantedQoS: integer); +begin + SyncCode.Enter; + writeln('SubAck'); + SyncCode.Leave; +end; + +procedure TMQTTGate.OnUnSubAck(Sender: TObject); +begin + SyncCode.Enter; + writeln('UnSubAck'); + SyncCode.Leave; +end; + +procedure TMQTTGate.OnPublish(Sender: TObject; topic, payload: ansistring; + isRetain: boolean); +begin + SyncCode.Enter; + writeln('Publish', ' topic=', topic, ' payload=', payload); + SyncCode.Leave; +end; + +procedure TMQTTGate.OnTimerTick(Sender: TObject); +begin + SyncCode.Enter; + cnt := cnt + 1; + writeln('Tick. N='+IntToStr(cnt)); + MQTTClient.PingReq; + MQTTClient.Publish('test', IntToStr(cnt)); + SyncCode.Leave; +end; + +procedure TMQTTGate.DoRun; +var + ErrorMsg: string; +begin + StopOnException := True; + SyncCode := TCriticalSection.Create(); + + // quick check parameters + ErrorMsg := CheckOptions('h', 'help'); + if ErrorMsg <> '' then + begin + ShowException(Exception.Create(ErrorMsg)); + Terminate; + Exit; + end; + + // parse parameters + if HasOption('h', 'help') then + begin + WriteHelp; + Terminate; + Exit; + end; + + // begin main program + MQTTClient := TMQTTClient.Create(MQTT_Server, 1883); + MQTTClient.OnConnAck := @OnConnAck; + MQTTClient.OnPingResp := @OnPingResp; + MQTTClient.OnPublish := @OnPublish; + MQTTClient.OnSubAck := @OnSubAck; + MQTTClient.Connect(); + + //todo: wait 'OnConnAck' + Sleep(1000); + if not MQTTClient.isConnected then + begin + writeln('connect FAIL'); + exit; + end; + + // mqtt subscribe to all topics + MQTTClient.Subscribe('#'); + + cnt := 0; + TimerTick := NewTimer(5000, @OnTimerTick, true); + try + while (not Terminated) and (MQTTClient.isConnected) do + begin + // wait other thread + CheckSynchronize(1000); + + //old: Check for ctrl-c + {if KeyPressed then // <--- CRT function to test key press + if ReadKey = ContrBreakSIG then // read the key pressed + begin + writeln('Ctrl-C pressed.'); + Terminate; + end;} + end; + + MQTTClient.Unsubscribe('#'); + MQTTClient.Disconnect; + Sleep(100); + MQTTClient.ForceDisconnect; + finally + FreeAndNil(TimerTick); + FreeAndNil(MQTTClient); + FreeAndNil(SyncCode); + Sleep(2000); // wait thread dies + end; + // stop program loop + Terminate; +end; + +procedure TMQTTGate.WriteHelp; +begin + { add your help code here } + writeln('Usage: ', ExeName, ' -h'); +end; + +var + Application: TMQTTGate; + +function MyCtrlBreakHandler(CtrlBr: boolean): boolean; +begin + writeln('CtrlBreak pressed. Terminating.'); + Application.Terminate; + Result := true; +end; + +begin + SysSetCtrlBreakHandler(@MyCtrlBreakHandler); + Application := TMQTTGate.Create(nil); + Application.Run; + Application.Free; +end. + From 1b53f70334e3fe53ad820d7e58bc484ad21040ac Mon Sep 17 00:00:00 2001 From: Pascal TONIN <pascal.tonin@wit.fr> Date: Tue, 18 Dec 2018 11:32:33 +0100 Subject: [PATCH 10/11] Added Monitor event --- TMQTTClient/MQTT.pas | 22 +++++++++++++++++++--- TMQTTClient/MQTTReadThread.pas | 25 ++++++++++++++++++++----- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/TMQTTClient/MQTT.pas b/TMQTTClient/MQTT.pas index 4e6a008..4b959ae 100644 --- a/TMQTTClient/MQTT.pas +++ b/TMQTTClient/MQTT.pas @@ -115,6 +115,7 @@ TMQTTClient = class(TObject) FPingRespEvent: TPingRespEvent; FSubAckEvent: TSubAckEvent; FUnSubAckEvent: TUnSubAckEvent; + FOnMonitorEvent: TMonitorEvent; FCritical: TRTLCriticalSection; FMessageQueue: TQueue; @@ -137,6 +138,7 @@ TMQTTClient = class(TObject) procedure OnRTPublish(Sender: TObject; topic, payload: ansistring; retain: boolean); procedure OnRTTerminate(Sender: TObject); + procedure Monitor(const TheIsRead, TheIsError: boolean; TheArgs: array of const); public function isConnected: boolean; @@ -160,6 +162,7 @@ TMQTTClient = class(TObject) property OnPingResp: TPingRespEvent read FPingRespEvent write FPingRespEvent; property OnSubAck: TSubAckEvent read FSubAckEvent write FSubAckEvent; property OnUnSubAck: TUnSubAckEvent read FUnSubAckEvent write FUnSubAckEvent; + property OnMonitorEvent: TMonitorEvent read FOnMonitorEvent write FOnMonitorEvent; end; // Message Component Build helpers @@ -237,6 +240,7 @@ procedure TMQTTClient.Connect; FReadThread.OnPingResp := @OnRTPingResp; FReadThread.OnSubAck := @OnRTSubAck; FReadThread.OnTerminate := @OnRTTerminate; + FReadThread.OnMonitor := OnMonitorEvent; FReadThread.Start; FReaderThreadRunning := True; end; @@ -251,7 +255,8 @@ function TMQTTClient.Disconnect: boolean; var Data: TBytes; begin - writeln('TMQTTClient.Disconnect'); + // writeln('TMQTTClient.Disconnect'); + Monitor(false, false, ['Disconnect']); Result := False; SetLength(Data, 2); @@ -286,7 +291,8 @@ function TMQTTClient.Disconnect: boolean; ------------------------------------------------------------------------------*} procedure TMQTTClient.ForceDisconnect; begin - writeln('TMQTTClient.ForceDisconnect'); + // writeln('TMQTTClient.ForceDisconnect'); + Monitor(false, false, ['ForceDisconnect']); if FReadThread <> nil then begin FReadThread.OnTerminate := nil; @@ -311,7 +317,17 @@ procedure TMQTTClient.OnRTTerminate(Sender: TObject); FReadThread := nil; FReaderThreadRunning := False; FisConnected := False; - WriteLn('TMQTTClient.OnRTTerminate: Thread.Terminated.'); + // WriteLn('TMQTTClient.OnRTTerminate: Thread.Terminated.'); + Monitor(false, false, ['Thread.Terminated']); +end; + +{*------------------------------------------------------------------------------ + Raise a monitor event. +------------------------------------------------------------------------------*} +procedure TMQTTClient.Monitor(const TheIsRead, TheIsError: boolean; TheArgs: array of const); +begin + if Assigned(FOnMonitorEvent) then FOnMonitorEvent(TheIsRead,TheIsError,TheArgs); + end; {*------------------------------------------------------------------------------ diff --git a/TMQTTClient/MQTTReadThread.pas b/TMQTTClient/MQTTReadThread.pas index e4fde70..2eda1ba 100644 --- a/TMQTTClient/MQTTReadThread.pas +++ b/TMQTTClient/MQTTReadThread.pas @@ -68,6 +68,7 @@ TMQTTMessage = record TSubAckEvent = procedure(Sender: TObject; MessageID: integer; GrantedQoS: integer) of object; TUnSubAckEvent = procedure(Sender: TObject; MessageID: integer) of object; + TMonitorEvent = procedure(const TheIsRead, TheIsError: boolean; TheArgs: array of const) of object; TMQTTReadThread = class(TThread) private @@ -82,6 +83,7 @@ TMQTTReadThread = class(TThread) FPingRespEvent: TPingRespEvent; FSubAckEvent: TSubAckEvent; FUnSubAckEvent: TUnSubAckEvent; + FOnMonitorEvent: TMonitorEvent; // Takes a 2 Byte Length array and returns the length of the ansistring it preceeds as per the spec. function BytesToStrLength(LengthBytes: TBytes): integer; @@ -102,6 +104,8 @@ TMQTTReadThread = class(TThread) property OnPingResp: TPingRespEvent read FPingRespEvent write FPingRespEvent; property OnSubAck: TSubAckEvent read FSubAckEvent write FSubAckEvent; property OnUnSubAck: TUnSubAckEvent read FUnSubAckEvent write FUnSubAckEvent; + property OnMonitor: TMonitorEvent read FOnMonitorEvent write FOnMonitorEvent; + procedure Monitor(const TheIsRead, TheIsError: boolean; TheArgs: array of const); end; implementation @@ -134,6 +138,12 @@ constructor TMQTTReadThread.Create(HostName: ansistring; Port: integer); FreeOnTerminate := True; end; +procedure TMQTTReadThread.Monitor(const TheIsRead, TheIsError: boolean; TheArgs: array of const); +begin + if Assigned(FOnMonitorEvent) then FOnMonitorEvent(TheIsRead,TheIsError,TheArgs); + +end; + procedure TMQTTReadThread.Execute; var rxState: TRxStates; @@ -172,19 +182,24 @@ procedure TMQTTReadThread.Execute; RL := RemainingLength(Length(VH) + Length(Payload)); Data := BuildCommand(FH, RL, VH, Payload); - writeln('RX_START: ', FPSocket.LastErrorDesc); - writeln('RX_START: ', FPSocket.LastError); + //writeln('RX_START: ', FPSocket.LastErrorDesc); + Monitor(true, Length(FPSocket.LastErrorDesc) > 0, ['RX_START: ', FPSocket.LastErrorDesc]); + //writeln('RX_START: ', FPSocket.LastError); + Monitor(true, FPSocket.LastError > 0, ['RX_START: ', FPSocket.LastError]); //sleep(1); // Send CONNECT message while not self.Terminated do begin - writeln('loop...'); + // writeln('loop...'); + Monitor(false, false, ['loop']); SocketWrite(Data); error := FPSocket.LastError; - writeln('RX_START: ', FPSocket.LastErrorDesc); - writeln('RX_START: ', error); + //writeln('RX_START: ', FPSocket.LastErrorDesc); + Monitor(true, Length(FPSocket.LastErrorDesc) > 0, ['RX_START: ', FPSocket.LastErrorDesc]); + //writeln('RX_START: ', error); + Monitor(true, error > 0, ['RX_START: ', error]); if error = 0 then begin rxState := RX_FIXED_HEADER; From 83a96fc1e7c058e7ce4fa0fcbdc252724df6acc5 Mon Sep 17 00:00:00 2001 From: Pascal TONIN <pascal.tonin@wit.fr> Date: Tue, 18 Dec 2018 11:32:42 +0100 Subject: [PATCH 11/11] Added mosca test project with npm --- .gitignore | 3 +- package-lock.json | 3713 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 27 + test/broker.js | 24 + 4 files changed, 3766 insertions(+), 1 deletion(-) create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 test/broker.js diff --git a/.gitignore b/.gitignore index cd816b5..454ff22 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,5 @@ bin/* examples/embeddedApp/embeddedApp backup lib -*.lps \ No newline at end of file +*.lps +node_modules \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..b5eaba0 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3713 @@ +{ + "name": "mqtt-fpc-sdk", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "abstract-leveldown": { + "version": "0.12.4", + "resolved": "http://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-0.12.4.tgz", + "integrity": "sha1-KeGOYy5g5OIh1YECR4UqY9ey5BA=", + "dev": true, + "requires": { + "xtend": "~3.0.0" + }, + "dependencies": { + "xtend": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", + "integrity": "sha1-XM50B7r2Qsunvs2laBEcST9ZZlo=", + "dev": true + } + } + }, + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", + "dev": true, + "optional": true + }, + "ajv": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.2.tgz", + "integrity": "sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "amqp": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/amqp/-/amqp-0.2.7.tgz", + "integrity": "sha1-c4z8Rf2cmSYLRdX6/DLtAAhB4bE=", + "dev": true, + "optional": true, + "requires": { + "lodash": "^4.0.0" + } + }, + "amqplib": { + "version": "0.4.2", + "resolved": "http://registry.npmjs.org/amqplib/-/amqplib-0.4.2.tgz", + "integrity": "sha1-XkoqkUzLMSX5y5H22gfJeqTLE6Y=", + "dev": true, + "optional": true, + "requires": { + "bitsyntax": "~0.0.4", + "buffer-more-ints": "0.0.2", + "readable-stream": "1.x >=1.1.9", + "when": "~3.6.2" + } + }, + "ansi": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz", + "integrity": "sha1-DELU+xcWDVqa8eSEus4cZpIsGyE=", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "array-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", + "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", + "dev": true + }, + "array-index": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-index/-/array-index-1.0.0.tgz", + "integrity": "sha1-7FanSe4QPk4Ix5C5w1PfFgVbl/k=", + "dev": true, + "requires": { + "debug": "^2.2.0", + "es6-symbol": "^3.0.2" + } + }, + "ascoltatori": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ascoltatori/-/ascoltatori-3.2.0.tgz", + "integrity": "sha1-FoO9h+MIpzyRjjuZqyaDsCU8iWc=", + "dev": true, + "requires": { + "amqp": "~0.2.4", + "amqplib": "~0.4.1", + "debug": "^2.2.0", + "eventemitter2": "^2.1.3", + "ioredis": "^2.3.0", + "kafka-node": "~0.5.8", + "kerberos": "~0.0", + "mongodb": "^2.1.18", + "mqtt": "^1.10.0", + "msgpack-lite": "^0.1.20", + "node-uuid": "~1.4.3", + "qlobber": "~0.7.0", + "qlobber-fsq": "~3.2.4", + "steed": "^1.1.3", + "zmq": "^2.14.0" + }, + "dependencies": { + "ioredis": { + "version": "2.5.0", + "resolved": "http://registry.npmjs.org/ioredis/-/ioredis-2.5.0.tgz", + "integrity": "sha1-+2/fChp+CXRhTGe25eETCKjPlbk=", + "dev": true, + "optional": true, + "requires": { + "bluebird": "^3.3.4", + "cluster-key-slot": "^1.0.6", + "debug": "^2.2.0", + "double-ended-queue": "^2.1.0-0", + "flexbuffer": "0.0.6", + "lodash": "^4.8.2", + "redis-commands": "^1.2.0", + "redis-parser": "^1.3.0" + } + } + } + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "async": { + "version": "1.5.2", + "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true, + "optional": true + }, + "async-cache": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/async-cache/-/async-cache-1.1.0.tgz", + "integrity": "sha1-SppaidBl7F2OUlS9nulrp2xTK1o=", + "dev": true, + "requires": { + "lru-cache": "^4.0.0" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", + "dev": true, + "optional": true, + "requires": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + } + }, + "bindings": { + "version": "1.2.1", + "resolved": "http://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz", + "integrity": "sha1-FK1hE4EtLTfXLme0ystLtyZQXxE=", + "dev": true, + "optional": true + }, + "bitsyntax": { + "version": "0.0.4", + "resolved": "http://registry.npmjs.org/bitsyntax/-/bitsyntax-0.0.4.tgz", + "integrity": "sha1-6xDMb4K4xJDj6FaY8H6D1G4MuoI=", + "dev": true, + "optional": true, + "requires": { + "buffer-more-ints": "0.0.2" + } + }, + "bl": { + "version": "1.2.2", + "resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "dev": true, + "requires": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "dev": true, + "requires": { + "inherits": "~2.0.0" + } + }, + "bluebird": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", + "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==", + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "brfs": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/brfs/-/brfs-1.4.4.tgz", + "integrity": "sha512-rX2qc9hkpLPiwdu1HkLY642rwwo3X6N+ZPyEPdNn3OUKV/B2BRP7dHdnkhGantOJLVoTluNYBi4VecHb2Kq2hw==", + "dev": true, + "requires": { + "quote-stream": "^1.0.1", + "resolve": "^1.1.5", + "static-module": "^2.1.1", + "through2": "^2.0.0" + } + }, + "bson": { + "version": "0.4.23", + "resolved": "http://registry.npmjs.org/bson/-/bson-0.4.23.tgz", + "integrity": "sha1-5louPHUH/63kEJvHV1p25Q+NqRU=", + "dev": true, + "optional": true + }, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dev": true, + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "dev": true, + "optional": true + }, + "buffer-equal": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", + "integrity": "sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs=", + "dev": true + }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", + "dev": true + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "buffer-more-ints": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-0.0.2.tgz", + "integrity": "sha1-JrOIXRD6E9t/wBquOquHAZngEkw=", + "dev": true + }, + "buffermaker": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffermaker/-/buffermaker-1.2.0.tgz", + "integrity": "sha1-u3MlLsCIK3Y56bVWuCnav8LK4bo=", + "dev": true, + "optional": true, + "requires": { + "long": "1.1.2" + } + }, + "buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", + "dev": true, + "optional": true + }, + "bytewise": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/bytewise/-/bytewise-1.1.0.tgz", + "integrity": "sha1-HRPL/3F65xWAlKqIGzXQgbOHJT4=", + "dev": true, + "requires": { + "bytewise-core": "^1.2.2", + "typewise": "^1.0.3" + } + }, + "bytewise-core": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bytewise-core/-/bytewise-core-1.2.3.tgz", + "integrity": "sha1-P7QQx+kVWOsasiqCg0V3qmvWHUI=", + "dev": true, + "requires": { + "typewise-core": "^1.2" + } + }, + "callback-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/callback-stream/-/callback-stream-1.1.0.tgz", + "integrity": "sha1-RwGlEmbwbgbqpx/BcjOCLYdfSQg=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "> 1.0.0 < 3.0.0" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", + "dev": true, + "optional": true, + "requires": { + "traverse": ">=0.3.0 <0.4" + } + }, + "chalk": { + "version": "1.1.3", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "chownr": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", + "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", + "dev": true, + "optional": true + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + }, + "cluster-key-slot": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.0.12.tgz", + "integrity": "sha512-21O0kGmvED5OJ7ZTdqQ5lQQ+sjuez33R+d35jZKLwqUb5mqcPHUsxOSzj61+LHVtxGZd1kShbQM3MjB/gBJkVg==", + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "combined-stream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.9.0", + "resolved": "http://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "requires": { + "graceful-readlink": ">= 1.0.0" + } + }, + "commist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/commist/-/commist-1.0.0.tgz", + "integrity": "sha1-wMNSUBz29S6RJOPvicmAbiAi6+8=", + "dev": true, + "requires": { + "leven": "^1.0.0", + "minimist": "^1.1.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "d": { + "version": "1.0.0", + "resolved": "http://registry.npmjs.org/d/-/d-1.0.0.tgz", + "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "dev": true, + "requires": { + "es5-ext": "^0.10.9" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "optional": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "deepcopy": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/deepcopy/-/deepcopy-0.6.3.tgz", + "integrity": "sha1-Y0eA8vhlardxr4+oQx7RzO5Vx7A=", + "dev": true + }, + "deferred-leveldown": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-0.2.0.tgz", + "integrity": "sha1-LO8fER4cV4cNi7uK8mUOWHzS9bQ=", + "dev": true, + "requires": { + "abstract-leveldown": "~0.12.1" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "double-ended-queue": { + "version": "2.1.0-0", + "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz", + "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=", + "dev": true, + "optional": true + }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "dev": true, + "requires": { + "readable-stream": "^2.0.2" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "duplexify": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.1.tgz", + "integrity": "sha512-vM58DwdnKmty+FSPzT14K9JXb90H+j5emaR4KYbr2KTIz00WHGbWOe5ghQTx233ZCLZtrGDALzKwcjEtSt35mA==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "requires": { + "prr": "~1.0.1" + }, + "dependencies": { + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + } + } + }, + "es5-ext": { + "version": "0.10.46", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.46.tgz", + "integrity": "sha512-24XxRvJXNFwEMpJb3nOkiRJKRoupmjYmOPVlI65Qy2SrtxwOTB+g6ODjBKOtwEHbYrhWRty9xxOWLNdClT2djw==", + "dev": true, + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.1", + "next-tick": "1" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-promise": { + "version": "3.0.2", + "resolved": "http://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", + "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=", + "dev": true, + "optional": true + }, + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "escodegen": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.9.1.tgz", + "integrity": "sha512-6hTjO1NAWkHnDk3OqQ4YrCuwwmGHL9S3nPlzBOUG/R44rda3wLNrfvQ5fkSGjyhHFKM7ALPKcKGrwvCLe0lC7Q==", + "dev": true, + "requires": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + } + }, + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "event-lite": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/event-lite/-/event-lite-0.1.2.tgz", + "integrity": "sha512-HnSYx1BsJ87/p6swwzv+2v6B4X+uxUteoDfRxsAb1S1BePzQqOLevVmkdA15GHJVd9A9Ok6wygUR18Hu0YeV9g==", + "dev": true, + "optional": true + }, + "eventemitter2": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-2.2.2.tgz", + "integrity": "sha1-QH6nHCAgzVdTggOrfnpr3Pt2ktU=", + "dev": true, + "optional": true + }, + "execspawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/execspawn/-/execspawn-1.0.1.tgz", + "integrity": "sha1-gob53efOzeeQX73ATiTzaPI/jaY=", + "dev": true, + "optional": true, + "requires": { + "util-extend": "^1.0.1" + } + }, + "expand-template": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-1.1.1.tgz", + "integrity": "sha512-cebqLtV8KOZfw0UI8TEFWxtczxxC1jvyUvx6H4fyp1K1FN7A4Q+uggVUlOsI1K8AGU0rwOGqP8nCapdrw8CYQg==", + "dev": true, + "optional": true + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "falafel": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/falafel/-/falafel-2.1.0.tgz", + "integrity": "sha1-lrsXdh2rqU9G0AFzizzt86Z/4Gw=", + "dev": true, + "requires": { + "acorn": "^5.0.0", + "foreach": "^2.0.5", + "isarray": "0.0.1", + "object-keys": "^1.0.6" + } + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "fast-future": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fast-future/-/fast-future-1.0.2.tgz", + "integrity": "sha1-hDWpqqAteSSNF9cE52JZMB2ZKAo=", + "dev": true, + "optional": true + }, + "fast-json-parse": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz", + "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fast-safe-stringify": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-1.2.3.tgz", + "integrity": "sha512-QJYT/i0QYoiZBQ71ivxdyTqkwKkQ0oxACXHYxH2zYHJEgzi2LsbjgvtzTbLi1SZcF190Db2YP7I7eTsU2egOlw==", + "dev": true + }, + "fastfall": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/fastfall/-/fastfall-1.5.1.tgz", + "integrity": "sha1-P+4DMxpJ0dObPN96XpzWb0dee5Q=", + "dev": true, + "requires": { + "reusify": "^1.0.0" + } + }, + "fastparallel": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/fastparallel/-/fastparallel-2.3.0.tgz", + "integrity": "sha1-HnCb+2oDmT84V+POfwExHOdgJhM=", + "dev": true, + "requires": { + "reusify": "^1.0.0", + "xtend": "^4.0.1" + } + }, + "fastq": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz", + "integrity": "sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA==", + "dev": true, + "requires": { + "reusify": "^1.0.0" + } + }, + "fastseries": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/fastseries/-/fastseries-1.7.2.tgz", + "integrity": "sha1-0izhO5Qz3/M4jZHb1ri9qbIaD0s=", + "dev": true, + "requires": { + "reusify": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "fd": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/fd/-/fd-0.0.3.tgz", + "integrity": "sha512-iAHrIslQb3U68OcMSP0kkNWabp7sSN6d2TBSb2JO3gcLJVDd4owr/hKM4SFJovFOUeeXeItjYgouEDTMWiVAnA==", + "dev": true + }, + "flatstr": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.9.tgz", + "integrity": "sha512-qFlJnOBWDfIaunF54/lBqNKmXOI0HqNhu+mHkLmbaBXlS71PUd9OjFOdyevHt/aHoHB1+eW7eKHgRKOG5aHSpw==", + "dev": true + }, + "flexbuffer": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/flexbuffer/-/flexbuffer-0.0.6.tgz", + "integrity": "sha1-A5/fI/iCPkQMOPMnfm/vEXQhWzA=", + "dev": true, + "optional": true + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "fs-ext": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/fs-ext/-/fs-ext-0.5.0.tgz", + "integrity": "sha1-nB+aILjn4BLgqRS14ZEyck9E9p4=", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fstream": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", + "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "gauge": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.6.0.tgz", + "integrity": "sha1-01MBrRjpaQK0dR3LvkD0IYuUKkY=", + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-color": "^0.1.7", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "ghreleases": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/ghreleases/-/ghreleases-1.0.7.tgz", + "integrity": "sha512-1lFGyLLF38Q6cFCDyebN5vzQ2P9DEaAgxPIDLmQwQDVDmUe2Wgv+6dhAIoHeA+My4HLpaJ+dKF73xtuykN2cbQ==", + "dev": true, + "optional": true, + "requires": { + "after": "~0.8.1", + "ghrepos": "~2.1.0", + "ghutils": "~3.2.0", + "simple-mime": "~0.1.0", + "url-template": "~2.0.6", + "xtend": "~4.0.0" + } + }, + "ghrepos": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ghrepos/-/ghrepos-2.1.0.tgz", + "integrity": "sha512-6GM0ohSDTAv7xD6GsKfxJiV/CajoofRyUwu0E8l29d1o6lFAUxmmyMP/FH33afA20ZrXzxxcTtN6TsYvudMoAg==", + "dev": true, + "optional": true, + "requires": { + "ghutils": "~3.2.0" + } + }, + "ghutils": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/ghutils/-/ghutils-3.2.6.tgz", + "integrity": "sha512-WpYHgLQkqU7Cv147wKUEThyj6qKHCdnAG2CL9RRsRQImVdLGdVqblJ3JUnj3ToQwgm1ALPS+FXgR0448AgGPUg==", + "dev": true, + "requires": { + "jsonist": "~2.1.0", + "xtend": "~4.0.1" + } + }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", + "dev": true, + "optional": true + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "glob-stream": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", + "dev": true, + "requires": { + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "dev": true + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "dev": true, + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-color": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", + "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=", + "dev": true, + "optional": true + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "help-me": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-1.1.0.tgz", + "integrity": "sha1-jy1QjQYAtKRW2i8IZVbn5cBWo8Y=", + "dev": true, + "requires": { + "callback-stream": "^1.0.2", + "glob-stream": "^6.1.0", + "through2": "^2.0.1", + "xtend": "^4.0.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "hyperquest": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/hyperquest/-/hyperquest-2.1.3.tgz", + "integrity": "sha512-fUuDOrB47PqNK/BAMOS13v41UoaqIxqSLHX6CAbOD7OfT+/GCWO1/vPLfTNutOeXrv1ikuaZ3yux+33Z9vh+rw==", + "dev": true, + "requires": { + "buffer-from": "^0.1.1", + "duplexer2": "~0.0.2", + "through2": "~0.6.3" + }, + "dependencies": { + "buffer-from": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-0.1.2.tgz", + "integrity": "sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg==", + "dev": true + }, + "duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", + "dev": true, + "requires": { + "readable-stream": "~1.1.9" + } + }, + "through2": { + "version": "0.6.5", + "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "dev": true, + "requires": { + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + }, + "dependencies": { + "readable-stream": { + "version": "1.0.34", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + } + } + } + } + }, + "ieee754": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", + "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==", + "dev": true, + "optional": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true, + "optional": true + }, + "int64-buffer": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/int64-buffer/-/int64-buffer-0.1.10.tgz", + "integrity": "sha1-J3siiofZWtd30HwTgyAiQGpHNCM=", + "dev": true, + "optional": true + }, + "ioredis": { + "version": "1.15.1", + "resolved": "http://registry.npmjs.org/ioredis/-/ioredis-1.15.1.tgz", + "integrity": "sha1-UlJVzM1Ve904oO00ZhmfWesLnRw=", + "dev": true, + "optional": true, + "requires": { + "bluebird": "^2.9.34", + "debug": "^2.2.0", + "double-ended-queue": "^2.1.0-0", + "flexbuffer": "0.0.6", + "lodash": "^3.6.0" + }, + "dependencies": { + "bluebird": { + "version": "2.11.0", + "resolved": "http://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", + "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=", + "dev": true, + "optional": true + }, + "lodash": { + "version": "3.10.1", + "resolved": "http://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", + "dev": true, + "optional": true + } + } + }, + "is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "requires": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + }, + "is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", + "dev": true + }, + "is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "requires": { + "is-unc-path": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "requires": { + "unc-path-regex": "^0.1.2" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "json-buffer": { + "version": "2.0.11", + "resolved": "http://registry.npmjs.org/json-buffer/-/json-buffer-2.0.11.tgz", + "integrity": "sha1-PkQf2jCYvo0eMXGtWRvGKjPi1V8=", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "requires": { + "jsonify": "~0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "jsonist": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/jsonist/-/jsonist-2.1.0.tgz", + "integrity": "sha1-RHek0WzTd/rsWNjPhwt+OS9tf+k=", + "dev": true, + "requires": { + "bl": "~1.2.0", + "hyperquest": "~2.1.2", + "json-stringify-safe": "~5.0.1", + "xtend": "~4.0.1" + } + }, + "jsonschema": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.2.4.tgz", + "integrity": "sha512-lz1nOH69GbsVHeVgEdvyavc/33oymY1AZwtePMiMj4HZPMbP5OIKK3zT9INMWjwua/V4Z4yq7wSlBbSG+g4AEw==", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "kafka-node": { + "version": "0.5.9", + "resolved": "http://registry.npmjs.org/kafka-node/-/kafka-node-0.5.9.tgz", + "integrity": "sha1-mpwp0JI37okrb1ZkDg0yqAORohI=", + "dev": true, + "optional": true, + "requires": { + "async": ">0.9 <2.0", + "binary": "~0.3.0", + "buffer-crc32": "~0.2.5", + "buffermaker": "~1.2.0", + "debug": "^2.1.3", + "lodash": ">3.0 <4.0", + "minimatch": "^3.0.2", + "nested-error-stacks": "^1.0.2", + "node-uuid": "~1.4.3", + "node-zookeeper-client": "~0.2.2", + "optional": "^0.1.3", + "retry": "~0.6.1", + "snappy": "^5.0.5" + }, + "dependencies": { + "lodash": { + "version": "3.10.1", + "resolved": "http://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", + "dev": true, + "optional": true + } + } + }, + "kerberos": { + "version": "0.0.24", + "resolved": "https://registry.npmjs.org/kerberos/-/kerberos-0.0.24.tgz", + "integrity": "sha512-QO6bFq9eETHB5zcA0OJiQtw137TH45OuUcGtI+QGg2ZJQIPCvwXL2kjCqZZMColcIdbPhj4X40EY5f3oOiBfiw==", + "dev": true, + "optional": true, + "requires": { + "nan": "~2.10.0" + }, + "dependencies": { + "nan": { + "version": "2.10.0", + "resolved": "http://registry.npmjs.org/nan/-/nan-2.10.0.tgz", + "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", + "dev": true, + "optional": true + } + } + }, + "level-codec": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-7.0.1.tgz", + "integrity": "sha512-Ua/R9B9r3RasXdRmOtd+t9TCOEIIlts+TN/7XTT2unhDaL6sJn83S3rUyljbr6lVtw49N3/yA0HHjpV6Kzb2aQ==", + "dev": true + }, + "level-errors": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-1.0.5.tgz", + "integrity": "sha512-/cLUpQduF6bNrWuAC4pwtUKA5t669pCsCi2XbmojG2tFeOr9j6ShtdDCtFFQO1DRt+EVZhx9gPzP9G2bUaG4ig==", + "dev": true, + "requires": { + "errno": "~0.1.1" + } + }, + "level-iterator-stream": { + "version": "1.3.1", + "resolved": "http://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-1.3.1.tgz", + "integrity": "sha1-5Dt4sagUPm+pek9IXrjqUwNS8u0=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "level-errors": "^1.0.3", + "readable-stream": "^1.0.33", + "xtend": "^4.0.0" + } + }, + "level-post": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/level-post/-/level-post-1.0.7.tgz", + "integrity": "sha512-PWYqG4Q00asOrLhX7BejSajByB4EmG2GaKHfj3h5UmmZ2duciXLPGYWIjBzLECFWUGOZWlm5B20h/n3Gs3HKew==", + "dev": true, + "requires": { + "ltgt": "^2.1.2" + } + }, + "level-sublevel": { + "version": "6.6.5", + "resolved": "https://registry.npmjs.org/level-sublevel/-/level-sublevel-6.6.5.tgz", + "integrity": "sha512-SBSR60x+dghhwGUxPKS+BvV1xNqnwsEUBKmnFepPaHJ6VkBXyPK9SImGc3K2BkwBfpxlt7GKkBNlCnrdufsejA==", + "dev": true, + "requires": { + "bytewise": "~1.1.0", + "levelup": "~0.19.0", + "ltgt": "~2.1.1", + "pull-defer": "^0.2.2", + "pull-level": "^2.0.3", + "pull-stream": "^3.6.8", + "typewiselite": "~1.0.0", + "xtend": "~4.0.0" + }, + "dependencies": { + "bl": { + "version": "0.8.2", + "resolved": "http://registry.npmjs.org/bl/-/bl-0.8.2.tgz", + "integrity": "sha1-yba8oI0bwuoA/Ir7Txpf0eHGbk4=", + "dev": true, + "requires": { + "readable-stream": "~1.0.26" + } + }, + "levelup": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/levelup/-/levelup-0.19.1.tgz", + "integrity": "sha1-86anIFJyxLXzXkEv8ASgOgrt9Qs=", + "dev": true, + "requires": { + "bl": "~0.8.1", + "deferred-leveldown": "~0.2.0", + "errno": "~0.1.1", + "prr": "~0.0.0", + "readable-stream": "~1.0.26", + "semver": "~5.1.0", + "xtend": "~3.0.0" + }, + "dependencies": { + "xtend": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", + "integrity": "sha1-XM50B7r2Qsunvs2laBEcST9ZZlo=", + "dev": true + } + } + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "semver": { + "version": "5.1.1", + "resolved": "http://registry.npmjs.org/semver/-/semver-5.1.1.tgz", + "integrity": "sha1-oykqNz5vPgeY2gsgZBuanFvEfhk=", + "dev": true + } + } + }, + "leveldown": { + "version": "1.4.6", + "resolved": "http://registry.npmjs.org/leveldown/-/leveldown-1.4.6.tgz", + "integrity": "sha1-xie6pMZ2X9Pr+U87MKeu/bnIk/s=", + "dev": true, + "optional": true, + "requires": { + "abstract-leveldown": "~2.4.0", + "bindings": "~1.2.1", + "fast-future": "~1.0.0", + "nan": "~2.3.0", + "prebuild": "^4.1.1" + }, + "dependencies": { + "abstract-leveldown": { + "version": "2.4.1", + "resolved": "http://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-2.4.1.tgz", + "integrity": "sha1-s7/tuITraToSd18MVenwpCDM7mQ=", + "dev": true, + "optional": true, + "requires": { + "xtend": "~4.0.0" + } + } + } + }, + "levelup": { + "version": "1.3.9", + "resolved": "https://registry.npmjs.org/levelup/-/levelup-1.3.9.tgz", + "integrity": "sha512-VVGHfKIlmw8w1XqpGOAGwq6sZm2WwWLmlDcULkKWQXEA5EopA8OBNJ2Ck2v6bdk8HeEZSbCSEgzXadyQFm76sQ==", + "dev": true, + "requires": { + "deferred-leveldown": "~1.2.1", + "level-codec": "~7.0.0", + "level-errors": "~1.0.3", + "level-iterator-stream": "~1.3.0", + "prr": "~1.0.1", + "semver": "~5.4.1", + "xtend": "~4.0.0" + }, + "dependencies": { + "abstract-leveldown": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-2.6.3.tgz", + "integrity": "sha512-2++wDf/DYqkPR3o5tbfdhF96EfMApo1GpPfzOsR/ZYXdkSmELlvOOEAl9iKkRsktMPHdGjO4rtkBpf2I7TiTeA==", + "dev": true, + "requires": { + "xtend": "~4.0.0" + } + }, + "deferred-leveldown": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-1.2.2.tgz", + "integrity": "sha512-uukrWD2bguRtXilKt6cAWKyoXrTSMo5m7crUdLfWQmu8kIm88w3QZoUL+6nhpfKVmhHANER6Re3sKoNoZ3IKMA==", + "dev": true, + "requires": { + "abstract-leveldown": "~2.6.0" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "semver": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", + "dev": true + } + } + }, + "leven": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/leven/-/leven-1.0.2.tgz", + "integrity": "sha1-kUS27ryl8dBoAWnxpncNzqYLdcM=", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "dev": true, + "optional": true + }, + "lodash.pad": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-4.5.1.tgz", + "integrity": "sha1-QzCUmoM6fI2iLMIPaibE1Z3runA=", + "dev": true + }, + "lodash.padend": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz", + "integrity": "sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4=", + "dev": true + }, + "lodash.padstart": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz", + "integrity": "sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs=", + "dev": true + }, + "long": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/long/-/long-1.1.2.tgz", + "integrity": "sha1-6u9ZUcp1UdlpJrgtokLbnWso+1M=", + "dev": true, + "optional": true + }, + "looper": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/looper/-/looper-2.0.0.tgz", + "integrity": "sha1-Zs0Md0rz1P7axTeU90LbVtqPCew=", + "dev": true + }, + "lru-cache": { + "version": "4.0.2", + "resolved": "http://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz", + "integrity": "sha1-HRdnnAac2l0ECZGgnbwsDbN35V4=", + "dev": true, + "requires": { + "pseudomap": "^1.0.1", + "yallist": "^2.0.0" + } + }, + "ltgt": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.1.3.tgz", + "integrity": "sha1-EIUaBtmWS5cReEQcI8nlJpjuzjQ=", + "dev": true + }, + "magic-string": { + "version": "0.22.5", + "resolved": "http://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", + "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==", + "dev": true, + "requires": { + "vlq": "^0.2.2" + } + }, + "memdown": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/memdown/-/memdown-1.1.2.tgz", + "integrity": "sha1-O4wkWA2yPkezxnLyzPCxkxh4RMs=", + "dev": true, + "requires": { + "abstract-leveldown": "^2.0.3", + "functional-red-black-tree": "^1.0.1", + "inherits": "~2.0.1", + "ltgt": "~1.0.2" + }, + "dependencies": { + "abstract-leveldown": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-2.7.2.tgz", + "integrity": "sha512-+OVvxH2rHVEhWLdbudP6p0+dNMXu8JA1CbhP19T8paTYAcX7oJ4OVjT+ZUVpv7mITxXHqDMej+GdqXBmXkw09w==", + "dev": true, + "requires": { + "xtend": "~4.0.0" + } + }, + "ltgt": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-1.0.2.tgz", + "integrity": "sha1-5oF+sprSBPwMnpbviw/umO9rmqM=", + "dev": true + } + } + }, + "merge-source-map": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.0.4.tgz", + "integrity": "sha1-pd5GU42uhNQRTMXqArR3KmNGcB8=", + "dev": true, + "requires": { + "source-map": "^0.5.6" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true + }, + "mime-db": { + "version": "1.37.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", + "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==", + "dev": true + }, + "mime-types": { + "version": "2.1.21", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", + "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", + "dev": true, + "requires": { + "mime-db": "~1.37.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mongodb": { + "version": "2.1.21", + "resolved": "http://registry.npmjs.org/mongodb/-/mongodb-2.1.21.tgz", + "integrity": "sha1-dkcJ28zrWCW06zH5U5X5Zf1EInI=", + "dev": true, + "optional": true, + "requires": { + "es6-promise": "3.0.2", + "mongodb-core": "1.3.21", + "readable-stream": "1.0.31" + }, + "dependencies": { + "readable-stream": { + "version": "1.0.31", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.31.tgz", + "integrity": "sha1-jyUC4LyeOw2huUUgqrtOJgPsr64=", + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + } + } + }, + "mongodb-core": { + "version": "1.3.21", + "resolved": "http://registry.npmjs.org/mongodb-core/-/mongodb-core-1.3.21.tgz", + "integrity": "sha1-/hKee+4rOybBQJ3gKrYNA/YpHMo=", + "dev": true, + "optional": true, + "requires": { + "bson": "~0.4.23", + "require_optional": "~1.0.0" + } + }, + "mosca": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/mosca/-/mosca-2.8.3.tgz", + "integrity": "sha512-jjhbk7DZjSRq8JaGhcdQQVReMXlgcIzKvlfxTZfZksnvhiZH0EEy4hNYefQokaa9f6zqdkc09u2dbUJ/ZTFlag==", + "dev": true, + "requires": { + "amqp": "~0.2.4", + "array-from": "^2.1.1", + "ascoltatori": "^3.0.0", + "brfs": "~1.4.2", + "clone": "^1.0.2", + "commander": "~2.9.0", + "deepcopy": "^0.6.1", + "escape-string-regexp": "^1.0.5", + "extend": "^3.0.0", + "ioredis": "^1.15.1", + "json-buffer": "~2.0.11", + "jsonschema": "^1.0.3", + "level-sublevel": "^6.5.2", + "leveldown": "~1.4.3", + "levelup": "^1.3.8", + "lru-cache": "~4.0.0", + "memdown": "~1.1.1", + "minimatch": "~3.0.0", + "mongodb": "~2.1.4", + "moving-average": "0.1.1", + "mqtt": "^1.6.3", + "mqtt-connection": "^2.1.1", + "msgpack5": "^3.3.0", + "nanoid": "^0.2.2", + "pbkdf2-password": "^1.1.0", + "pino": "^2.4.2", + "qlobber": "~0.7.0", + "retimer": "^1.0.1", + "st": "^1.1.0", + "steed": "^1.0.0", + "uuid": "^2.0.1", + "websocket-stream": "~3.1.0" + } + }, + "moving-average": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/moving-average/-/moving-average-0.1.1.tgz", + "integrity": "sha1-mxnDdpeOIblF7Xd2eO2VTUt7VHU=", + "dev": true + }, + "mqtt": { + "version": "1.14.1", + "resolved": "http://registry.npmjs.org/mqtt/-/mqtt-1.14.1.tgz", + "integrity": "sha1-fjdphxU9AXk+lG0m1GEi6/DANVQ=", + "dev": true, + "requires": { + "commist": "^1.0.0", + "concat-stream": "^1.4.7", + "end-of-stream": "^1.1.0", + "help-me": "^1.0.0", + "inherits": "^2.0.1", + "minimist": "^1.1.0", + "mqtt-connection": "^2.0.0", + "mqtt-packet": "^3.4.7", + "pump": "^1.0.1", + "readable-stream": "~1.0.2", + "reinterval": "^1.0.1", + "split2": "^2.0.1", + "websocket-stream": "^3.0.1", + "xtend": "^4.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + } + } + }, + "mqtt-connection": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/mqtt-connection/-/mqtt-connection-2.1.1.tgz", + "integrity": "sha1-ey6YWnThlmGUML69NdoWLDTE5Wo=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "mqtt-packet": "^3.0.0", + "reduplexer": "^1.1.0", + "through2": "^0.6.3" + }, + "dependencies": { + "readable-stream": { + "version": "1.0.34", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "through2": { + "version": "0.6.5", + "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "dev": true, + "requires": { + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + } + } + }, + "mqtt-packet": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-3.5.0.tgz", + "integrity": "sha512-lfeRZ95Mr3fcuYArDUG+bfC6jBQ07dNK3cXAYvN0d4sFttPx4VuizyZwTxkPJvxjJcx8TZZLVUK9gFt5OFcF5g==", + "dev": true, + "requires": { + "bl": "^1.0.0", + "inherits": "^2.0.1" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "msgpack-lite": { + "version": "0.1.26", + "resolved": "https://registry.npmjs.org/msgpack-lite/-/msgpack-lite-0.1.26.tgz", + "integrity": "sha1-3TxQsm8FnyXn7e42REGDWOKprYk=", + "dev": true, + "optional": true, + "requires": { + "event-lite": "^0.1.1", + "ieee754": "^1.1.8", + "int64-buffer": "^0.1.9", + "isarray": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true, + "optional": true + } + } + }, + "msgpack5": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/msgpack5/-/msgpack5-3.6.0.tgz", + "integrity": "sha512-6HuCZHA57WtNUzrKIvjJ8OMxigzveJ6D5i13y6TsgGu3X3zxABpuBvChpppOoGdB9SyWZcmqUs1fwUV/PpSQ7Q==", + "dev": true, + "requires": { + "bl": "^1.2.1", + "inherits": "^2.0.3", + "readable-stream": "^2.3.3", + "safe-buffer": "^5.1.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "nan": { + "version": "2.3.5", + "resolved": "http://registry.npmjs.org/nan/-/nan-2.3.5.tgz", + "integrity": "sha1-gioNwmYpDOTNOhIoLKPn42Rmigg=", + "dev": true, + "optional": true + }, + "nanoid": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-0.2.2.tgz", + "integrity": "sha512-GHoRrvNEKiwdkwQ/enKL8AhQkkrBC/2KxMZkDvQzp8OtkpX8ZAmoYJWFVl7l8F2+HcEJUfdg21Ab2wXXfrvACQ==", + "dev": true + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "dev": true + }, + "nested-error-stacks": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-1.0.2.tgz", + "integrity": "sha1-GfYZWRUZ8JZ2mlupqG5u7sgjw88=", + "dev": true, + "optional": true, + "requires": { + "inherits": "~2.0.1" + } + }, + "next-tick": { + "version": "1.0.0", + "resolved": "http://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "node-gyp": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.4.0.tgz", + "integrity": "sha1-3aVYOTs+y74kyea4cDxxGUxj+jY=", + "dev": true, + "optional": true, + "requires": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3", + "osenv": "0", + "path-array": "^1.0.0", + "request": "2", + "rimraf": "2", + "semver": "2.x || 3.x || 4 || 5", + "tar": "^2.0.0", + "which": "1" + } + }, + "node-ninja": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/node-ninja/-/node-ninja-1.0.2.tgz", + "integrity": "sha1-IKCeV7kuLfWRmT1L8JisPnJwYrY=", + "dev": true, + "optional": true, + "requires": { + "fstream": "^1.0.0", + "glob": "3 || 4 || 5 || 6 || 7", + "graceful-fs": "^4.1.2", + "minimatch": "3", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2", + "osenv": "0", + "path-array": "^1.0.0", + "request": "2", + "rimraf": "2", + "semver": "2.x || 3.x || 4 || 5", + "tar": "^2.0.0", + "which": "1" + }, + "dependencies": { + "gauge": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-1.2.7.tgz", + "integrity": "sha1-6c7FSD09TuDvRLYKfZnkk14TbZM=", + "dev": true, + "optional": true, + "requires": { + "ansi": "^0.3.0", + "has-unicode": "^2.0.0", + "lodash.pad": "^4.1.0", + "lodash.padend": "^4.1.0", + "lodash.padstart": "^4.1.0" + } + }, + "npmlog": { + "version": "2.0.4", + "resolved": "http://registry.npmjs.org/npmlog/-/npmlog-2.0.4.tgz", + "integrity": "sha1-mLUlMPJRTKkNCexbIsiEZyI3VpI=", + "dev": true, + "optional": true, + "requires": { + "ansi": "~0.3.1", + "are-we-there-yet": "~1.1.2", + "gauge": "~1.2.5" + } + } + } + }, + "node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=", + "dev": true + }, + "node-zookeeper-client": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/node-zookeeper-client/-/node-zookeeper-client-0.2.3.tgz", + "integrity": "sha512-V4gVHxzQ42iwhkANpPryzfjmqi3Ql3xeO9E/px7W5Yi774WplU3YtqUpnvcL/eJit4UqcfuLOgZLkpf0BPhHmg==", + "dev": true, + "optional": true, + "requires": { + "async": "~0.2.7", + "underscore": "~1.4.4" + }, + "dependencies": { + "async": { + "version": "0.2.10", + "resolved": "http://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", + "dev": true, + "optional": true + } + } + }, + "noop-logger": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", + "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=", + "dev": true, + "optional": true + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "npmlog": { + "version": "3.1.2", + "resolved": "http://registry.npmjs.org/npmlog/-/npmlog-3.1.2.tgz", + "integrity": "sha1-LUb6h0M3r5SYovErtD2NC+SjaHM=", + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.6.0", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true, + "optional": true + }, + "object-inspect": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.4.1.tgz", + "integrity": "sha512-wqdhLpfCUbEsoEwl3FXwGyv8ief1k/1aUdIPCqVnupM6e8l63BEJdiF/0swtn04/8p05tG/T0FrpTlfwvljOdw==", + "dev": true + }, + "object-keys": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", + "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optional": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/optional/-/optional-0.1.4.tgz", + "integrity": "sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw==", + "dev": true, + "optional": true + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + } + }, + "options": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", + "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", + "dev": true + }, + "ordered-read-streams": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", + "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", + "dev": true, + "requires": { + "readable-stream": "^2.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-array": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-array/-/path-array-1.0.1.tgz", + "integrity": "sha1-fi8PNfB6IBUSK4aLfqwOssT+wnE=", + "dev": true, + "requires": { + "array-index": "^1.0.0" + } + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "pbkdf2-password": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/pbkdf2-password/-/pbkdf2-password-1.2.1.tgz", + "integrity": "sha1-n3RROhVf041Na1yEFNOVXdJspu4=", + "dev": true, + "requires": { + "fastfall": "^1.2.3" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "pino": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-2.16.0.tgz", + "integrity": "sha1-UauDG5tFkzDn//Xtt1sglzypRwM=", + "dev": true, + "requires": { + "chalk": "^1.1.1", + "fast-json-parse": "^1.0.0", + "fast-safe-stringify": "^1.1.3", + "flatstr": "^1.0.4", + "object.assign": "^4.0.4", + "once": "^1.3.3", + "quick-format-unescaped": "^1.0.0", + "split2": "^2.0.1" + } + }, + "prebuild": { + "version": "4.5.0", + "resolved": "http://registry.npmjs.org/prebuild/-/prebuild-4.5.0.tgz", + "integrity": "sha1-KqoN8gY7/4FKgDvU3JT/m2Tl3wA=", + "dev": true, + "optional": true, + "requires": { + "async": "^1.4.0", + "execspawn": "^1.0.1", + "expand-template": "^1.0.0", + "ghreleases": "^1.0.2", + "github-from-package": "0.0.0", + "minimist": "^1.1.2", + "mkdirp": "^0.5.1", + "node-gyp": "^3.0.3", + "node-ninja": "^1.0.1", + "noop-logger": "^0.1.0", + "npmlog": "^2.0.0", + "os-homedir": "^1.0.1", + "pump": "^1.0.0", + "rc": "^1.0.3", + "simple-get": "^1.4.2", + "tar-fs": "^1.7.0", + "tar-stream": "^1.2.1", + "xtend": "^4.0.1" + }, + "dependencies": { + "gauge": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-1.2.7.tgz", + "integrity": "sha1-6c7FSD09TuDvRLYKfZnkk14TbZM=", + "dev": true, + "optional": true, + "requires": { + "ansi": "^0.3.0", + "has-unicode": "^2.0.0", + "lodash.pad": "^4.1.0", + "lodash.padend": "^4.1.0", + "lodash.padstart": "^4.1.0" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true, + "optional": true + }, + "npmlog": { + "version": "2.0.4", + "resolved": "http://registry.npmjs.org/npmlog/-/npmlog-2.0.4.tgz", + "integrity": "sha1-mLUlMPJRTKkNCexbIsiEZyI3VpI=", + "dev": true, + "optional": true, + "requires": { + "ansi": "~0.3.1", + "are-we-there-yet": "~1.1.2", + "gauge": "~1.2.5" + } + } + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true + }, + "prr": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz", + "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "psl": { + "version": "1.1.31", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", + "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==", + "dev": true + }, + "pull-cat": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/pull-cat/-/pull-cat-1.1.11.tgz", + "integrity": "sha1-tkLdElXaN2pwa220+pYvX9t0wxs=", + "dev": true + }, + "pull-defer": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/pull-defer/-/pull-defer-0.2.3.tgz", + "integrity": "sha512-/An3KE7mVjZCqNhZsr22k1Tx8MACnUnHZZNPSJ0S62td8JtYr/AiRG42Vz7Syu31SoTLUzVIe61jtT/pNdjVYA==", + "dev": true + }, + "pull-level": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pull-level/-/pull-level-2.0.4.tgz", + "integrity": "sha512-fW6pljDeUThpq5KXwKbRG3X7Ogk3vc75d5OQU/TvXXui65ykm+Bn+fiktg+MOx2jJ85cd+sheufPL+rw9QSVZg==", + "dev": true, + "requires": { + "level-post": "^1.0.7", + "pull-cat": "^1.1.9", + "pull-live": "^1.0.1", + "pull-pushable": "^2.0.0", + "pull-stream": "^3.4.0", + "pull-window": "^2.1.4", + "stream-to-pull-stream": "^1.7.1" + } + }, + "pull-live": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pull-live/-/pull-live-1.0.1.tgz", + "integrity": "sha1-pOzuAeMwFV6RJLu89HYfIbOPUfU=", + "dev": true, + "requires": { + "pull-cat": "^1.1.9", + "pull-stream": "^3.4.0" + } + }, + "pull-pushable": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pull-pushable/-/pull-pushable-2.2.0.tgz", + "integrity": "sha1-Xy867UethpGfAbEqLpnW8b13ZYE=", + "dev": true + }, + "pull-stream": { + "version": "3.6.9", + "resolved": "https://registry.npmjs.org/pull-stream/-/pull-stream-3.6.9.tgz", + "integrity": "sha512-hJn4POeBrkttshdNl0AoSCVjMVSuBwuHocMerUdoZ2+oIUzrWHFTwJMlbHND7OiKLVgvz6TFj8ZUVywUMXccbw==", + "dev": true + }, + "pull-window": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/pull-window/-/pull-window-2.1.4.tgz", + "integrity": "sha1-/DuG/uvRkgx64pdpHiP3BfiFUvA=", + "dev": true, + "requires": { + "looper": "^2.0.0" + } + }, + "pump": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", + "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "qlobber": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/qlobber/-/qlobber-0.7.0.tgz", + "integrity": "sha1-Aim2Nc19IK17Os8pjabSuU8ONM8=", + "dev": true + }, + "qlobber-fsq": { + "version": "3.2.4", + "resolved": "http://registry.npmjs.org/qlobber-fsq/-/qlobber-fsq-3.2.4.tgz", + "integrity": "sha1-++CF2o9GJiiOzCDHEHKT4OrPTbI=", + "dev": true, + "optional": true, + "requires": { + "async": "~1.5.2", + "fs-ext": "~0.5.0", + "graceful-fs": "~4.1.3", + "qlobber": "~0.7.0" + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "quick-format-unescaped": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-1.1.2.tgz", + "integrity": "sha1-DKWB3jF0vs7yWsPC6JVjQjgdtpg=", + "dev": true, + "requires": { + "fast-safe-stringify": "^1.0.8" + } + }, + "quote-stream": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/quote-stream/-/quote-stream-1.0.2.tgz", + "integrity": "sha1-hJY/jJwmuULhU/7rU6rnRlK34LI=", + "dev": true, + "requires": { + "buffer-equal": "0.0.1", + "minimist": "^1.1.3", + "through2": "^2.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "redis-commands": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.4.0.tgz", + "integrity": "sha512-cu8EF+MtkwI4DLIT0x9P8qNTLFhQD4jLfxLR0cCNkeGzs87FN6879JOJwNQR/1zD7aSYNbU0hgsV9zGY71Itvw==", + "dev": true, + "optional": true + }, + "redis-parser": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-1.3.0.tgz", + "integrity": "sha1-gG6+e7+3005NfB6e8oLvz60EEmo=", + "dev": true, + "optional": true + }, + "reduplexer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reduplexer/-/reduplexer-1.1.0.tgz", + "integrity": "sha1-ff7RimeedJwdetNt4BrLUV8I4UA=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "~1.0.26-2" + }, + "dependencies": { + "readable-stream": { + "version": "1.0.34", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + } + } + }, + "reinterval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz", + "integrity": "sha1-M2Hs+jymwYKDOA3Qu5VG85D17Oc=", + "dev": true + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + } + } + }, + "require_optional": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", + "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", + "dev": true, + "optional": true, + "requires": { + "resolve-from": "^2.0.0", + "semver": "^5.1.0" + } + }, + "resolve": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.9.0.tgz", + "integrity": "sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=", + "dev": true, + "optional": true + }, + "retimer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/retimer/-/retimer-1.1.0.tgz", + "integrity": "sha512-+Tjoa47XqpO+cmNObvmK6UPFmUTzQPtr4MqMS7ZJKPKYAnryCxG2FXT8/SEgPsEghQQgXFPZEdILNxJkvXtjUw==", + "dev": true + }, + "retry": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.6.1.tgz", + "integrity": "sha1-/ckO7ZQ/3hG4k1VLjMY9DombqRg=", + "dev": true, + "optional": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, + "requires": { + "glob": "^7.0.5" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true, + "optional": true + }, + "shallow-copy": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz", + "integrity": "sha1-QV9CcC1z2BAzApLMXuhurhoRoXA=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true, + "optional": true + }, + "simple-get": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-1.4.3.tgz", + "integrity": "sha1-6XVe2kB+ltpAxeUVjJ6jezO+y+s=", + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.1", + "unzip-response": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "simple-mime": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/simple-mime/-/simple-mime-0.1.0.tgz", + "integrity": "sha1-lfUXxPRm18/1YacfydqyWW6p7y4=", + "dev": true, + "optional": true + }, + "snappy": { + "version": "5.0.5", + "resolved": "http://registry.npmjs.org/snappy/-/snappy-5.0.5.tgz", + "integrity": "sha1-7BiTI0aVRq7d5DWS94CICP0HO0U=", + "dev": true, + "optional": true, + "requires": { + "bindings": "1.2.1", + "nan": "2.3.5", + "node-gyp": "3.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + }, + "split2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz", + "integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==", + "dev": true, + "requires": { + "through2": "^2.0.2" + } + }, + "sshpk": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.2.tgz", + "integrity": "sha512-Ra/OXQtuh0/enyl4ETZAfTaeksa6BXks5ZcjpSUNrjBr0DvrJKX+1fsKDPpT9TBXgHAFsa4510aNVgI8g/+SzA==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "st": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/st/-/st-1.2.2.tgz", + "integrity": "sha512-goKkumvz0BMLs6KjjPf5Fub/3T34tRVQxInUI5lqtbaKD+s4HcRlJYP2GPJ8RgAmrsnYOPGmOFEP6ho0KJ+E8g==", + "dev": true, + "requires": { + "async-cache": "~1.1.0", + "bl": "~1.2.1", + "fd": "~0.0.2", + "graceful-fs": "~4.1.11", + "mime": "~1.4.1", + "negotiator": "~0.6.1" + } + }, + "static-eval": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.0.0.tgz", + "integrity": "sha512-6flshd3F1Gwm+Ksxq463LtFd1liC77N/PX1FVVc3OzL3hAmo2fwHFbuArkcfi7s9rTNsLEhcRmXGFZhlgy40uw==", + "dev": true, + "requires": { + "escodegen": "^1.8.1" + } + }, + "static-module": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/static-module/-/static-module-2.2.5.tgz", + "integrity": "sha512-D8vv82E/Kpmz3TXHKG8PPsCPg+RAX6cbCOyvjM6x04qZtQ47EtJFVwRsdov3n5d6/6ynrOY9XB4JkaZwB2xoRQ==", + "dev": true, + "requires": { + "concat-stream": "~1.6.0", + "convert-source-map": "^1.5.1", + "duplexer2": "~0.1.4", + "escodegen": "~1.9.0", + "falafel": "^2.1.0", + "has": "^1.0.1", + "magic-string": "^0.22.4", + "merge-source-map": "1.0.4", + "object-inspect": "~1.4.0", + "quote-stream": "~1.0.2", + "readable-stream": "~2.3.3", + "shallow-copy": "~0.0.1", + "static-eval": "^2.0.0", + "through2": "~2.0.3" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "steed": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/steed/-/steed-1.1.3.tgz", + "integrity": "sha1-8VJd1a2xLrIb90dJU3Zo1iW5q8U=", + "dev": true, + "requires": { + "fastfall": "^1.5.0", + "fastparallel": "^2.2.0", + "fastq": "^1.3.0", + "fastseries": "^1.7.0", + "reusify": "^1.0.0" + } + }, + "stream-shift": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "dev": true + }, + "stream-to-pull-stream": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/stream-to-pull-stream/-/stream-to-pull-stream-1.7.2.tgz", + "integrity": "sha1-dXYJrhzr0zx0MtSvvjH/eGULnd4=", + "dev": true, + "requires": { + "looper": "^3.0.0", + "pull-stream": "^3.2.3" + }, + "dependencies": { + "looper": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/looper/-/looper-3.0.0.tgz", + "integrity": "sha1-LvpUw7HLq6m5Su4uWRSwvlf7t0k=", + "dev": true + } + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "http://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "optional": true + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "tar": { + "version": "2.2.1", + "resolved": "http://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "dev": true, + "requires": { + "block-stream": "*", + "fstream": "^1.0.2", + "inherits": "2" + } + }, + "tar-fs": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", + "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.0.1", + "mkdirp": "^0.5.1", + "pump": "^1.0.0", + "tar-stream": "^1.1.2" + } + }, + "tar-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "dev": true, + "requires": { + "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", + "xtend": "^4.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "through2-filter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-2.0.0.tgz", + "integrity": "sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=", + "dev": true, + "requires": { + "through2": "~2.0.0", + "xtend": "~4.0.0" + } + }, + "to-absolute-glob": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", + "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", + "dev": true, + "requires": { + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" + } + }, + "to-buffer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", + "dev": true + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", + "dev": true, + "optional": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "typewise": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typewise/-/typewise-1.0.3.tgz", + "integrity": "sha1-EGeTZUCvl5N8xdz5kiSG6fooRlE=", + "dev": true, + "requires": { + "typewise-core": "^1.2.0" + } + }, + "typewise-core": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/typewise-core/-/typewise-core-1.2.0.tgz", + "integrity": "sha1-l+uRgFx/VdL5QXSPpQ0xXZke8ZU=", + "dev": true + }, + "typewiselite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typewiselite/-/typewiselite-1.0.0.tgz", + "integrity": "sha1-yIgvobsQksBgBal/NO9chQjjZk4=", + "dev": true + }, + "ultron": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", + "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=", + "dev": true + }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", + "dev": true + }, + "underscore": { + "version": "1.4.4", + "resolved": "http://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", + "integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ=", + "dev": true, + "optional": true + }, + "unique-stream": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.2.1.tgz", + "integrity": "sha1-WqADz76Uxf+GbE59ZouxxNuts2k=", + "dev": true, + "requires": { + "json-stable-stringify": "^1.0.0", + "through2-filter": "^2.0.0" + } + }, + "unzip-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-1.0.2.tgz", + "integrity": "sha1-uYTwh3/AqJwsdzzB73tbIytbBv4=", + "dev": true, + "optional": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=", + "dev": true, + "optional": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "util-extend": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", + "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=", + "dev": true, + "optional": true + }, + "uuid": { + "version": "2.0.3", + "resolved": "http://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", + "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vlq": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", + "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==", + "dev": true + }, + "websocket-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/websocket-stream/-/websocket-stream-3.1.0.tgz", + "integrity": "sha1-xtnRMjC3fkdMS2c2wpW7p3zdf4c=", + "dev": true, + "requires": { + "duplexify": "^3.2.0", + "inherits": "^2.0.1", + "through2": "^2.0.0", + "ws": "^1.0.1", + "xtend": "^4.0.0" + } + }, + "when": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/when/-/when-3.6.4.tgz", + "integrity": "sha1-RztRfsFZ4rhQBUl6E5g/CVQS404=", + "dev": true, + "optional": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "ws": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", + "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", + "dev": true, + "requires": { + "options": ">=0.0.5", + "ultron": "1.0.x" + } + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "zmq": { + "version": "2.15.3", + "resolved": "https://registry.npmjs.org/zmq/-/zmq-2.15.3.tgz", + "integrity": "sha1-Zsbegsw2sJc0uCBwN3ZJCm+75iQ=", + "dev": true, + "optional": true, + "requires": { + "bindings": "~1.2.1", + "nan": "~2.3.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..1589ab3 --- /dev/null +++ b/package.json @@ -0,0 +1,27 @@ +{ + "name": "mqtt-fpc-sdk", + "version": "1.0.0", + "description": "MQTT Framework for FPC", + "main": "a", + "directories": { + "example": "examples", + "lib": "lib", + "test": "test" + }, + "scripts": { + "broker": "node test/broker.js" + }, + "repository": { + "type": "git", + "url": "https://tfs.wit.fr/wit/OpenRedy/_git/mqtt-fpc-sdk" + }, + "keywords": [ + "mqtt", + "fpc" + ], + "author": "", + "license": "ISC", + "devDependencies": { + "mosca": "^2.8.3" + } +} diff --git a/test/broker.js b/test/broker.js new file mode 100644 index 0000000..1f1a774 --- /dev/null +++ b/test/broker.js @@ -0,0 +1,24 @@ +var mosca = require('mosca'); + +var settings = { + port: 1883 +}; + +var server = new mosca.Server(settings); + +server.on('clientConnected', function(client) { + console.log('client connected', client.id); +}); + +// fired when a message is received +server.on('published', function(packet, client) { + + console.log('Published', packet.topic ,packet.payload ? packet.payload.toString() : ''); +}); + +server.on('ready', setup); + +// fired when the mqtt server is ready +function setup() { + console.log('Mosca server is up and running'); +} \ No newline at end of file