Beispiel #1
0
def httpget(arg):
  '''
  makes an http GET request for the given url
  '''
  request = {}
  if is_ip(arg):
      print 'rec ip'
      get_request = "GET " + '/' + " HTTP/1.1\r\nHost: " + arg + "\r\n\r\n"
      request['get_request'] = get_request
      request['scheme'] = 'http'
      request['domain'] = arg
      tcpclient = TCPClient(arg, 80, get_request)
  else:
      url = urlparse(arg)
      path = url.path
      filename = path.split('/')[-1]
      if url.path == "":
        path = '/'
      if path == '/':
        filename = 'index.html'
      get_request = "GET " + path  + " HTTP/1.0\r\nHost: " + url.netloc + "\r\n\r\n"
      request['get_request'] = get_request
      request['scheme'] = url.scheme
      request['domain'] = url.netloc
      tcpclient = TCPClient(socket.gethostbyname(url.netloc), 80, get_request)

  tcpclient.do_handshake()
  data = tcpclient.get_data()

  f = open(filename, 'w')
  f.write(data.split('\r\n\r\n')[1])
  f.close()
Beispiel #2
0
    def __init__(self, video_array):
        """
        Initializes the entire GUI pulling json data from contacts and writing to cameras to display current index.
        :param videoStream: :param outputPath:
        """
        # I put this inside of the class because there is no real use of inheritance in this application of tkinter
        parent = tk.Tk()
        parent.resizable(0, 0)
        super(CLERNFDS, self).__init__(parent)
        # Instantiate Client Object
        self.client = TCPClient()

        # initialize the root window
        self.root = parent

        # Create Title
        title = tk.Label(self.root, text="CLERN FDS", font=("Helvetica", 20))
        title.grid(row=0, column=0, columnspan=3)
        # Contact Input Box
        # Create Label
        input_label = tk.Label(self.root, text="Enter a Valid Contact Phone #")
        input_label.grid(row=1, column=0, columnspan=2, padx=10)
        self.contact_entry = tk.Entry(self.root, width=12)
        self.contact_entry.grid(row=2, column=0, padx=5, sticky="w")
        self.contact_entry.insert(tk.INSERT, "3145567823")
        # Contact Add Button
        add_btn = tk.Button(self.root,
                            text="Add",
                            command=lambda: self.add_contact())
        add_btn.grid(row=2, column=1, sticky="w")

        # Contact Delete Dropdown
        # Create Label
        drop_down_label = tk.Label(self.root,
                                   text="Select a Contact to Remove")
        drop_down_label.grid(row=3, column=0, columnspan=2, padx=10)
        # Delete Contact Button
        del_btn = tk.Button(self.root,
                            text="Delete",
                            command=lambda: self.delete_contact())
        del_btn.grid(row=4, column=1, sticky="w")
        # Pull Contact List && Also calls the updateDropDown function where the options are allocated
        self.update_contacts()

        # Camera Index Dropdown
        self.test_videos = video_array
        # Select Camera Index Label
        drop_down_label = tk.Label(self.root, text="Select Camera Index")
        drop_down_label.grid(row=5, column=0, columnspan=2, padx=10)
        # Draws the index drop down && Allocate Camera Indexes and put it into cameras.txt
        self.update_index_drop_down()
        # Add an update button to refresh the drop down
        del_btn = tk.Button(self.root,
                            text="Refresh",
                            command=lambda: self.update_index_drop_down())
        del_btn.grid(row=6, column=1, sticky="w")

        # set a callback to handle when the window is closed
        self.root.wm_title("CLERN Fall Detection System")
        self.root.wm_protocol("WM_DELETE_WINDOW", self.on_close)
Beispiel #3
0
 def test_flush_queue(self):
     """
     测试清空队列数据
     :return:
     """
     tcp_client = TCPClient()
     result: bool = tcp_client.flush_queue()
     self.assertTrue(result)
