<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>html, body {
margin: 0;
padding: 0;
}
.app {
margin: 10px;
padding: 0;
}
.files-list {
margin: 10px 0 0;
width: 100%;
border-collapse: collapse;
}
.files-list__head {
border: 1px solid #999;
}
.files-list__head > tr > th {
padding: 10px;
border: 1px solid #999;
text-align: left;
font-weight: normal;
background: #ddd;
}
.files-list__body {
}
.files-list__file {
cursor: pointer;
}
.files-list__file:hover {
background: #ccf;
}
.files-list__file > td {
padding: 10px;
border: 1px solid #999;
}
.files-list__file > td:first-child::before {
content: '\01F4C4';
margin-right: 1em;
}
.files-list__file_low {
background: #fcc;
}
.files-list__file_medium {
background: #ffc;
}
.files-list__file_high {
background: #cfc;
}
.files-list__file_folder > td:first-child::before {
content: '\01F4C1';
margin-right: 1em;
}
.file-header {
border: 1px solid #999;
display: flex;
justify-content: space-between;
align-items: center;
}
.file-header__back {
margin: 10px;
cursor: pointer;
flex-shrink: 0;
flex-grow: 0;
text-decoration: underline;
color: #338;
}
.file-header__name {
margin: 10px;
flex-shrink: 2;
flex-grow: 2;
}
.file-header__stat {
margin: 10px;
flex-shrink: 0;
flex-grow: 0;
}
.file-content {
margin: 10px 0 0;
border: 1px solid #999;
padding: 10px;
}
.code-line {
margin: 0;
padding: 0.3em;
height: 1em;
}
.code-line_covered {
background: #cfc;
}
.code-line_uncovered {
background: #fcc;
}
</style>
</head>
<body>
<div id="root"></div>
<script>var data = {"files":[{"path":["/","home","wcampbell","projects","wcampbell","code","saleae","src","client.rs"],"content":"//! This module defines the client data structure - the main entry point of communication\n//! to the saleae\n\nuse anyhow::Result;\nuse std::io::prelude::{Read, Write};\nuse std::io::{BufReader, BufWriter};\nuse std::net::TcpStream;\n\nuse crate::device::ConnectedDevice;\nuse crate::performance::PerformanceOption;\nuse crate::request::Request;\nuse crate::response::Response;\nuse crate::samplerate::SampleRate;\n\n#[faux::create]\n#[derive(Debug)]\npub struct Connection {\n stream: TcpStream,\n}\n\n#[faux::methods]\nimpl Connection {\n pub fn new(ip_port: \u0026str) -\u003e Self {\n Connection {\n stream: TcpStream::connect(ip_port).unwrap(),\n }\n }\n\n pub fn general_recieve_ack(\u0026mut self) -\u003e Result\u003cbool\u003e {\n let r: String = std::str::from_utf8(\u0026self.read_line()?)?.to_string();\n Ok(Response::verify_ack(\u0026r))\n }\n\n pub fn general_recieve_message(\u0026mut self) -\u003e Result\u003cString\u003e {\n let msg: String = std::str::from_utf8(\u0026self.read_line()?)?.to_string();\n Response::verify_ack(\u0026msg);\n Ok(msg)\n }\n\n fn read_line(\u0026mut self) -\u003e Result\u003cVec\u003cu8\u003e\u003e {\n let mut reader = BufReader::new(\u0026self.stream);\n let mut buf = [0; 500];\n let len = reader.read(\u0026mut buf)?;\n if len \u003c 1 {\n panic!(\"read buffer len \u003c 0\");\n }\n Ok(buf[..len].to_vec())\n }\n\n //TODO Support for parameters\n pub fn run_command(\u0026mut self, command: \u0026str) -\u003e Result\u003c()\u003e {\n let mut writer = BufWriter::new(\u0026self.stream);\n let len = writer.write(command.as_bytes()).unwrap();\n if len \u003c 1 {\n panic!(\"write buffer len \u003c 0\");\n }\n Ok(())\n }\n}\n\n#[derive(Debug)]\n/// Main interface for communication to Saleae Logic\npub struct Client {\n /// tcp stream with connection to saleae\n connection: Connection,\n}\n\n/// Constructor\nimpl Client {\n /// constructor\n //TODO make this create a connection from a string\n pub fn new(connection: Connection) -\u003e Result\u003cClient\u003e {\n Ok(Client { connection })\n }\n}\n\n/// Interface for setting and getting Logic information\nimpl Client {\n /// Set a trigger of channels\n /// TODO create trigger methods/structs/tests\n\n pub fn set_num_samples(\u0026mut self, num: u32) -\u003e Result\u003cbool\u003e {\n self.connection\n .run_command(\u0026format!(\"set_num_samples, {}\\0\", num))?;\n Ok(self.connection.general_recieve_ack()?)\n }\n\n pub fn get_num_samples(\u0026mut self) -\u003e Result\u003cu32\u003e {\n self.connection.run_command(\"get_num_samples\\0\")?;\n let response = self.connection.general_recieve_message()?;\n if Response::verify_ack(\u0026response) {\n Ok(Response::parse_num_samples(\u0026Response::remove_ack(\n \u0026response,\n )))\n } else {\n Err(anyhow!(\"No ACK found\"))\n }\n }\n\n /// Set the capture duration to a length of time\n pub fn set_capture_seconds(\u0026mut self, seconds: f32) -\u003e Result\u003cbool\u003e {\n self.connection\n .run_command(\u0026format!(\"set_capture_seconds, {}\\0\", seconds))?;\n Ok(self.connection.general_recieve_ack()?)\n }\n\n /// Set sample rate of saleae\n ///\n /// Note: Make sure to run `get_all_sample_rates` and set it from a available\n /// sample rate\n pub fn set_sample_rate(\u0026mut self, rate: \u0026SampleRate) -\u003e Result\u003cbool\u003e {\n self.connection.run_command(\u0026format!(\n \"set_sample_rate, {}, {}\\0\",\n rate.DigitalSampleRate, rate.AnalogSampleRate\n ))?;\n Ok(self.connection.general_recieve_ack()?)\n }\n\n pub fn get_sample_rate(\u0026mut self) -\u003e Result\u003cSampleRate\u003e {\n self.connection.run_command(\"get_sample_rate\\0\")?;\n let response = self.connection.general_recieve_message()?;\n Ok(Response::parse_get_sample_rate(\u0026Response::remove_ack(\n \u0026response,\n )))\n }\n\n pub fn get_all_sample_rates(\u0026mut self) -\u003e Result\u003cVec\u003cSampleRate\u003e\u003e {\n self.connection.run_command(\"get_all_sample_rates\\0\")?;\n let response = self.connection.general_recieve_message()?;\n Ok(Response::parse_get_all_sample_rates(\u0026Response::remove_ack(\n \u0026response,\n )))\n }\n\n /// Return current performance level of Logic\n pub fn get_performance(\u0026mut self) -\u003e Result\u003cu8\u003e {\n self.connection.run_command(\"get_performance\\0\")?;\n let response = self.connection.general_recieve_message()?;\n Ok(Response::parse_performance(\u0026Response::remove_ack(\n \u0026response,\n )))\n }\n\n /// Set the performance value, controlling the USB traffic and quality\n pub fn set_performance(\u0026mut self, perf: PerformanceOption) -\u003e Result\u003cbool\u003e {\n let input = String::from(\u0026format!(\"set_performance, {}\\0\", perf as i32));\n self.connection.run_command(\u0026input)?;\n Ok(self.connection.general_recieve_ack()?)\n }\n\n //TODO get_capture_pretrigger_buffer_size\n\n /// Return current connected devices of Logic\n pub fn get_connected_devices(\u0026mut self) -\u003e Result\u003cVec\u003cConnectedDevice\u003e\u003e {\n self.connection.run_command(\"get_connected_devices\\0\")?;\n let response = self.connection.general_recieve_message()?;\n Ok(Response::parse_connected_devices(\u0026Response::remove_ack(\n \u0026response,\n )))\n }\n\n /// Find index of device from the list of devices connected to Saleae\n ///\n /// Get current index of connected devices and find equal device to parameter.\n /// Send that device as active device to logic.\n ///\n /// Note: Indices start at 1, not 0\n /// TODO: test with multiple saleae\n pub fn select_active_device(\u0026mut self, device: ConnectedDevice) -\u003e Result\u003cbool\u003e {\n let b = self\n .get_connected_devices()\n .unwrap()\n .into_iter()\n .position(|a| a == device);\n self.connection\n .run_command(\u0026format!(\"select_active_device, {}\", b.unwrap() + 1))?;\n // Weirdly doesn't return an ACK\n Ok(true)\n }\n\n /// Return current active device of Logic\n pub fn get_active_device(\u0026mut self) -\u003e Result\u003cConnectedDevice\u003e {\n self.connection.run_command(\"get_connected_devices\\0\")?;\n let response = self.connection.general_recieve_message()?;\n Ok(\n Response::parse_connected_devices(\u0026Response::remove_ack(\u0026response))\n .into_iter()\n .find(|a| a.is_active)\n .unwrap(),\n )\n }\n\n /// Parse the get active channels command into tuples of digital and analog\n /// channels that are current\n pub fn get_active_channels(\u0026mut self) -\u003e Result\u003cVec\u003cVec\u003cu8\u003e\u003e\u003e {\n self.connection.run_command(\"get_active_channels\\0\")?;\n let response = self.connection.general_recieve_message()?;\n Ok(Response::parse_get_active_channels(\u0026Response::remove_ack(\n \u0026response,\n ))?)\n }\n\n /// Set the active channels for the Logic program\n ///\n /// # Example\n /// TODO add get_active_channels\n pub fn set_active_channels(\n \u0026mut self,\n digital_channels: \u0026[u8],\n analog_channels: \u0026[u8],\n ) -\u003e Result\u003cbool\u003e {\n self.connection\n .run_command(\u0026Request::prepare_set_active_channels(\n \u0026digital_channels,\n \u0026analog_channels,\n )?)?;\n Ok(self.connection.general_recieve_ack()?)\n }\n\n /// Reset Active Channel\n pub fn reset_active_channels(\u0026mut self) -\u003e Result\u003cbool\u003e {\n self.connection.run_command(\"reset_active_channels\\0\")?;\n Ok(self.connection.general_recieve_ack()?)\n }\n\n //TODO get_digital_voltage_options OR get_full_scale_voltage_range\n //TODO set_full_scale_voltage_range\n\n /// Start Capture, without wating for ack/nack\n pub fn start_capture(\u0026mut self) -\u003e Result\u003cbool\u003e {\n self.connection.run_command(\"capture\\0\")?;\n Ok(true)\n // Doesn't return ACK\n }\n\n /// Start Capture, then wait until ack\n pub fn start_capture_block_until_finished(\u0026mut self) -\u003e Result\u003cbool\u003e {\n self.start_capture()?;\n Ok(self.connection.general_recieve_ack()?)\n }\n\n /// Check if processing is complete\n pub fn is_processing_complete(\u0026mut self) -\u003e Result\u003cbool\u003e {\n self.connection.run_command(\"is_processing_complete\\0\")?;\n let response = self.connection.general_recieve_message()?;\n Ok(Response::parse_processing_complete(\u0026Response::remove_ack(\n \u0026response,\n )))\n }\n\n /// Stop the saleae capture\n pub fn stop_capture(\u0026mut self) -\u003e Result\u003cbool\u003e {\n self.connection.run_command(\"stop_capture\\0\")?;\n Ok(self.connection.general_recieve_ack()?)\n }\n\n //TODO capture_to_file\n //TODO save_to_file\n //TODO load_from_file\n\n /// Close all tabs\n pub fn close_all_tabs(\u0026mut self) -\u003e Result\u003cbool\u003e {\n self.connection.run_command(\"close_all_tabs\\0\")?;\n Ok(self.connection.general_recieve_ack()?)\n }\n\n //TODO export_data2\n //TODO get_analyzers\n //TODO export_analyzer\n //TODO is_analyzer_complete\n //TODO get_capture_range\n //TODO get_viewstate\n //TODO get_viewstate\n //TODO exit\n}\n","traces":[{"line":23,"address":4253312,"length":1,"stats":{"Line":0}},{"line":25,"address":4253326,"length":1,"stats":{"Line":0}},{"line":29,"address":4253392,"length":1,"stats":{"Line":0}},{"line":30,"address":4253407,"length":1,"stats":{"Line":0}},{"line":31,"address":4254006,"length":1,"stats":{"Line":0}},{"line":34,"address":4254512,"length":1,"stats":{"Line":0}},{"line":35,"address":4254527,"length":1,"stats":{"Line":0}},{"line":36,"address":4255117,"length":1,"stats":{"Line":0}},{"line":37,"address":4255160,"length":1,"stats":{"Line":0}},{"line":40,"address":null,"length":0,"stats":{"Line":0}},{"line":41,"address":4255695,"length":1,"stats":{"Line":0}},{"line":42,"address":4255762,"length":1,"stats":{"Line":0}},{"line":43,"address":4255819,"length":1,"stats":{"Line":0}},{"line":44,"address":4256050,"length":1,"stats":{"Line":0}},{"line":45,"address":4256119,"length":1,"stats":{"Line":0}},{"line":47,"address":4256061,"length":1,"stats":{"Line":0}},{"line":51,"address":4256336,"length":1,"stats":{"Line":0}},{"line":52,"address":4256358,"length":1,"stats":{"Line":0}},{"line":53,"address":4256387,"length":1,"stats":{"Line":0}},{"line":54,"address":4256545,"length":1,"stats":{"Line":0}},{"line":55,"address":4256565,"length":1,"stats":{"Line":0}},{"line":57,"address":null,"length":0,"stats":{"Line":0}},{"line":72,"address":4233664,"length":1,"stats":{"Line":6}},{"line":73,"address":4233674,"length":1,"stats":{"Line":6}},{"line":82,"address":4233808,"length":1,"stats":{"Line":1}},{"line":83,"address":4233834,"length":1,"stats":{"Line":1}},{"line":84,"address":4233839,"length":1,"stats":{"Line":1}},{"line":85,"address":4234352,"length":1,"stats":{"Line":1}},{"line":88,"address":4234720,"length":1,"stats":{"Line":2}},{"line":89,"address":4234742,"length":1,"stats":{"Line":2}},{"line":90,"address":4234993,"length":1,"stats":{"Line":2}},{"line":91,"address":4235286,"length":1,"stats":{"Line":2}},{"line":92,"address":4235414,"length":1,"stats":{"Line":1}},{"line":93,"address":4235379,"length":1,"stats":{"Line":1}},{"line":96,"address":4235344,"length":1,"stats":{"Line":1}},{"line":101,"address":4235776,"length":1,"stats":{"Line":1}},{"line":102,"address":4235804,"length":1,"stats":{"Line":1}},{"line":103,"address":4235809,"length":1,"stats":{"Line":1}},{"line":104,"address":4236321,"length":1,"stats":{"Line":1}},{"line":111,"address":4236688,"length":1,"stats":{"Line":1}},{"line":112,"address":4236718,"length":1,"stats":{"Line":1}},{"line":113,"address":4236723,"length":1,"stats":{"Line":1}},{"line":114,"address":4236730,"length":1,"stats":{"Line":1}},{"line":116,"address":4237352,"length":1,"stats":{"Line":1}},{"line":119,"address":4237728,"length":1,"stats":{"Line":1}},{"line":120,"address":4237750,"length":1,"stats":{"Line":1}},{"line":121,"address":4237973,"length":1,"stats":{"Line":1}},{"line":122,"address":4238305,"length":1,"stats":{"Line":1}},{"line":123,"address":4238260,"length":1,"stats":{"Line":1}},{"line":127,"address":4238688,"length":1,"stats":{"Line":0}},{"line":128,"address":4238710,"length":1,"stats":{"Line":0}},{"line":129,"address":4238933,"length":1,"stats":{"Line":0}},{"line":130,"address":4239262,"length":1,"stats":{"Line":0}},{"line":131,"address":4239217,"length":1,"stats":{"Line":0}},{"line":136,"address":4239648,"length":1,"stats":{"Line":1}},{"line":137,"address":4239670,"length":1,"stats":{"Line":1}},{"line":138,"address":4239893,"length":1,"stats":{"Line":1}},{"line":139,"address":4240225,"length":1,"stats":{"Line":1}},{"line":140,"address":4240180,"length":1,"stats":{"Line":1}},{"line":145,"address":4240592,"length":1,"stats":{"Line":1}},{"line":146,"address":4240618,"length":1,"stats":{"Line":1}},{"line":147,"address":4240941,"length":1,"stats":{"Line":1}},{"line":148,"address":4241221,"length":1,"stats":{"Line":1}},{"line":154,"address":4241760,"length":1,"stats":{"Line":1}},{"line":155,"address":4241782,"length":1,"stats":{"Line":1}},{"line":156,"address":4242005,"length":1,"stats":{"Line":1}},{"line":157,"address":4242334,"length":1,"stats":{"Line":1}},{"line":158,"address":4242289,"length":1,"stats":{"Line":1}},{"line":169,"address":4242720,"length":1,"stats":{"Line":0}},{"line":170,"address":4242738,"length":1,"stats":{"Line":0}},{"line":171,"address":null,"length":0,"stats":{"Line":0}},{"line":172,"address":null,"length":0,"stats":{"Line":0}},{"line":173,"address":null,"length":0,"stats":{"Line":0}},{"line":174,"address":4230688,"length":1,"stats":{"Line":0}},{"line":175,"address":4242973,"length":1,"stats":{"Line":0}},{"line":176,"address":4242981,"length":1,"stats":{"Line":0}},{"line":182,"address":4243792,"length":1,"stats":{"Line":0}},{"line":183,"address":4243814,"length":1,"stats":{"Line":0}},{"line":184,"address":4244037,"length":1,"stats":{"Line":0}},{"line":186,"address":4244321,"length":1,"stats":{"Line":0}},{"line":187,"address":null,"length":0,"stats":{"Line":0}},{"line":188,"address":4230800,"length":1,"stats":{"Line":0}},{"line":189,"address":null,"length":0,"stats":{"Line":0}},{"line":195,"address":4244944,"length":1,"stats":{"Line":1}},{"line":196,"address":4244966,"length":1,"stats":{"Line":1}},{"line":197,"address":4245205,"length":1,"stats":{"Line":1}},{"line":198,"address":4245537,"length":1,"stats":{"Line":1}},{"line":199,"address":4245492,"length":1,"stats":{"Line":1}},{"line":207,"address":4246448,"length":1,"stats":{"Line":1}},{"line":212,"address":4246483,"length":1,"stats":{"Line":1}},{"line":213,"address":4246524,"length":1,"stats":{"Line":1}},{"line":214,"address":4246504,"length":1,"stats":{"Line":1}},{"line":215,"address":4246514,"length":1,"stats":{"Line":1}},{"line":217,"address":4247085,"length":1,"stats":{"Line":1}},{"line":221,"address":4247760,"length":1,"stats":{"Line":1}},{"line":222,"address":4247782,"length":1,"stats":{"Line":1}},{"line":223,"address":4248002,"length":1,"stats":{"Line":1}},{"line":230,"address":4248288,"length":1,"stats":{"Line":1}},{"line":231,"address":4248307,"length":1,"stats":{"Line":1}},{"line":237,"address":4248576,"length":1,"stats":{"Line":1}},{"line":238,"address":4248591,"length":1,"stats":{"Line":1}},{"line":239,"address":4248794,"length":1,"stats":{"Line":1}},{"line":243,"address":4249088,"length":1,"stats":{"Line":1}},{"line":244,"address":4249110,"length":1,"stats":{"Line":1}},{"line":245,"address":4249333,"length":1,"stats":{"Line":1}},{"line":246,"address":4249665,"length":1,"stats":{"Line":1}},{"line":247,"address":4249620,"length":1,"stats":{"Line":1}},{"line":252,"address":4250032,"length":1,"stats":{"Line":1}},{"line":253,"address":4250054,"length":1,"stats":{"Line":1}},{"line":254,"address":4250274,"length":1,"stats":{"Line":1}},{"line":262,"address":4250560,"length":1,"stats":{"Line":1}},{"line":263,"address":4250582,"length":1,"stats":{"Line":1}},{"line":264,"address":4250802,"length":1,"stats":{"Line":1}}],"covered":71,"coverable":113},{"path":["/","home","wcampbell","projects","wcampbell","code","saleae","src","device.rs"],"content":"//! This module defines devices that are connected to the saleae logic program.\n//!\n//! ## Example of response from Logic\n//! ```text\n//! 1, Logic Pro 16, LOGIC_PRO_16_DEVICE, 0xdf03c43d1f3aa2f3, ACTIVE\n//! ```\n//! ## C# struct\n//! ```text\n//! struct ConnectedDevices\n//! {\n//! String type;\n//! String name;\n//! int device_id;\n//! int index;\n//! bool is_active;\n//! }\n//! ```\n\nuse anyhow::Result;\nuse std::str::FromStr;\n\ncustom_derive! {\n /// Device id for saleae devices\n #[allow(non_camel_case_types)]\n #[derive(Debug, EnumFromStr, PartialEq)]\n pub enum DeviceID {\n /// Regular 4 Wire device\n LOGIC_4_DEVICE,\n /// Regular 8 Wire device\n LOGIC_8_DEVICE,\n /// Pro 8 Wire device\n LOGIC_PRO_8_DEVICE,\n /// Pro 16 Wire device\n LOGIC_PRO_16_DEVICE,\n }\n}\n\n/// Connected Device to saleae, the main usability comes from the fromStr trait.\n#[derive(Debug, PartialEq)]\npub struct ConnectedDevice {\n /// type of device\n pub d_type: String,\n /// name of device\n pub name: String,\n /// id of device\n pub device_id: DeviceID,\n /// index of device\n pub index: String,\n /// if device is active\n pub is_active: bool,\n}\n\nimpl FromStr for ConnectedDevice {\n type Err = std::num::ParseIntError;\n fn from_str(response: \u0026str) -\u003e Result\u003cSelf, Self::Err\u003e {\n let v: Vec\u003c\u0026str\u003e = response.split(',').map(|a| a.trim_start()).collect();\n\n /* parse into device_id */\n let device_id: DeviceID = v[2].parse().unwrap();\n\n /*\n * last element is ACTIVE, if that element doesn't don't cause a panic by\n * checking that element\n */\n let is_active = v.len() == 5 \u0026\u0026 v[4] == \"ACTIVE\";\n\n Ok(ConnectedDevice {\n d_type: v[0].to_string(),\n name: v[1].to_string(),\n device_id,\n index: v[3].to_string(),\n is_active,\n })\n }\n}\n","traces":[{"line":55,"address":4227568,"length":1,"stats":{"Line":3}},{"line":56,"address":4227588,"length":1,"stats":{"Line":6}},{"line":59,"address":4227696,"length":1,"stats":{"Line":3}},{"line":65,"address":4227784,"length":1,"stats":{"Line":3}},{"line":67,"address":4228081,"length":1,"stats":{"Line":3}},{"line":68,"address":4227847,"length":1,"stats":{"Line":3}},{"line":69,"address":4227942,"length":1,"stats":{"Line":3}},{"line":70,"address":4227999,"length":1,"stats":{"Line":3}},{"line":71,"address":4228020,"length":1,"stats":{"Line":3}},{"line":72,"address":4228074,"length":1,"stats":{"Line":3}}],"covered":10,"coverable":10},{"path":["/","home","wcampbell","projects","wcampbell","code","saleae","src","request.rs"],"content":"//! This module helps create requests to the Saleae Logic software\n//!\n//! The function here parse and type check the input from the API into strings to send into\n//! the Saleae socket\nuse anyhow::Result;\n\npub struct Request {}\n\nimpl Request {\n pub fn prepare_set_active_channels(\n digital_channels: \u0026[u8],\n analog_channels: \u0026[u8],\n ) -\u003e Result\u003cString\u003e {\n // Check only one kind of empty\n if digital_channels.is_empty() \u0026\u0026 analog_channels.is_empty() {\n return Err(anyhow!(\n \"Logic requires at least one active channel, no active channels found\"\n ));\n }\n\n let d_str = if !digital_channels.is_empty() {\n format!(\n \", digital_channels, {}\",\n Request::create_channel_str(digital_channels)?\n )\n } else {\n \"\".to_string()\n };\n\n let a_str = if !analog_channels.is_empty() {\n format!(\n \", analog_channels, {}\",\n Request::create_channel_str(analog_channels)?\n )\n } else {\n \"\".to_string()\n };\n\n Ok(format!(\"set_active_channels{}{}\\0\", d_str, a_str))\n }\n}\n\n/// Helper functions\nimpl Request {\n pub fn create_channel_str(v: \u0026[u8]) -\u003e Result\u003cString\u003e {\n let s = v\n .iter()\n .map(|a| format!(\"{}, \", a.to_string()))\n .collect::\u003cString\u003e();\n Ok(s[..s.len() - 2].to_string())\n }\n}\n","traces":[{"line":10,"address":4286880,"length":1,"stats":{"Line":2}},{"line":15,"address":4286922,"length":1,"stats":{"Line":2}},{"line":16,"address":4287143,"length":1,"stats":{"Line":1}},{"line":17,"address":null,"length":0,"stats":{"Line":0}},{"line":21,"address":4287106,"length":1,"stats":{"Line":2}},{"line":22,"address":4287351,"length":1,"stats":{"Line":0}},{"line":23,"address":4287253,"length":1,"stats":{"Line":2}},{"line":24,"address":4287260,"length":1,"stats":{"Line":2}},{"line":27,"address":4287228,"length":1,"stats":{"Line":1}},{"line":30,"address":4287758,"length":1,"stats":{"Line":2}},{"line":31,"address":4287946,"length":1,"stats":{"Line":0}},{"line":32,"address":4287844,"length":1,"stats":{"Line":2}},{"line":33,"address":4287851,"length":1,"stats":{"Line":2}},{"line":36,"address":4287815,"length":1,"stats":{"Line":1}},{"line":39,"address":4288349,"length":1,"stats":{"Line":2}},{"line":45,"address":4289584,"length":1,"stats":{"Line":2}},{"line":46,"address":4289604,"length":1,"stats":{"Line":2}},{"line":47,"address":null,"length":0,"stats":{"Line":0}},{"line":48,"address":4232032,"length":1,"stats":{"Line":2}},{"line":49,"address":null,"length":0,"stats":{"Line":0}},{"line":50,"address":4289710,"length":1,"stats":{"Line":2}}],"covered":16,"coverable":21},{"path":["/","home","wcampbell","projects","wcampbell","code","saleae","src","response.rs"],"content":"//! This module help discern and parse the responses from saleae\n\nuse crate::device::ConnectedDevice;\nuse crate::samplerate::SampleRate;\nuse anyhow::Result;\nuse std::str::FromStr;\n\n/// struct to handle responses\npub struct Response {}\n\n//TODO add errors\nimpl Response {\n /// Return string without \"\\nACK\" string line nor extra 0 char's from buffer\n pub fn remove_ack(response: \u0026str) -\u003e String {\n response\n .trim_end_matches(char::from(0))\n .trim_end_matches(\"\\nACK\")\n .to_string()\n }\n\n /// Check if last string is ACK\n pub fn verify_ack(response: \u0026str) -\u003e bool {\n response.lines().last().unwrap() == \"ACK\"\n }\n\n /// Parse the performance response\n ///\n /// # Sample Input\n /// The following values are expected as input:\n /// ```text, no_run\n /// 100\n /// 80\n /// 60\n /// 40\n /// 20\n /// ```\n pub fn parse_performance(response: \u0026str) -\u003e u8 {\n response.parse::\u003cu8\u003e().unwrap()\n }\n\n pub fn parse_num_samples(response: \u0026str) -\u003e u32 {\n response.parse::\u003cu32\u003e().unwrap()\n }\n\n ///\n pub fn parse_get_sample_rate(response: \u0026str) -\u003e SampleRate {\n let mut iter = response.lines();\n SampleRate {\n DigitalSampleRate: iter.next().unwrap().parse::\u003cu32\u003e().unwrap(),\n AnalogSampleRate: iter.next().unwrap().parse::\u003cu32\u003e().unwrap(),\n }\n }\n\n /// Parse get all sample rates\n ///\n /// # Sample input\n /// ```text\n /// 5000000, 1250000\n /// 10000000, 625000\n /// ```\n pub fn parse_get_all_sample_rates(response: \u0026str) -\u003e Vec\u003cSampleRate\u003e {\n response\n .lines()\n .map(|a| SampleRate::from_str(\u0026a).unwrap())\n .collect()\n }\n\n /// Parse the connected_devices reponse into ConnectedDevice\n ///\n /// # Sample Input\n /// ```text\n /// 1, Logic Pro 16, LOGIC_PRO_16_DEVICE, 0xdf03c43d1f3aa2f3, ACTIVE\n /// ```\n pub fn parse_connected_devices(response: \u0026str) -\u003e Vec\u003cConnectedDevice\u003e {\n response\n .lines()\n .map(|a| ConnectedDevice::from_str(\u0026a).unwrap())\n .collect()\n }\n\n pub fn parse_get_active_channels(response: \u0026str) -\u003e Result\u003cVec\u003cVec\u003cu8\u003e\u003e\u003e {\n println!(\"{}\", response);\n let v: Vec\u003c\u0026str\u003e = response.split(',').map(|a| a.trim_start()).collect();\n\n // Find position of starter word\n let digital_pos = v.iter().position(|a| *a == \"digital_channels\").unwrap();\n let analog_pos = v.iter().position(|a| *a == \"analog_channels\").unwrap();\n\n // Parse in between words to find values\n let digital_res: Vec\u003cu8\u003e = v[digital_pos + 1..analog_pos]\n .iter()\n .map(|a| a.parse().unwrap())\n .collect();\n\n let analog_res: Vec\u003cu8\u003e = v[analog_pos + 1..v.len()]\n .iter()\n .map(|a| a.parse().unwrap())\n .collect();\n Ok(vec![digital_res, analog_res])\n }\n\n /// Parse if processing is complete\n ///\n /// # Sample Input\n /// ```text\n /// FALSE\n /// ```\n /// ```text\n /// TRUE\n /// ```\n pub fn parse_processing_complete(response: \u0026str) -\u003e bool {\n response == \"TRUE\"\n }\n}\n","traces":[{"line":14,"address":4279104,"length":1,"stats":{"Line":5}},{"line":15,"address":4279123,"length":1,"stats":{"Line":5}},{"line":22,"address":4279264,"length":1,"stats":{"Line":3}},{"line":23,"address":4279281,"length":1,"stats":{"Line":3}},{"line":37,"address":4279392,"length":1,"stats":{"Line":2}},{"line":38,"address":4279406,"length":1,"stats":{"Line":2}},{"line":41,"address":4279488,"length":1,"stats":{"Line":2}},{"line":42,"address":4279502,"length":1,"stats":{"Line":2}},{"line":46,"address":4279568,"length":1,"stats":{"Line":1}},{"line":47,"address":4279585,"length":1,"stats":{"Line":1}},{"line":49,"address":4279633,"length":1,"stats":{"Line":1}},{"line":50,"address":4279784,"length":1,"stats":{"Line":1}},{"line":61,"address":4279984,"length":1,"stats":{"Line":1}},{"line":62,"address":4280004,"length":1,"stats":{"Line":1}},{"line":74,"address":4280080,"length":1,"stats":{"Line":2}},{"line":75,"address":4280100,"length":1,"stats":{"Line":2}},{"line":81,"address":4280176,"length":1,"stats":{"Line":2}},{"line":82,"address":4280202,"length":1,"stats":{"Line":2}},{"line":83,"address":4280435,"length":1,"stats":{"Line":4}},{"line":86,"address":4280520,"length":1,"stats":{"Line":4}},{"line":87,"address":4280729,"length":1,"stats":{"Line":4}},{"line":90,"address":4280912,"length":1,"stats":{"Line":2}},{"line":91,"address":null,"length":0,"stats":{"Line":0}},{"line":92,"address":4336736,"length":1,"stats":{"Line":2}},{"line":93,"address":4281093,"length":1,"stats":{"Line":2}},{"line":95,"address":4281101,"length":1,"stats":{"Line":2}},{"line":96,"address":null,"length":0,"stats":{"Line":0}},{"line":97,"address":4336832,"length":1,"stats":{"Line":2}},{"line":98,"address":null,"length":0,"stats":{"Line":0}},{"line":99,"address":4281308,"length":1,"stats":{"Line":2}},{"line":111,"address":4281696,"length":1,"stats":{"Line":2}},{"line":112,"address":4281710,"length":1,"stats":{"Line":2}}],"covered":29,"coverable":32},{"path":["/","home","wcampbell","projects","wcampbell","code","saleae","src","samplerate.rs"],"content":"//! This module defines the sample rates returned and used by the saleae Logic program\n//!\n//! # C# Example\n//! ```text\n//! struct SampleRate\n//! {\n//! public int AnalogSampleRate;\n//! public int DigitalSampleRate;\n//! }\n//! ```\nuse std::str::FromStr;\n\n#[allow(non_snake_case)]\n#[derive(Debug, PartialEq)]\npub struct SampleRate {\n pub DigitalSampleRate: u32,\n pub AnalogSampleRate: u32,\n}\n\nimpl FromStr for SampleRate {\n type Err = std::num::ParseIntError;\n fn from_str(response: \u0026str) -\u003e Result\u003cSelf, Self::Err\u003e {\n let v: Vec\u003c\u0026str\u003e = response.split(',').map(|a| a.trim_start()).collect();\n\n Ok(SampleRate {\n DigitalSampleRate: v[0].parse::\u003cu32\u003e().unwrap(),\n AnalogSampleRate: v[1].parse::\u003cu32\u003e().unwrap(),\n })\n }\n}\n","traces":[{"line":22,"address":4211904,"length":1,"stats":{"Line":2}},{"line":23,"address":4211924,"length":1,"stats":{"Line":4}},{"line":25,"address":4212233,"length":1,"stats":{"Line":2}},{"line":26,"address":4212025,"length":1,"stats":{"Line":2}},{"line":27,"address":4212138,"length":1,"stats":{"Line":2}}],"covered":5,"coverable":5},{"path":["/","home","wcampbell","projects","wcampbell","code","saleae","tests","client.rs"],"content":"#[cfg(test)]\nmod tests {\n use saleae::client::{Client, Connection};\n use saleae::device::DeviceID;\n use saleae::ConnectedDevice;\n use saleae::PerformanceOption;\n use saleae::SampleRate;\n\n #[test]\n fn set_num_samples() {\n let mut conn = Connection::faux();\n unsafe { faux::when!(conn.run_command).then(|_| Ok(())) }\n unsafe { faux::when!(conn.general_recieve_ack).then(|_| Ok(true)) }\n\n let mut conn = Client::new(conn).unwrap();\n let response = conn.set_num_samples(500).unwrap();\n assert_eq!(true, response);\n }\n\n #[test]\n fn get_num_samples() {\n let mut conn = Connection::faux();\n unsafe { faux::when!(conn.run_command).then(|_| Ok(())) }\n unsafe { faux::when!(conn.general_recieve_message).then(|_| Ok(\"3000\\nACK\".to_string())) }\n\n let mut conn = Client::new(conn).unwrap();\n let response = conn.get_num_samples().unwrap();\n assert_eq!(3000, response);\n }\n\n #[test]\n #[should_panic]\n fn get_num_samples_fail() {\n let mut conn = Connection::faux();\n unsafe { faux::when!(conn.run_command).then(|_| Ok(())) }\n unsafe { faux::when!(conn.general_recieve_message).then(|_| Ok(\"3000\".to_string())) }\n\n let mut conn = Client::new(conn).unwrap();\n let response = conn.get_num_samples().unwrap();\n assert_eq!(3000, response);\n }\n\n #[test]\n fn set_capture_seconds() {\n let mut conn = Connection::faux();\n unsafe { faux::when!(conn.run_command).then(|_| Ok(())) }\n unsafe { faux::when!(conn.general_recieve_ack).then(|_| Ok(true)) }\n\n let mut conn = Client::new(conn).unwrap();\n let response = conn.set_capture_seconds(2.2).unwrap();\n assert_eq!(true, response);\n }\n\n #[test]\n fn set_sample_rate() {\n let mut conn = Connection::faux();\n unsafe { faux::when!(conn.run_command).then(|_| Ok(())) }\n unsafe { faux::when!(conn.general_recieve_ack).then(|_| Ok(true)) }\n\n let mut conn = Client::new(conn).unwrap();\n let response = conn\n .set_sample_rate(\u0026SampleRate {\n AnalogSampleRate: 6250000,\n DigitalSampleRate: 1562500,\n })\n .unwrap();\n assert_eq!(true, response);\n }\n\n #[test]\n fn get_sample_rate() {\n let mut conn = Connection::faux();\n unsafe { faux::when!(conn.run_command).then(|_| Ok(())) }\n unsafe {\n faux::when!(conn.general_recieve_message).then(|_| Ok(\"1000000\\n0\\n\".to_string()))\n }\n\n let mut conn = Client::new(conn).unwrap();\n let response = conn.get_sample_rate().unwrap();\n assert_eq!(response.DigitalSampleRate, 1000000);\n assert_eq!(response.AnalogSampleRate, 0);\n }\n\n #[test]\n fn get_performance() {\n let mut conn = Connection::faux();\n unsafe { faux::when!(conn.run_command).then(|_| Ok(())) }\n unsafe { faux::when!(conn.general_recieve_message).then(|_| Ok(\"100\".to_string())) }\n\n let mut conn = Client::new(conn).unwrap();\n let response = conn.get_performance().unwrap();\n assert_eq!(response, 100);\n }\n\n #[test]\n fn set_performance() {\n let mut conn = Connection::faux();\n unsafe { faux::when!(conn.run_command).then(|_| Ok(())) }\n unsafe { faux::when!(conn.general_recieve_ack).then(|_| Ok(true)) }\n\n let mut conn = Client::new(conn).unwrap();\n let response = conn.set_performance(PerformanceOption::Full).unwrap();\n assert_eq!(response, true);\n\n let mut conn2 = Connection::faux();\n unsafe { faux::when!(conn2.run_command).then(|_| Ok(())) }\n unsafe { faux::when!(conn2.general_recieve_ack).then(|_| Ok(false)) }\n\n let mut conn2 = Client::new(conn2).unwrap();\n let response2 = conn2.set_performance(PerformanceOption::Low).unwrap();\n assert_eq!(response2, false);\n }\n\n #[test]\n fn get_connected_devices() {\n let mut conn = Connection::faux();\n unsafe { faux::when!(conn.run_command).then(|_| Ok(())) }\n unsafe {\n faux::when!(conn.general_recieve_message).then(|_| Ok(\"1, Logic 8, LOGIC_8_DEVICE, 0x2dc9, ACTIVE\\n2, Logic Pro 8, LOGIC_PRO_8_DEVICE, 0x7243\\n3, Logic Pro 16, LOGIC_PRO_16_DEVICE, 0x673f\\n4, Logic 4, LOGIC_4_DEVICE, 0x6709\\nACK\".to_string()))\n }\n\n let mut conn = Client::new(conn).unwrap();\n let response = conn.get_connected_devices().unwrap();\n assert_eq!(\n response[0],\n ConnectedDevice {\n d_type: \"1\".to_string(),\n name: \"Logic 8\".to_string(),\n device_id: DeviceID::LOGIC_8_DEVICE,\n index: \"0x2dc9\".to_string(),\n is_active: true\n }\n );\n assert_eq!(\n response[1],\n ConnectedDevice {\n d_type: \"2\".to_string(),\n name: \"Logic Pro 8\".to_string(),\n device_id: DeviceID::LOGIC_PRO_8_DEVICE,\n index: \"0x7243\".to_string(),\n is_active: false\n }\n );\n assert_eq!(\n response[2],\n ConnectedDevice {\n d_type: \"3\".to_string(),\n name: \"Logic Pro 16\".to_string(),\n device_id: DeviceID::LOGIC_PRO_16_DEVICE,\n index: \"0x673f\".to_string(),\n is_active: false\n }\n );\n assert_eq!(\n response[3],\n ConnectedDevice {\n d_type: \"4\".to_string(),\n name: \"Logic 4\".to_string(),\n device_id: DeviceID::LOGIC_4_DEVICE,\n index: \"0x6709\".to_string(),\n is_active: false\n }\n );\n }\n\n #[test]\n fn select_active_device() {\n //TODO can't test b/c of get_connected_devices not being fauxable\n //let device = ConnectedDevice {\n // d_type: \"4\".to_string(),\n // name: \"Logic 4\".to_string(),\n // device_id: DeviceID::LOGIC_4_DEVICE,\n // index: \"0x6709\".to_string(),\n // is_active: false,\n //};\n\n //let mut conn = Connection::faux();\n //unsafe { faux::when!(conn.get_connected_devices).then(|_| Ok(device)) };\n //unsafe { faux::when!(conn.run_command).then(|_| Ok(())) }\n\n //let mut conn = Client::new(conn).unwrap();\n //let response = conn.select_active_device(device).unwrap();\n //assert_eq!(response, true);\n }\n\n #[test]\n fn get_active_device() {\n let mut conn = Connection::faux();\n unsafe { faux::when!(conn.run_command).then(|_| Ok(())) }\n unsafe {\n faux::when!(conn.general_recieve_message).then(|_| {\n Ok(\"digital_channels, 0, 4, 5, 7, analog_channels, 0, 1, 2, 5, 8\".to_string())\n })\n }\n\n let mut conn = Client::new(conn).unwrap();\n let response = conn.get_active_channels().unwrap();\n assert_eq!(response[0], [0, 4, 5, 7]);\n assert_eq!(response[1], [0, 1, 2, 5, 8]);\n }\n\n #[test]\n fn set_active_channels() {\n let mut conn = Connection::faux();\n unsafe { faux::when!(conn.run_command).then(|_| Ok(())) }\n unsafe { faux::when!(conn.general_recieve_ack).then(|_| Ok(true)) }\n\n let mut conn = Client::new(conn).unwrap();\n let response = conn\n .set_active_channels(\u0026[0, 4, 5, 7], \u0026[0, 1, 2, 5, 8])\n .unwrap();\n assert_eq!(response, true);\n }\n\n #[test]\n fn reset_active_channels() {\n let mut conn = Connection::faux();\n unsafe { faux::when!(conn.run_command).then(|_| Ok(())) }\n unsafe { faux::when!(conn.general_recieve_ack).then(|_| Ok(true)) }\n\n let mut conn = Client::new(conn).unwrap();\n let response = conn.reset_active_channels().unwrap();\n assert_eq!(response, true);\n }\n\n #[test]\n fn start_capture() {\n let mut conn = Connection::faux();\n unsafe { faux::when!(conn.run_command).then(|_| Ok(())) }\n\n let mut conn = Client::new(conn).unwrap();\n let response = conn.start_capture().unwrap();\n assert_eq!(response, true);\n }\n\n #[test]\n fn start_capture_block_until_finished() {\n let mut conn = Connection::faux();\n unsafe { faux::when!(conn.run_command).then(|_| Ok(())) }\n unsafe { faux::when!(conn.general_recieve_ack).then(|_| Ok(true)) }\n\n let mut conn = Client::new(conn).unwrap();\n let response = conn.start_capture_block_until_finished().unwrap();\n assert_eq!(response, true);\n }\n\n #[test]\n fn is_processing_complete() {\n let mut conn = Connection::faux();\n unsafe { faux::when!(conn.run_command).then(|_| Ok(())) }\n unsafe { faux::when!(conn.general_recieve_message).then(|_| Ok(\"TRUE\\nACK\".to_string())) }\n\n let mut conn = Client::new(conn).unwrap();\n let response = conn.is_processing_complete().unwrap();\n assert_eq!(response, true);\n }\n\n #[test]\n fn stop_capture() {\n let mut conn = Connection::faux();\n unsafe { faux::when!(conn.run_command).then(|_| Ok(())) }\n unsafe { faux::when!(conn.general_recieve_ack).then(|_| Ok(true)) }\n\n let mut conn = Client::new(conn).unwrap();\n let response = conn.stop_capture().unwrap();\n assert_eq!(response, true);\n }\n\n #[test]\n fn close_all_tabs() {\n let mut conn = Connection::faux();\n unsafe { faux::when!(conn.run_command).then(|_| Ok(())) }\n unsafe { faux::when!(conn.general_recieve_ack).then(|_| Ok(true)) }\n\n let mut conn = Client::new(conn).unwrap();\n let response = conn.close_all_tabs().unwrap();\n assert_eq!(response, true);\n }\n}\n","traces":[{"line":10,"address":4240032,"length":1,"stats":{"Line":2}},{"line":11,"address":4240039,"length":1,"stats":{"Line":1}},{"line":12,"address":4240083,"length":1,"stats":{"Line":2}},{"line":13,"address":4240122,"length":1,"stats":{"Line":2}},{"line":15,"address":4240161,"length":1,"stats":{"Line":1}},{"line":16,"address":4240294,"length":1,"stats":{"Line":1}},{"line":17,"address":4240383,"length":1,"stats":{"Line":1}},{"line":21,"address":4240912,"length":1,"stats":{"Line":2}},{"line":22,"address":4240919,"length":1,"stats":{"Line":1}},{"line":23,"address":4240963,"length":1,"stats":{"Line":2}},{"line":24,"address":4241002,"length":1,"stats":{"Line":2}},{"line":26,"address":4241041,"length":1,"stats":{"Line":1}},{"line":27,"address":4241174,"length":1,"stats":{"Line":1}},{"line":28,"address":4241256,"length":1,"stats":{"Line":1}},{"line":33,"address":4241776,"length":1,"stats":{"Line":2}},{"line":34,"address":4241783,"length":1,"stats":{"Line":1}},{"line":35,"address":4241827,"length":1,"stats":{"Line":2}},{"line":36,"address":4241866,"length":1,"stats":{"Line":2}},{"line":38,"address":4241905,"length":1,"stats":{"Line":1}},{"line":39,"address":4242038,"length":1,"stats":{"Line":1}},{"line":40,"address":4242120,"length":1,"stats":{"Line":0}},{"line":44,"address":4242640,"length":1,"stats":{"Line":2}},{"line":45,"address":4242647,"length":1,"stats":{"Line":1}},{"line":46,"address":4242691,"length":1,"stats":{"Line":2}},{"line":47,"address":4242730,"length":1,"stats":{"Line":2}},{"line":49,"address":4242769,"length":1,"stats":{"Line":1}},{"line":50,"address":4242902,"length":1,"stats":{"Line":1}},{"line":51,"address":4242994,"length":1,"stats":{"Line":1}},{"line":55,"address":4243520,"length":1,"stats":{"Line":2}},{"line":56,"address":4243527,"length":1,"stats":{"Line":1}},{"line":57,"address":4243571,"length":1,"stats":{"Line":2}},{"line":58,"address":4243610,"length":1,"stats":{"Line":2}},{"line":60,"address":4243649,"length":1,"stats":{"Line":1}},{"line":61,"address":4243789,"length":1,"stats":{"Line":1}},{"line":62,"address":4243782,"length":1,"stats":{"Line":1}},{"line":67,"address":4243873,"length":1,"stats":{"Line":1}},{"line":71,"address":4244400,"length":1,"stats":{"Line":2}},{"line":72,"address":4244407,"length":1,"stats":{"Line":1}},{"line":73,"address":4244451,"length":1,"stats":{"Line":2}},{"line":75,"address":4244490,"length":1,"stats":{"Line":2}},{"line":78,"address":4244529,"length":1,"stats":{"Line":1}},{"line":79,"address":4244671,"length":1,"stats":{"Line":1}},{"line":80,"address":4244768,"length":1,"stats":{"Line":1}},{"line":81,"address":4244865,"length":1,"stats":{"Line":1}},{"line":85,"address":4245728,"length":1,"stats":{"Line":2}},{"line":86,"address":4245735,"length":1,"stats":{"Line":1}},{"line":87,"address":4245779,"length":1,"stats":{"Line":2}},{"line":88,"address":4245818,"length":1,"stats":{"Line":2}},{"line":90,"address":4245857,"length":1,"stats":{"Line":1}},{"line":91,"address":4245990,"length":1,"stats":{"Line":1}},{"line":92,"address":4246072,"length":1,"stats":{"Line":1}},{"line":96,"address":4246608,"length":1,"stats":{"Line":2}},{"line":97,"address":4246615,"length":1,"stats":{"Line":1}},{"line":98,"address":4246670,"length":1,"stats":{"Line":2}},{"line":99,"address":4246712,"length":1,"stats":{"Line":2}},{"line":101,"address":4246754,"length":1,"stats":{"Line":1}},{"line":102,"address":4246899,"length":1,"stats":{"Line":1}},{"line":103,"address":4247005,"length":1,"stats":{"Line":1}},{"line":105,"address":4247100,"length":1,"stats":{"Line":1}},{"line":106,"address":4247437,"length":1,"stats":{"Line":2}},{"line":107,"address":4247487,"length":1,"stats":{"Line":2}},{"line":109,"address":4247529,"length":1,"stats":{"Line":1}},{"line":110,"address":4247674,"length":1,"stats":{"Line":1}},{"line":111,"address":4247774,"length":1,"stats":{"Line":1}},{"line":115,"address":4248400,"length":1,"stats":{"Line":2}},{"line":116,"address":4248407,"length":1,"stats":{"Line":1}},{"line":117,"address":4248454,"length":1,"stats":{"Line":2}},{"line":119,"address":4248496,"length":1,"stats":{"Line":2}},{"line":122,"address":4248538,"length":1,"stats":{"Line":1}},{"line":123,"address":4248683,"length":1,"stats":{"Line":1}},{"line":124,"address":4249034,"length":1,"stats":{"Line":1}},{"line":125,"address":4248774,"length":1,"stats":{"Line":1}},{"line":126,"address":4248908,"length":1,"stats":{"Line":1}},{"line":127,"address":4248789,"length":1,"stats":{"Line":1}},{"line":128,"address":4248831,"length":1,"stats":{"Line":1}},{"line":129,"address":4248858,"length":1,"stats":{"Line":1}},{"line":130,"address":4248866,"length":1,"stats":{"Line":1}},{"line":134,"address":4249805,"length":1,"stats":{"Line":1}},{"line":135,"address":4249557,"length":1,"stats":{"Line":1}},{"line":136,"address":4249679,"length":1,"stats":{"Line":1}},{"line":137,"address":4249572,"length":1,"stats":{"Line":1}},{"line":138,"address":4249599,"length":1,"stats":{"Line":1}},{"line":139,"address":4249626,"length":1,"stats":{"Line":1}},{"line":140,"address":4249634,"length":1,"stats":{"Line":1}},{"line":144,"address":4250576,"length":1,"stats":{"Line":1}},{"line":145,"address":4250328,"length":1,"stats":{"Line":1}},{"line":146,"address":4250450,"length":1,"stats":{"Line":1}},{"line":147,"address":4250343,"length":1,"stats":{"Line":1}},{"line":148,"address":4250370,"length":1,"stats":{"Line":1}},{"line":149,"address":4250397,"length":1,"stats":{"Line":1}},{"line":150,"address":4250405,"length":1,"stats":{"Line":1}},{"line":154,"address":4251305,"length":1,"stats":{"Line":1}},{"line":155,"address":4251063,"length":1,"stats":{"Line":1}},{"line":156,"address":4251182,"length":1,"stats":{"Line":1}},{"line":157,"address":4251075,"length":1,"stats":{"Line":1}},{"line":158,"address":4251102,"length":1,"stats":{"Line":1}},{"line":159,"address":4251129,"length":1,"stats":{"Line":1}},{"line":160,"address":4251137,"length":1,"stats":{"Line":1}},{"line":167,"address":4252160,"length":1,"stats":{"Line":2}},{"line":187,"address":4252176,"length":1,"stats":{"Line":2}},{"line":188,"address":4252183,"length":1,"stats":{"Line":1}},{"line":189,"address":4252230,"length":1,"stats":{"Line":2}},{"line":191,"address":4252272,"length":1,"stats":{"Line":2}},{"line":192,"address":4265934,"length":1,"stats":{"Line":1}},{"line":196,"address":4252314,"length":1,"stats":{"Line":1}},{"line":197,"address":4252459,"length":1,"stats":{"Line":1}},{"line":198,"address":4252546,"length":1,"stats":{"Line":1}},{"line":199,"address":4252698,"length":1,"stats":{"Line":1}},{"line":203,"address":4253600,"length":1,"stats":{"Line":2}},{"line":204,"address":4253607,"length":1,"stats":{"Line":1}},{"line":205,"address":4253651,"length":1,"stats":{"Line":2}},{"line":206,"address":4253690,"length":1,"stats":{"Line":2}},{"line":208,"address":4253729,"length":1,"stats":{"Line":1}},{"line":209,"address":4253876,"length":1,"stats":{"Line":1}},{"line":210,"address":4253862,"length":1,"stats":{"Line":1}},{"line":212,"address":4253971,"length":1,"stats":{"Line":1}},{"line":216,"address":4254496,"length":1,"stats":{"Line":2}},{"line":217,"address