I'm using "chai" to test a response data of https,the data is like is:
let req = https.request(options, (res) => {
res.on('data', (data) => {
return callback(null, data);
});
});
The test code like this:
let chai = require("chai");
let expect = chai.expect;
console.log("data=" + data);
console.log("typeof data = " + typeof(data));//object
console.log("util.isObject(data) = " + util.isObject(data));//true
console.log("util.isString(data) = " + util.isString(data));//false
// assert.isObject(data, "object");
expect(JSON.stringify(data)).to.be.an("string");//ok
expect(JSON.parse(data)).to.be.an("object");//ok
expect(data).to.be.an("object");//error
Mocha test failed at "expect(data).to.be.an("object");",log like this:
data={"data":{"isDulp":false,"bindTb":false},"req_id":"REQ_APP-1487212987084_2851"}
typeof data = object
util.isObject(data) = true
util.isString(data) = false
Uncaught AssertionError: expected <Buffer 7b 22 64 61 74 61 22 3a 7b 22 69 73 44 75 6c 70 22 3a 66 61 6c 73 65 2c 22 62 69 6e 64 54 62 22 3a 66 61 6c 73 65 7d 2c 22 72 65 71 5f 69 64 22 3a 22 ... > to be an object
I thought 'data' is a object, and when I use typeof to test it, it print "object", but when I use chai "expect(data).to.be.an("object")" the test case failed.
If I use "expect(JSON.parse(data)).to.be.an("object")", the test case passed.
Some one who can tell me why? What the type of the 'data'?
The expected buffer result shows that your endpoint returns a buffer instead of an object, assert String works because it is an string of course. I am guessing that the reason it fails is that data is not an object but a buffer.
Related
I have a list like this:
["Dhoni 35 WC 785623", "Sachin 40 Batsman 4500", "Dravid 45 Batsman 50000", "Kumble 41 Bowler 456431", "Srinath 41 Bowler 65465"]
After applying filter I want like this:
["Dhoni WC", "Sachin Batsman", "Dravid Batsman", "Kumble Bowler", "Srinath Bowler"]
I tried out this way
m = sc.parallelize(["Dhoni 35 WC 785623","Sachin 40 Batsman 4500","Dravid 45 Batsman 50000","Kumble 41 Bowler 456431","Srinath 41 Bowler 65465"])
n = m.map(lambda k:k.split(' '))
o = n.map(lambda s:(s[0]))
o.collect()
['Dhoni', 'Sachin', 'Dravid', 'Kumble', 'Srinath']
q = n.map(lambda s:s[2])
q.collect()
['WC', 'Batsman', 'Batsman', 'Bowler', 'Bowler']
Provided, all your list items are of same format, one way to achieve this is with map.
rdd = sc.parallelize(["Dhoni 35 WC 785623","Sachin 40 Batsman 4500","Dravid 45 Batsman 50000","Kumble 41 Bowler 456431","Srinath 41 Bowler 65465"])
rdd.map(lambda x:(x.split(' ')[0]+' '+x.split(' ')[2])).collect()
Output:
['Dhoni WC', 'Sachin Batsman', 'Dravid Batsman', 'Kumble Bowler', 'Srinath Bowler']
I was facing a problem where I got data (String) from a database with Linebreaks as (Hex) 0D. I displayed this data in a Textbox, which did not use the 0D as a linbreak. I found that the Textbox needs 0D-0A (LF & CR, dont know which is which) to actually show the new line. To solve this problem I came up with the following code.
Private Function convertString(txt As String) As String
Dim data = System.Text.Encoding.Default.GetBytes(txt)
Dim hexString As String = BitConverter.ToString(data)
hexString = hexString.Replace("0D", "0D-0A")
Dim arr As [String]() = hexString.Split("-"c)
Dim array As Byte() = New Byte(arr.Length - 1) {}
For i As Integer = 0 To arr.Length - 1
array(i) = Convert.ToByte(arr(i), 16)
Next
Return System.Text.Encoding.Default.GetString(array)
End Function
Explanation/procedure:
1. Convert String to ByteArray
2. Convert ByteArray to Hex-String (Hex-Chars separated by '-' )
3. Adding the missing lf or cr by replacing the solo one
4. Convert Hex-String back to ByteArray
5. Convert ByteArray back to String
Now my question:
I am pretty sure there is a better way to do that. How can I simplify those lines of code?
You should be able to just Replace vbCr with vbCrLf:
Dim txt = "This is a" & vbCr & "test"
Encoding.UTF8.GetBytes(txt).HexDump()
gives (HexDump is a custom utility method, but not relevant to the question):
00000000 54 68 69 73 20 69 73 20 61 0D 74 65 73 74 This is a·test
Dim txt2 = txt.Replace(vbCr, vbCrLf)
Encoding.UTF8.GetBytes(txt2).HexDump()
gives:
00000000 54 68 69 73 20 69 73 20 61 0D 0A 74 65 73 74 This is a··test
So, your whole method would be:
Private Function convertString(txt As String) As String
Return txt.Replace(vbCr, vbCrLf)
End Function
In a recent Go project I need to read a binary data file generated by Python, but due to padding, binary.Read in Go doesn't read it properly. Below is a minimal example of my problem.
The struct I deal with if of the following format
type Index struct{
A int32
B int32
C int32
D int64
}
As you can see the size of the struct is 4+4+4+8=20, but Python added an extra 4 bytes for alignment. So the size is actually 24.
Below is the runnable Python code I use to write this struct:
#!/usr/bin/env python
# encoding=utf8
import struct
if __name__ == '__main__':
data = range(1, 13)
format = 'iiiq' * 3
content = struct.pack(format, *data)
with open('index.bin', 'wb') as f:
f.write(content)
the iiiq format means there are three 32 bit integers and one 64 bit integer in the struct, which is the same with the Index struct I defined earlier. And running this code will generate a file named index.bin of size 72, which equals to 24 * 3.
And below is the Go code I use to read index.bin:
package main
import (
"encoding/binary"
"fmt"
"os"
"io"
"unsafe"
)
type Index struct {
A int32
B int32
C int32
D int64
}
func main() {
indexSize := unsafe.Sizeof(Index{})
fp, _ := os.Open("index.bin")
defer fp.Close()
info, _ := fp.Stat()
fileSize := info.Size()
entryCnt := fileSize / int64(indexSize)
fmt.Printf("entry cnt: %d\n", entryCnt)
readSlice := make([]Index, entryCnt)
reader := io.Reader(fp)
_ = binary.Read(reader, binary.LittleEndian, &readSlice)
fmt.Printf("After read:\n%#v\n", readSlice)
}
And this is the output:
entry cnt: 3
After read:
[]main.Index{main.Index{A:1, B:2, C:3, D:17179869184}, main.Index{A:0, B:5, C:6, D:7}, main.Index{A:8, B:0, C:9, D:47244640266}}
Obviously the output is messed up when reading from the Python generated file.
So my question is, how can I read the python generated file(with padding) in Go properly?
You can just pad your Go struct to match:
type Index struct {
A int32
B int32
C int32
_ int32
D int64
}
Which produces:
[]main.Index{main.Index{A:1, B:2, C:3, _:0, D:4}, main.Index{A:5, B:6, C:7, _:0, D:8}, main.Index{A:9, B:10, C:11, _:0, D:12}}
binary.Read knows to skip the _ field:
When reading into structs, the field data for fields with blank (_) field names is skipped; i.e., blank field names may be used for padding.
(So the 0 values for _ are not because the padding in the file was set to zero, but because the struct field was initialized to 0 and never changed, and the padding in the file was skipped rather than read.)
For example,
package main
import (
"bufio"
"encoding/binary"
"fmt"
"io"
"os"
)
type Index struct {
A int32
B int32
C int32
D int64
}
func readIndex(r io.Reader) (Index, error) {
var index Index
var buf [24]byte
_, err := io.ReadFull(r, buf[:])
if err != nil {
return index, err
}
index.A = int32(binary.LittleEndian.Uint32(buf[0:4]))
index.B = int32(binary.LittleEndian.Uint32(buf[4:8]))
index.C = int32(binary.LittleEndian.Uint32(buf[8:12]))
index.D = int64(binary.LittleEndian.Uint64(buf[16:24]))
return index, nil
}
func main() {
f, err := os.Open("index.bin")
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
defer f.Close()
r := bufio.NewReader(f)
indexes := make([]Index, 0, 1024)
for {
index, err := readIndex(r)
if err != nil {
if err == io.EOF {
break
}
fmt.Fprintln(os.Stderr, err)
return
}
indexes = append(indexes, index)
}
fmt.Println(indexes)
}
Output:
[{1 2 3 4} {5 6 7 8} {9 10 11 12}]
Input:
00000000 01 00 00 00 02 00 00 00 03 00 00 00 00 00 00 00 |................|
00000010 04 00 00 00 00 00 00 00 05 00 00 00 06 00 00 00 |................|
00000020 07 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 |................|
00000030 09 00 00 00 0a 00 00 00 0b 00 00 00 00 00 00 00 |................|
00000040 0c 00 00 00 00 00 00 00 |........|
#Barber's solution is workable, but I found adding a padding field not so comfortable. And I found a better way of doing it.
Below is the new golang read code which works perfectly:
package main
import (
"fmt"
"os"
"io"
"io/ioutil"
"unsafe"
)
type Index struct {
A int32
B int32
C int32
// Pad int32
D int64
}
func main() {
indexSize := unsafe.Sizeof(Index{})
fp, _ := os.Open("index.bin")
defer fp.Close()
info, _ := fp.Stat()
fileSize := info.Size()
entryCnt := fileSize / int64(indexSize)
reader := io.Reader(fp)
allBytes, _ := ioutil.ReadAll(reader)
readSlice := *((*[]Index)(unsafe.Pointer(&allBytes)))
realLen := len(allBytes) / int(indexSize)
readSlice = readSlice[:realLen]
fmt.Printf("After read:\n%#v\n", readSlice)
}
Output:
After read:
[]main.Index{main.Index{A:1, B:2, C:3, D:4}, main.Index{A:5, B:6, C:7, D:8}, main.Index{A:9, B:10, C:11, D:12}}
This solution needs no explicit padding field.
The essence here is that if you let golang convert the whole bytes to a slice of Index struct, it seems to be able to handle the padding well.
The Sensor advertises these Bluetooth LE Packages:
> 04 3E 26 02 01 03 01 B8 AB C0 5D 4C D9 1A 02 01 04 09 09 38
42 42 41 43 34 39 44 07 16 09 18 47 08 00 FE 04 16 0F 18 5B
B3
> 04 3E 26 02 01 03 01 B8 AB C0 5D 4C D9 1A 02 01 04 09 09 38
42 42 41 43 34 39 44 07 16 09 18 45 08 00 FE 04 16 0F 18 5A
BC
> 04 3E 26 02 01 03 01 B8 AB C0 5D 4C D9 1A 02 01 04 09 09 38
42 42 41 43 34 39 44 07 16 09 18 44 08 00 FE 04 16 0F 18 5B
B2
How do I decode it?
LE Advertising Report:
ADV_NONCONN_IND - Non connectable undirected advertising (3)
bdaddr D9:4C:5D:C0:AB:B8 (Random)
Flags: 0x04
Complete local name: '8BBAC49D'
Unknown type 0x16 with 6 bytes data
Unknown type 0x16 with 3 bytes data
RSSI: -77
It's not a beacon advertisement. The packets are the device sending three pieces of information.
The device's local name "8BBAC49D"
The Health Thermometer Service is available (with a current temperature measurement)
The Battery Service is available (with a current battery level measurement)
Breakdown of this BLE discovered packet:
> 04 3E 26 02 01 03 01 B8 AB C0 5D 4C D9 1A 02 01 04 09 09 38
42 42 41 43 34 39 44 07 16 09 18 44 08 00 FE 04 16 0F 18 5B
B2
If you look at your repeat packet, you will see that each temperature measurement varies slightly, as does the battery measurement.
Here is the breakdown of the packet:
B8 AB C0 5D 4C D9 1A # Bluetooth Mac Address
02 # Number of bytes that follow in first AD structure
01 # Flags AD type
04 # Flags value 0x04 = 000000100
bit 0 (OFF) LE Limited Discoverable Mode
bit 1 (OFF) LE General Discoverable Mode
bit 2 (ON) BR/EDR Not Supported
bit 3 (OFF) Simultaneous LE and BR/EDR to Same Device Capable (controller)
bit 4 (OFF) Simultaneous LE and BR/EDR to Same Device Capable (Host)
09 # Number of bytes that follow in the first AD Structure
09 # Complete Local Name AD Type
38 42 42 41 43 34 39 44 # "8BBAC49D"
07 # Number of bytes that follow in the second AD Structure
16 # Service Data AD Type
09 18 # 16-bit Service UUID 0x1809 = Health thermometer (org.bluetooth.service.health_thermometer)
44 08 00 FE # Additional Service Data 440800 (Temperature = 0x000844 x 10^-2) = 21.16 degrees
04 # Number of bytes that follow in the third AD Structure
16 # Service Data AD Type
0F 18 # 16-bit Service UUID 0x180F = Battery Service (org.bluetooth.service.battery_service)
5B # Additional Service Data (battery level)
B2 # checksum
See the bluetooth 16-bit service UUID definitions for more information:
https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.battery_service.xml
https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.health_thermometer.xml
You can use hcidump -w dump.log to record some packages and open it in Wireshark - which does most of the decoding for you.
The missing pices:
04 # HCI Packet Type: HCI Event (0x04)
3E # Event Code: LE Meta (0x3e)
26 # Parameter Total Length: 38
02 # Sub Event: LE Advertising Report (0x02)
01 # Num Reports: 1
03 # Event Type: Non-Connectable Undirected Advertising (0x03)
01 # Peer Address Type: Random Device Address (0x01)
Screenshot form Wireshark:
And here is the Packet in btsnoop.log format. Works with Wireshark and hcidump -r packet.log.
public class Util {
public static int convertU16ToInt(byte i) {
int firstByte = (0x000000FF & ((int)i));
return firstByte;
}
public static int bytesToInt(final byte[] array, final int start)
{
final ByteBuffer buf = ByteBuffer.wrap(array); // big endian by default
buf.position(start);
buf.put(array);
buf.position(start);
return buf.getInt();
}
public static int convertU32ToInt(byte b[], int start) {
return ((b[start] << 24) & 0xff000000 |(b[start + 1] << 16) & 0xff0000
| (b[start + 2] << 8) & 0xff00 | (b[start + 3]) & 0xff);
}
public static long int64Converter(byte buf[], int start) {
return ((buf[start] & 0xFFL) << 56) | ((buf[start + 1] & 0xFFL) << 48)
| ((buf[start + 2] & 0xFFL) << 40)
| ((buf[start + 3] & 0xFFL) << 32)
| ((buf[start + 4] & 0xFFL) << 24)
| ((buf[start + 5] & 0xFFL) << 16)
| ((buf[start + 6] & 0xFFL) << 8)
| ((buf[start + 7] & 0xFFL) << 0);
}
public static long convertU16ToInt(byte[] buf, int index) {
int firstByte = (0x000000FF & ((int)buf[index]));
int secondByte = (0x000000FF & ((int)buf[index+1]));
int thirdByte = (0x000000FF & ((int)buf[index+2]));
int fourthByte = (0x000000FF & ((int)buf[index+3]));
index = index+4;
long anUnsignedInt = ((long) (firstByte << 24
| secondByte << 16
| thirdByte << 8
| fourthByte))
& 0xFFFFFFFFL;
return anUnsignedInt;
}
public static short toUnsigned(byte b) {
return (short)(b & 0xff);
}
public static int convertU16ToInt(byte byte1, byte byte2) {
int N = (( 255 - byte1 & 0xff ) << 8 ) | byte2 & 0xff;
return N;
}
public static short UInt16Decode(byte inbyByteA, byte inbyByteB) {
short n = (short)(((inbyByteA & 0xFF) << 8) | (inbyByteB & 0xFF));
return n;
}
public static long UInt32Decode(int inbyByteA, int inbyByteB) {
int n = inbyByteA<< 16 | inbyByteB;
return n;
}
public static long decodeMeasurement16(byte byte3, byte byte4) {
return 0L;
}
public static double decodeMeasurement32(byte byte3, byte byte4, byte byte6, byte byte7) {
double outdblFloatValue = 0;
int outi16DecimalPointPosition = 0;
int ui16Integer1 = convertU16ToInt (byte3, byte4);
int ui16Integer2 = convertU16ToInt (byte6, byte7);
int ui32Integer = ( (int)UInt32Decode (ui16Integer1, ui16Integer2) ) & 0x07FFFFFF;
outi16DecimalPointPosition = ((0x000000FF - byte3 ) >> 3) - 15;
// Decode raw value, with Exampledata: 0x05FFFFFC
if ((100000000 + 0x2000000) > ui32Integer) {
// Data is a valid value
if (0x04000000 == (ui32Integer & 0x04000000)) {
ui32Integer = (ui32Integer | 0xF8000000);
// With Exampledata: 0xFDFFFFFC
}
ui32Integer = ui32Integer + 0x02000000; // with Exampledata: 0xFFFFFFFC
}
else {
// Data contains error code, decode error code
outdblFloatValue = (double)((ui32Integer - 0x02000000) - 16352.0);
outi16DecimalPointPosition = 0;
return -36; // Return value is error code
}
outdblFloatValue = (double)ui32Integer;
outdblFloatValue = outdblFloatValue / (Math.pow(10.0f, (double)outi16DecimalPointPosition));
return outdblFloatValue;
}
public static int toByte(int number) {
int tmp = number & 0xff;
return (tmp & 0x80) == 0 ? tmp : tmp - 256;
}
public static long getUnsignedInt(int x) {
return x & 0x00000000ffffffffL;
}
}
After getting bytes array, call Util.decodeMeasurement32(byte[9], byte[10], byte[11], byte[12]). These bytes are the temperature bytes.
The thermometer works like a BLE beacon, i.e. you cannot connect. All information is given in the advertising every 5 seconds or so. E.g. with Android & the blessed library (https://github.com/weliem/blessed-android):
lateinit var central: BluetoothCentralManager
val HTS_SERVICE_UUID = ParcelUuid.fromString("00001809-0000-1000-8000-00805f9b34fb")
val BTS_SERVICE_UUID = ParcelUuid.fromString("0000180f-0000-1000-8000-00805f9b34fb")
fun convertTemperature(bytes: ByteArray?): Float {
if (null == bytes)
return -273.15f
val bb: ByteBuffer = ByteBuffer.allocate(2)
bb.order(ByteOrder.LITTLE_ENDIAN)
bb.put(bytes[0])
bb.put(bytes[1])
return bb.getShort(0) / 100.0f
}
val bluetoothCentralManagerCallback: BluetoothCentralManagerCallback = object : BluetoothCentralManagerCallback() {
override fun onDiscoveredPeripheral(peripheral: BluetoothPeripheral, scanResult: ScanResult) {
val rssi = scanResult.rssi
val scanRec = scanResult.scanRecord
val payload = scanRec?.serviceData
val temperature = convertTemperature(payload?.get(key = HTS_SERVICE_UUID))
val other_data = payload?.get(key = HTS_SERVICE_UUID)?.sliceArray(2..3)
val battery_level = payload?.get(key = BTS_SERVICE_UUID)
central.stopScan()
tempLabel.text = getString(R.string.temp, temperature)
}
}
central = BluetoothCentralManager(applicationContext, bluetoothCentralManagerCallback, Handler(Looper.getMainLooper()))
central.scanForPeripheralsWithNames(arrayOf("7FE2183D"))
Every time you want a new reading you can start scanning again.
I am drawing an signature like this as given below and taking X Y cordinate and saving it to the arry list.
Bitmap bmp;
//Graphics object
Graphics graphics;
//Pen object
Pen pen = new Pen(Color.Black);
// Array List of line segments
ArrayList pVector = new ArrayList();
//Point object
Point lastPoint = new Point(0, 0);
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
// process if currently drawing signature
if (!drawSign)
{
// start collecting points
drawSign = true;
// use current mouse click as the first point
lastPoint.X = e.X;
lastPoint.Y = e.Y;
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
// process if drawing signature
if (drawSign)
{
if (graphics != null)
{
// draw the new segment on the memory bitmap
graphics.DrawLine(pen, lastPoint.X, lastPoint.Y, e.X, e.Y);
pVector.Add(lastPoint.X + " " + lastPoint.Y + " " + e.X + " " + e.Y);
// update the current position
lastPoint.X = e.X;
lastPoint.Y = e.Y;
// display the updated bitmap
Invalidate();
}
}
}
Using the arrylist (pVector) I am saving the values to the database as string(singature ) and aslo as image as given below
//Saving value to Database
ArrayList arrSign = new ArrayList();
arrSign = this.signatureControl.getPVector();
string singature = "";
for (int i = 0; i < arrSign.Count; i++)
{
singature = singature + arrSign[i].ToString() + "*";
}
the string singature wiil be like this
60 46 59 48*59 48 59 51*59 51 59 53*59 53 60 49*60 49 61 44*61 44 62 38*62 38 64 31*64 31 67 23*67 23 70 14*70 14 72 10*72 10 75 3*75 3 77 -2*77 -2 76 2*76 2 75 6*75 6 72 17*72 17 71 24*71 24 69 31*69 31 68 46*68 46 67 59*67 59 68 71*68 71 69 79*69 79 70 86*70 86 71 89*71 89 71 93*71 93 71 95*71 95 71 97*71 97 70 95*70 95 69 88*69 88 68 81*68 81 69 77*69 77 69 68*69 68 71 60
//Saving as Image file
Pen pen = new Pen(Color.Black);
string[] arrStr = (signature.Split('*'));
Graphics graphics;
Bitmap bmp = new Bitmap(300, 200);
graphics = Graphics.FromImage(bmp);
graphics.Clear(Color.White);
for (int i = 0; i < arrStr.Length - 2; i++)
{
string[] strArr = new string[4];
strArr = ((arrStr[i].ToString()).Split(' '));
graphics.DrawLine(pen, Convert.ToInt32(strArr[0].ToString()), Convert.ToInt32(strArr[1].ToString()),
Convert.ToInt32(strArr[2].ToString()), Convert.ToInt32(strArr[3].ToString()));
}
string pathToCopyImage = systemBus.TempFile;
bmp.Save(pathToCopyImage + "\\" + dsReportDetails.Tables["tblDelivery"].Rows[0]["PKDelivery"].ToString() + "_Signature.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
bmp.Dispose();
My problem is that after Saving the signature as Image file I am not able to convert it back to arrylist like the one that i am used to save the value in the database.
ie I need to convert the image file back to as given below format
60 46 59 48*59 48 59 51*59 51 59 53*59 53 60 49*60 49 61 44*61 44 62 38*62 38 64 31*64 31 67 23*67 23 70 14*70 14 72 10*72 10 75 3*75 3 77 -2*77 -2 76 2*76 2 75 6*75 6 72 17*72 17 71 24*71 24 69 31*69 31 68 46*68 46 67 59*67 59 68 71*68 71 69 79*69 79 70 86*70 86 71 89*71 89 71 93*71 93 71 95*71 95 71 97*71 97 70 95*70 95 69 88*69 88 68 81*68 81 69 77*69 77 69 68*69 68 71 60
Will any one help me please
It is not very easy to get your "signature string" back from image so you can just add you "string signature" to saved image as a metadata tag of image (as a Description for example). So then you read your image back you don't need to recognize "signature string" from image, you can just read it from metadata as a string. Msdn has a nice article about image metadata and api to work with them. http://msdn.microsoft.com/en-us/library/ms748873.aspx
By the way, your code for concatenating "signature string" is slow and memory consuming. It is better to use StringBuilder in such situations in .Net. And overall strings are not the best data structure to store list of points. But it depends on requirements for your app.