Beispiel #4
0
def main():
    c = TCPClient()
    c.start('127.0.0.1', 9989)
    t_values = [23, 24, 25]
    h_values = [71, 72, 73]
    l_values = [222, 223, 224]
    idx = 0

    while True:
        if idx == 3:
            idx = 0

        builder = flatbuffers.Builder(0)

        data_temp = builder.CreateString('Temp')
        data_humi = builder.CreateString('Humi')
        data_light = builder.CreateString('Light')

        IoTDevice.Sample.Data.DataStart(builder)
        IoTDevice.Sample.Data.DataAddName(builder, data_temp)
        IoTDevice.Sample.Data.DataAddValue(builder, t_values[idx])
        temp = IoTDevice.Sample.Data.DataEnd(builder)

        IoTDevice.Sample.Data.DataStart(builder)
        IoTDevice.Sample.Data.DataAddName(builder, data_humi)
        IoTDevice.Sample.Data.DataAddValue(builder, h_values[idx])
        humi = IoTDevice.Sample.Data.DataEnd(builder)

        IoTDevice.Sample.Data.DataStart(builder)
        IoTDevice.Sample.Data.DataAddName(builder, data_light)
        IoTDevice.Sample.Data.DataAddValue(builder, l_values[idx])
        light = IoTDevice.Sample.Data.DataEnd(builder)

        IoTDevice.Sample.IoTDevice.IoTDeviceStartDataVector(builder, 3)
        builder.PrependUOffsetTRelative(light)
        builder.PrependUOffsetTRelative(humi)
        builder.PrependUOffsetTRelative(temp)
        all_data = builder.EndVector(3)

        device_name = builder.CreateString('SPT-1001')
        pos = IoTDevice.Sample.Vec3.CreateVec3(builder, 1.0, 2.0, 3.0)

        IoTDevice.Sample.IoTDevice.IoTDeviceStart(builder)
        IoTDevice.Sample.IoTDevice.IoTDeviceAddPos(builder, pos)
        IoTDevice.Sample.IoTDevice.IoTDeviceAddName(builder, device_name)
        IoTDevice.Sample.IoTDevice.IoTDeviceAddData(builder, all_data)
        sample_device = IoTDevice.Sample.IoTDevice.IoTDeviceEnd(builder)

        builder.Finish(sample_device)

        buf = builder.Output()
        size = len(buf)
        idx = idx + 1

        c.write(buf, None)
        time.sleep(10)

    c.end()
Beispiel #5
0
def prepare():
    host = FunctionCaller('host')
    factHost = TCPReceiver(2232)
    factHost.parts[host.name] = host

    client = FunctionCaller('client')
    factClient = TCPClient('127.0.0.1', 2232)
    factClient.parts[client.name] = client
Beispiel #6
0
def func2(addr, port):
    data2 = []
    s = TCPClient()
    s.start(addr, port)
    len = s.write("client write", None)
    print 'client write len =' + str(len)
    len = s.read(data2, None)
    print 'client read len = ' + str(len)
    print ''.join(data2)
    s.end()
class AbstractCommunicator:
    def __init__(self, hostname, port):
        self.client = TCPClient(hostname, port)

    def start(self):
        if not self.client.connect():
            print('could not start ' + self.__class__.__name__)
            return
        self.start_receive_thread()

    def stop(self):
        self.client.disconnect()

    def send_line(self, command, encoding='utf-8'):
        if self.client.debug == True:
            print('{} send command -> {}'.format(self.__class__.__name__,
                                                 command))
        self.client.send_line(command, encoding)

    def start_receive_thread(self):
        def run(self):
            while self.client.connected:
                try:
                    message = None
                    message = self.client.read_line_non_blocking()
                    if (message != None) and (not message.startswith('ERROR')):
                        self.on_received(message)
                except Exception as e:
                    pass

        thread = threading.Thread(target=run, args=(self, ))
        thread.start()

    def on_received(self, message):
        pass
Beispiel #8
0
def main():
    # Ensure proper directories exist
    if not (os.path.exists('Frames')):
        os.mkdir('Frames')
    # Start The ClientGUI
    gui = CLERNFDS()
    # Init the Client being used to submit files
    client = TCPClient()
    # Get the frame deliverance loop started
    t = ThreadPoolExecutor()
    t.submit(frame_processes, gui, client)
    # Run the mainloop

    gui.loop()
    t.shutdown()
    clear_frames()
    print("Program Closed")
 def __init__(self, hostname, port):
     self.client = TCPClient(hostname, port)
Beispiel #10
0
#!/usr/bin/env python
# -*- encoding:utf-8 -*-

from clipboard_detector import ClipboardDetector
from tcp_client import TCPClient
from Queue import Queue
import os, sys, time
import threading

if __name__ == '__main__':

    queue = Queue()
    detector = ClipboardDetector(queue)
    detector.start()

    tcp_client = TCPClient(queue)
    tcp_client.start()

    try:
        while True:
            time.sleep(5)

    except (KeyboardInterrupt, SystemExit):
        print 'interrupt!'
        detector.stop()
        tcp_client.stop()

        detector.join()
        tcp_client.join()
Beispiel #11
0
    def __init__(self,
                 client_id,
                 server_host,
                 server_port,
                 mc_address,
                 mc_port,
                 send_interval=5,
                 chunk_size=10000000,
                 file_size=10000000 * 2,
                 run_time=30,
                 test_path='./',
                 dd_method=False):
        """
        :param client_id: string, unique id for the client
        :param server_host: string, ip address/hostname for sever
        :param server_host: string, port server will listen on
        :param mc_address: string, multicast group address to publish heartbeat
        :param mc_port: int, port for multicast group
        :param send_interval: int, heartbeat send interval
        :param chunk_size: int, in bytes, the size to data size to write to a
        file at a time
        :param file_size: int, maximum file size for the writer
        :param run_time: int, self explanatory, ya know
        :param test_path: string, path to write the data files
        :param dd_method: bool, use dd or not for the file writing
        """

        self.client_id = client_id
        self.server_host = server_host
        self.chunk_size = chunk_size
        self.file_size = file_size
        self.run_time = run_time
        self.mc_group = mc_address, mc_port
        self.send_interval = send_interval
        self.test_path = test_path
        # if dd_method is True, dd will be used
        # if dd_method is False, python file object will be used
        self.dd_method = dd_method
        logging.basicConfig(filename=client_id + '.log',
                            format='%(asctime)s %(levelname)s: %(message)s',
                            level=logging.INFO)

        # Unsure on requirements, going to assume worst case
        # Need to check to see if the chunk size and
        # run time will allow two instances of the time to be written
        try:
            # check to see if two chunks can be written to the file
            assert self.file_size / self.chunk_size >= 2

        except AssertionError:
            print "Client chunk size is too small for max file size." \
                  "Please reconfigure"
            exit(1)

        # Create the initial TCP connection
        self.tcp = TCPClient((server_host, server_port))
        self.hb1 = Heartbeat(self.mc_group[0], self.mc_group[1],
                             self.client_id, self.send_interval)
        self.kill_sig = Queue(1)
        self.hb_process = Process(target=self.hb1.run, args=(self.kill_sig, ))
        self.hb_process.daemon = True
        self.queue1 = Queue()
        dw1 = DataWriter(self.chunk_size, self.file_size, self.dd_method,
                         self.test_path)
        self.dw_process = Process(target=dw1.run,
                                  args=(self.queue1, self.kill_sig))
        self.dw_process.daemon = True
        self.dw_process_pid = None
Beispiel #12
0
class Client(object):
    """
    Client object
    """
    def __init__(self,
                 client_id,
                 server_host,
                 server_port,
                 mc_address,
                 mc_port,
                 send_interval=5,
                 chunk_size=10000000,
                 file_size=10000000 * 2,
                 run_time=30,
                 test_path='./',
                 dd_method=False):
        """
        :param client_id: string, unique id for the client
        :param server_host: string, ip address/hostname for sever
        :param server_host: string, port server will listen on
        :param mc_address: string, multicast group address to publish heartbeat
        :param mc_port: int, port for multicast group
        :param send_interval: int, heartbeat send interval
        :param chunk_size: int, in bytes, the size to data size to write to a
        file at a time
        :param file_size: int, maximum file size for the writer
        :param run_time: int, self explanatory, ya know
        :param test_path: string, path to write the data files
        :param dd_method: bool, use dd or not for the file writing
        """

        self.client_id = client_id
        self.server_host = server_host
        self.chunk_size = chunk_size
        self.file_size = file_size
        self.run_time = run_time
        self.mc_group = mc_address, mc_port
        self.send_interval = send_interval
        self.test_path = test_path
        # if dd_method is True, dd will be used
        # if dd_method is False, python file object will be used
        self.dd_method = dd_method
        logging.basicConfig(filename=client_id + '.log',
                            format='%(asctime)s %(levelname)s: %(message)s',
                            level=logging.INFO)

        # Unsure on requirements, going to assume worst case
        # Need to check to see if the chunk size and
        # run time will allow two instances of the time to be written
        try:
            # check to see if two chunks can be written to the file
            assert self.file_size / self.chunk_size >= 2

        except AssertionError:
            print "Client chunk size is too small for max file size." \
                  "Please reconfigure"
            exit(1)

        # Create the initial TCP connection
        self.tcp = TCPClient((server_host, server_port))
        self.hb1 = Heartbeat(self.mc_group[0], self.mc_group[1],
                             self.client_id, self.send_interval)
        self.kill_sig = Queue(1)
        self.hb_process = Process(target=self.hb1.run, args=(self.kill_sig, ))
        self.hb_process.daemon = True
        self.queue1 = Queue()
        dw1 = DataWriter(self.chunk_size, self.file_size, self.dd_method,
                         self.test_path)
        self.dw_process = Process(target=dw1.run,
                                  args=(self.queue1, self.kill_sig))
        self.dw_process.daemon = True
        self.dw_process_pid = None

    def start_client(self):
        """
        start the client
        """
        thread.start_new_thread(self.monitor, ())
        thread.start_new_thread(self.run_timer, ())
        self.hb_process.start()
        self.start_writer()

    def start_writer(self):
        """
        start the data writer
        """
        # Start the process for the data writing, chunking, thing,

        self.dw_process.start()
        self.dw_process_pid = self.dw_process.pid
        try:
            while self.kill_sig.empty():
                try:
                    dw_res = self.queue1.get(block=False)
                except Queue2.Empty:
                    continue
                self.tcp.send_data(json.JSONEncoder().encode({
                    self.client_id: {
                        "operation_time": dw_res[0],
                        "file_size": dw_res[1],
                        "chunk_size": self.chunk_size,
                        "write_speed": dw_res[2]
                    }
                }))
                logging.info(dw_res)
        except KeyboardInterrupt:
            pass
        finally:
            print "Closing Client"
            # ensure files were deleted
            self.kill_sig.put(True)
            self.dw_process.join()
            logging.info("Client shutting down")
            exit(0)

    def monitor(self):
        """
        monitor the data writier
        """
        try:
            while self.kill_sig.empty():
                if self.dw_process_pid:  # Probably not the best way...
                    time.sleep(10)
                    monitor_m = check_output([
                        'ps', 'p',
                        str(self.dw_process_pid), '-o', '%cpu,%mem'
                    ],
                                             stderr=STDOUT)
                    cpu, mem = monitor_m.splitlines()[1].strip().split()
                    self.tcp.send_data(json.JSONEncoder().encode({
                        self.client_id + '_Performance': {
                            "cpu": cpu,
                            "mem": mem
                        }
                    }))
        except KeyboardInterrupt:
            pass

    def run_timer(self):
        """
        run timer
        """
        timer = 0
        while timer < self.run_time:
            time.sleep(1)
            timer += 1
        print "Timer ran out"
        self.tcp.close()
        self.hb1.close()
        self.kill_sig.put(True)
Beispiel #13
0
class CLERNFDS(tk.Frame):
    """
    This is what the client will be interacting with primarily

    Needs to be the last thing running since the threading on tkinter is horrible and my solution is hacky

    GUI will hang until everything is done processing

    Threading a thread alongside this gui with the gui object as a parameter will allow that thread dynamic access
    to variables

    Multiprocessing alongside tkinter is not possible, only multithreading is.

    Video pauses when a drop down is selected
    (my guess is that it pauses the mainloop as well, so it is unavoidable without a custom mainloop)
    """
    # GUI has separate client object for concurrent delivery.
    client = None
    # For concurrent processes to end when the GUI closes
    is_running = False
    # Memory Location for contact list
    contact_list = dict()

    # Video feed
    video = None
    stop_event = None
    frame = None
    video_running = False
    # actual viewpoint of video preview.
    panel = None

    # selected contact
    selected_contact = None

    # selected index
    selected_index = None
    # available cameras
    cameras = dict()

    def __init__(self, video_array):
        """
        Initializes the entire GUI pulling json data from contacts and writing to cameras to display current index.
        :param videoStream: :param outputPath:
        """
        # I put this inside of the class because there is no real use of inheritance in this application of tkinter
        parent = tk.Tk()
        parent.resizable(0, 0)
        super(CLERNFDS, self).__init__(parent)
        # Instantiate Client Object
        self.client = TCPClient()

        # initialize the root window
        self.root = parent

        # Create Title
        title = tk.Label(self.root, text="CLERN FDS", font=("Helvetica", 20))
        title.grid(row=0, column=0, columnspan=3)
        # Contact Input Box
        # Create Label
        input_label = tk.Label(self.root, text="Enter a Valid Contact Phone #")
        input_label.grid(row=1, column=0, columnspan=2, padx=10)
        self.contact_entry = tk.Entry(self.root, width=12)
        self.contact_entry.grid(row=2, column=0, padx=5, sticky="w")
        self.contact_entry.insert(tk.INSERT, "3145567823")
        # Contact Add Button
        add_btn = tk.Button(self.root,
                            text="Add",
                            command=lambda: self.add_contact())
        add_btn.grid(row=2, column=1, sticky="w")

        # Contact Delete Dropdown
        # Create Label
        drop_down_label = tk.Label(self.root,
                                   text="Select a Contact to Remove")
        drop_down_label.grid(row=3, column=0, columnspan=2, padx=10)
        # Delete Contact Button
        del_btn = tk.Button(self.root,
                            text="Delete",
                            command=lambda: self.delete_contact())
        del_btn.grid(row=4, column=1, sticky="w")
        # Pull Contact List && Also calls the updateDropDown function where the options are allocated
        self.update_contacts()

        # Camera Index Dropdown
        self.test_videos = video_array
        # Select Camera Index Label
        drop_down_label = tk.Label(self.root, text="Select Camera Index")
        drop_down_label.grid(row=5, column=0, columnspan=2, padx=10)
        # Draws the index drop down && Allocate Camera Indexes and put it into cameras.txt
        self.update_index_drop_down()
        # Add an update button to refresh the drop down
        del_btn = tk.Button(self.root,
                            text="Refresh",
                            command=lambda: self.update_index_drop_down())
        del_btn.grid(row=6, column=1, sticky="w")

        # set a callback to handle when the window is closed
        self.root.wm_title("CLERN Fall Detection System")
        self.root.wm_protocol("WM_DELETE_WINDOW", self.on_close)

    def loop(self):
        self.is_running = True
        self.mainloop()

    def generate_camera_indexes(self):
        """
        Gets all accessible camera indexes to a max of ten and puts them in a dict
        under self.cameras["indexes"]
        :return:
        """
        self.cameras["indexes"] = self.test_videos

    def update_index_drop_down(self):
        """
        Updates the dropdown selection of indexes
        :return:
        """
        self.generate_camera_indexes()
        print(self.cameras["indexes"])
        first = tk.StringVar(self.root)
        if len(self.cameras["indexes"]) == 0:
            first.set("0")
            self.selected_index = first.get()
            self.index_drop_down = tk.OptionMenu(
                self.root,
                first,
                0,
                command=lambda val: self.update_selected_index(val))
        else:
            first.set(self.cameras["indexes"][0])
            self.selected_index = first.get()
            self.index_drop_down = tk.OptionMenu(
                self.root,
                first,
                *self.cameras['indexes'],
                command=lambda val: self.update_selected_index(val))
        self.index_drop_down.grid(row=6, column=0, padx=5, sticky="w")

    def update_selected_index(self, val):
        """
        Helper function to update_index_drop_down
        :param val:
        :return:
        """
        self.selected_index = val
        # changes video preview to current index.

    def update_contact_drop_down(self):
        """
        Updates the tkinter contact removal dropdown
        :return:
        """
        first = tk.StringVar(self.root)
        if len(self.contact_list["contacts"]) == 0:
            first.set("---None---")
            self.selected_contact = first.get()
            self.contact_drop_down = tk.OptionMenu(
                self.root,
                first,
                None,
                command=lambda val: self.update_selected_contact(val))
        else:
            first.set(self.contact_list["contacts"][0])
            self.selected_contact = first.get()
            self.contact_drop_down = tk.OptionMenu(
                self.root,
                first,
                *self.contact_list['contacts'],
                command=lambda val: self.update_selected_contact(val))
        self.contact_drop_down.grid(row=4, column=0, padx=5, sticky="w")

    def update_selected_contact(self, val):
        """
        Helper function to update_contact_drop_down
        :param val:
        :return:
        """
        self.selected_contact = int(val)

    def add_contact(self):
        """
        Validates phone number then adds it to the contacts.txt
        then updates the contact dropdown
        :return:
        """
        contact = self.contact_entry.get()
        contact = phonenumbers.parse(contact, "US")

        print(contact)
        if phonenumbers.is_valid_number(contact):
            self.contact_list['contacts'].append(contact.national_number)
            while True:
                try:
                    with open("contacts.txt", 'w') as json_file:
                        print("Contact Added")
                        json.dump(self.contact_list, json_file)
                        json_file.close()
                    break
                except Exception as e:
                    print("***Error: File Currently Open*** errmsg=%s" % e)
            self.update_contacts()
        else:
            print("Invalid Number")
            self.contact_entry.delete(0, tk.END)
            self.contact_entry.insert(0, "INVALID #")

    def delete_contact(self):
        """
        Deletes contact selected on the contact dropdown
        :return:
        """
        print(self.selected_contact)
        print(self.contact_list['contacts'])
        if self.selected_contact == "---None---":
            print("Contact List is empty")
            return
        self.contact_list['contacts'].remove(int(self.selected_contact))
        while True:
            try:
                with open("contacts.txt", 'w') as json_file:
                    print("%s Deleted" % self.selected_contact)
                    json.dump(self.contact_list, json_file)
                    json_file.close()
                break
            except Exception as e:
                print("***Error: File Currently Open*** errmsg=%s" % e)
        self.update_contacts()

    def update_contacts(self):
        """
        Pulls the contacts from the contacts.txt and loads them onto memory
        :return:
        """
        while True:
            try:
                with open('contacts.txt') as json_file:
                    self.contact_list = json.load(json_file)
                    print("Contacts Updated")
                    json_file.close()
                break
            except Exception as e:
                print("***Error*** errmsg=%s" % e)
        # Update the servers end.
        threading.Thread(target=self.update_server,
                         args=("contacts.txt", ),
                         daemon=True).start()
        # Update the dropdown
        self.update_contact_drop_down()

    def update_server(self, file_name):
        """
        Sends the contacts.txt
        :return:
        """
        self.client.send_file(file_name)

    def on_close(self):
        """
        Essentially the Destructor Call
        :return:
        """
        print("CLERN FDS closing...")
        # stop concurrent processes
        self.is_running = False
        # GUI Hangs until the program it is running inside comes to an end
        self.root.quit()
Beispiel #14
0
    
    if sys.argv[1] == 'host':
        main = FunctionCaller('host')
        fact = TCPReceiver(8007)
        fact.parts[main.name]=main
        fact.begin()
        def sendSync(fn):
            fact.sendAll('cl.sync('+fn+')')
        vid.caller.on_end_file(sendSync)
    if sys.argv[1] == 'cl':
        cl = FunctionCaller('cl')
        def restartPlayer(fn):
            vid.next(fn)
            return 'cl:ok'
        cl.on_sync(vid.next)
        fact = TCPClient('127.0.0.1',8007)
        fact.parts[cl.name]=cl
        fact.begin()



    def on_press(key):
        logging.debug(key)
        if key.char == 'k':
            sstory.setFadeTime(1,finish=1)
        if key.char == 'l':
            sstory.setFadeTime(1)
        if key.char in ['0','1','2','3']:
            fakeArduino.runFunction(str(key.char))
    listener = keyboard.Listener(on_press=on_press)
    listener.start()
Beispiel #15
0
"""
start program for client side application
"""
import _thread
from serial_reader import SerialReader
from tcp_client import TCPClient

SERIAL_PORT = '/dev/tty.usbserial-0001'
BAUD_RATE = 921600
if __name__ == '__main__':
    serial_reader = SerialReader(_serial_port=SERIAL_PORT,
                                 _baud_rate=BAUD_RATE)
    _thread.start_new_thread(serial_reader.assembly_serial_data, ())
    tcp_client = TCPClient('127.0.0.1', 5000)
    tcp_client.send_serial_data()
Beispiel #16
0
 def initClient():
     client = FunctionCaller('client')
     factClient = TCPClient('127.0.0.1', 2232)
     factClient.parts[client.name] = client
     factClient.begin()