diff --git a/README.md b/README.md
index 580c41c3ff58c1e894dc96a1e1be755429aae41a..0023ba53537c1e08b06bb3b6f33ca5297746fedb 100644
--- a/README.md
+++ b/README.md
@@ -27,6 +27,7 @@ Cisco IOS-XE
 Cisco IOS-XR  
 Cisco NX-OS  
 Cisco SG300  
+Dell OS10  
 HP Comware7  
 HP ProCurve  
 Juniper Junos  
@@ -58,9 +59,11 @@ A10
 Accedian  
 Aruba  
 Ciena SAOS  
+Citrix Netscaler  
 Cisco Telepresence  
 Check Point GAiA  
 Coriant  
+Dell Isilon  
 Eltex  
 Enterasys  
 Extreme EXOS  
diff --git a/examples/configuration_changes/config_changes_to_device_list.py b/examples/configuration_changes/config_changes_to_device_list.py
new file mode 100644
index 0000000000000000000000000000000000000000..b1f102b34b8b8504181d02954fd728d7205d889e
--- /dev/null
+++ b/examples/configuration_changes/config_changes_to_device_list.py
@@ -0,0 +1,106 @@
+#!/usr/bin/env python
+# Author:    Peter Bruno
+# Purpose:   Script commands to group of Cisco devices with
+#           success/failure feedback.
+from __future__ import print_function, unicode_literals
+import sys
+from netmiko import ConnectHandler
+from getpass import getpass
+
+
+def usage(ext):
+    # exit with description and command line example
+    print("\nInput file should contain list of switch IP addresses.")
+    print("Commands should be the commands you wish to run on your")
+    print('network devices enclosed in "quotes".')
+    print(
+        "Results key: # = enable mode, * = successful command",
+        "w = write mem, ! = command failure"
+    )
+    print("\nusage:")
+    print(
+        ("\n%s <input file>" % sys.argv[0]),
+        '"command1"',
+        '"command2"',
+        '"command3"',
+        "wr",
+    )
+    sys.exit(ext)
+
+
+def get_cmd_line():
+    if len(sys.argv) < 2:
+        usage(0)
+    cmdlist = sys.argv[2:]
+    try:
+        with open(sys.argv[1], "r") as f:
+            switchip = f.read().splitlines()
+        f.close()
+    except (IndexError, IOError):
+        usage(0)
+    return switchip, cmdlist
+
+
+def main():
+    inputfile, config_commands = get_cmd_line()
+
+    print("Switch configuration updater. Please provide login information.\n")
+    # Get username and password information.
+    username = input("Username: ")
+    password = getpass("Password: ")
+    enasecret = getpass("Enable Secret: ")
+
+    print("{}{:<20}{:<40}{:<20}".format(
+        "\n", "IP Address", "Name", "Results"), end="")
+
+    for switchip in inputfile:
+        ciscosw = {
+            "device_type": "cisco_ios",
+            "ip": switchip.strip(),
+            "username": username.strip(),
+            "password": password.strip(),
+            "secret": enasecret.strip(),
+        }
+        print()
+        print("{:<20}".format(switchip.strip()), end="", flush=True)
+        try:
+            # Connect to switch and enter enable mode.
+            net_connect = ConnectHandler(**ciscosw)
+        except Exception:
+            print("** Failed to connect.", end="", flush=True)
+            continue
+
+        prompt = net_connect.find_prompt()
+        # Print out the prompt/hostname of the device
+        print("{:<40}".format(prompt), end="", flush=True)
+        try:
+            # Ensure we are in enable mode and can make changes.
+            if "#" not in prompt[-1]:
+                net_connect.enable()
+                print("#", end="", flush=True)
+        except Exception:
+            print("Unable to enter enable mode.", end="", flush=True)
+            continue
+
+        else:
+            for cmd in config_commands:
+                # Make requested configuration changes.
+                try:
+                    if cmd in ("w", "wr"):
+                        output = net_connect.save_config()
+                        print("w", end="", flush=True)
+                    else:
+                        output = net_connect.send_config_set(cmd)
+                        if "Invalid input" in output:
+                            # Unsupported command in this IOS version.
+                            print("Invalid input: ", cmd, end="", flush=True)
+                        print("*", end="", flush=True)
+                except Exception:
+                    # Command failed! Stop processing further commands.
+                    print("!")
+                    break
+        net_connect.disconnect()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/examples/use_cases/case10_ssh_proxy/conn_ssh_proxy.py b/examples/use_cases/case10_ssh_proxy/conn_ssh_proxy.py
new file mode 100644
index 0000000000000000000000000000000000000000..2f0e74868f9f23ef5e89a4724c2453b5faf0c914
--- /dev/null
+++ b/examples/use_cases/case10_ssh_proxy/conn_ssh_proxy.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+from netmiko import Netmiko
+from getpass import getpass
+
+key_file = "/home/gituser/.ssh/test_rsa"
+
+cisco1 = {
+    'device_type': 'cisco_ios',
+    'host': 'cisco1.twb-tech.com', 
+    'username': 'testuser',
+    'use_keys': True,
+    'key_file': key_file,
+    'ssh_config_file': './ssh_config',
+}
+
+net_connect = Netmiko(**cisco1)
+print(net_connect.find_prompt())
+output = net_connect.send_command("show ip arp")
+print(output)
+
diff --git a/examples/use_cases/case10_ssh_proxy/ssh_config b/examples/use_cases/case10_ssh_proxy/ssh_config
new file mode 100644
index 0000000000000000000000000000000000000000..2f13ac22ce9587763d7d8a12a3e871a938b6f23c
--- /dev/null
+++ b/examples/use_cases/case10_ssh_proxy/ssh_config
@@ -0,0 +1,7 @@
+host jumphost
+  IdentityFile ~/.ssh/test_rsa
+  user gituser
+  hostname 54.241.72.159
+
+host * !jumphost
+  ProxyCommand ssh jumphost nc %h %p
diff --git a/examples/use_cases/case11_logging/conn_with_logging.py b/examples/use_cases/case11_logging/conn_with_logging.py
new file mode 100644
index 0000000000000000000000000000000000000000..188c45030f224de6671f1a000b5f7e483de132e4
--- /dev/null
+++ b/examples/use_cases/case11_logging/conn_with_logging.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+from netmiko import Netmiko
+from getpass import getpass
+
+import logging
+logging.basicConfig(filename='test.log', level=logging.DEBUG)
+logger = logging.getLogger("netmiko")
+
+cisco1 = {
+    'host': 'cisco1.twb-tech.com', 
+    'username': 'pyclass', 
+    'password': getpass(), 
+    'device_type': 'cisco_ios',
+}
+
+net_connect = Netmiko(**cisco1)
+print(net_connect.find_prompt())
+net_connect.disconnect()
diff --git a/examples/use_cases/case11_logging/test.log b/examples/use_cases/case11_logging/test.log
new file mode 100644
index 0000000000000000000000000000000000000000..f27e55345c7f6aa15ac65ae251cbe92721c752b4
--- /dev/null
+++ b/examples/use_cases/case11_logging/test.log
@@ -0,0 +1,64 @@
+DEBUG:paramiko.transport:starting thread (client mode): 0xb63946ec
+DEBUG:paramiko.transport:Local version/idstring: SSH-2.0-paramiko_2.4.1
+DEBUG:paramiko.transport:Remote version/idstring: SSH-2.0-Cisco-1.25
+INFO:paramiko.transport:Connected (version 2.0, client Cisco-1.25)
+DEBUG:paramiko.transport:kex algos:['diffie-hellman-group-exchange-sha1', 'diffie-hellman-group14-sha1', 'diffie-hellman-group1-sha1'] server key:['ssh-rsa'] client encrypt:['aes128-ctr', 'aes192-ctr', 'aes256-ctr', 'aes128-cbc', '3des-cbc', 'aes192-cbc', 'aes256-cbc'] server encrypt:['aes128-ctr', 'aes192-ctr', 'aes256-ctr', 'aes128-cbc', '3des-cbc', 'aes192-cbc', 'aes256-cbc'] client mac:['hmac-sha1', 'hmac-sha1-96', 'hmac-md5', 'hmac-md5-96'] server mac:['hmac-sha1', 'hmac-sha1-96', 'hmac-md5', 'hmac-md5-96'] client compress:['none'] server compress:['none'] client lang:[''] server lang:[''] kex follows?False
+DEBUG:paramiko.transport:Kex agreed: diffie-hellman-group-exchange-sha1
+DEBUG:paramiko.transport:HostKey agreed: ssh-rsa
+DEBUG:paramiko.transport:Cipher agreed: aes128-ctr
+DEBUG:paramiko.transport:MAC agreed: hmac-sha1
+DEBUG:paramiko.transport:Compression agreed: none
+DEBUG:paramiko.transport:Got server p (2048 bits)
+DEBUG:paramiko.transport:kex engine KexGex specified hash_algo <built-in function openssl_sha1>
+DEBUG:paramiko.transport:Switch to new keys ...
+DEBUG:paramiko.transport:Adding ssh-rsa host key for cisco1.twb-tech.com: b'c77967d9e78b5c6d9acaaa55cc7ad897'
+DEBUG:paramiko.transport:userauth is OK
+INFO:paramiko.transport:Authentication (password) successful!
+DEBUG:paramiko.transport:[chan 0] Max packet in: 32768 bytes
+DEBUG:paramiko.transport:[chan 0] Max packet out: 4096 bytes
+DEBUG:paramiko.transport:Secsh channel 0 opened.
+DEBUG:paramiko.transport:[chan 0] Sesch channel 0 request ok
+DEBUG:paramiko.transport:[chan 0] Sesch channel 0 request ok
+DEBUG:netmiko:read_channel: 
+pynet-rtr1#
+DEBUG:netmiko:read_channel: 
+DEBUG:netmiko:read_channel: 
+DEBUG:netmiko:read_channel: 
+DEBUG:netmiko:write_channel: b'\n'
+DEBUG:netmiko:read_channel: 
+pynet-rtr1#
+DEBUG:netmiko:read_channel: 
+DEBUG:netmiko:read_channel: 
+DEBUG:netmiko:In disable_paging
+DEBUG:netmiko:Command: terminal length 0
+
+DEBUG:netmiko:write_channel: b'terminal length 0\n'
+DEBUG:netmiko:Pattern is: pynet\-rtr1
+DEBUG:netmiko:_read_channel_expect read_data: ter
+DEBUG:netmiko:_read_channel_expect read_data: minal length 0
+pynet-rtr1#
+DEBUG:netmiko:Pattern found: pynet\-rtr1 terminal length 0
+pynet-rtr1#
+DEBUG:netmiko:terminal length 0
+pynet-rtr1#
+DEBUG:netmiko:Exiting disable_paging
+DEBUG:netmiko:write_channel: b'terminal width 511\n'
+DEBUG:netmiko:Pattern is: pynet\-rtr1
+DEBUG:netmiko:_read_channel_expect read_data: t
+DEBUG:netmiko:_read_channel_expect read_data: erminal width 511
+pynet-rtr1#
+DEBUG:netmiko:Pattern found: pynet\-rtr1 terminal width 511
+pynet-rtr1#
+DEBUG:netmiko:read_channel: 
+DEBUG:netmiko:read_channel: 
+DEBUG:netmiko:write_channel: b'\n'
+DEBUG:netmiko:read_channel: 
+pynet-rtr1#
+DEBUG:netmiko:read_channel: 
+DEBUG:netmiko:write_channel: b'\n'
+DEBUG:netmiko:read_channel: 
+pynet-rtr1#
+DEBUG:netmiko:read_channel: 
+DEBUG:netmiko:read_channel: 
+DEBUG:netmiko:exit_config_mode: 
+DEBUG:netmiko:write_channel: b'exit\n'
diff --git a/examples/use_cases/case11_logging/write_channel.py b/examples/use_cases/case11_logging/write_channel.py
new file mode 100644
index 0000000000000000000000000000000000000000..5b01f718f769872cbfc1ea818c0d6cacb81add6e
--- /dev/null
+++ b/examples/use_cases/case11_logging/write_channel.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+from netmiko import Netmiko
+from getpass import getpass
+import time
+
+cisco1 = {
+    'host': 'cisco1.twb-tech.com', 
+    'username': 'pyclass', 
+    'password': getpass(), 
+    'device_type': 'cisco_ios',
+}
+
+net_connect = Netmiko(**cisco1)
+print(net_connect.find_prompt())
+net_connect.write_channel("show ip int brief\n")
+time.sleep(1)
+output = net_connect.read_channel()
+print(output)
+net_connect.disconnect()
diff --git a/examples/use_cases/case12_telnet/conn_telnet.py b/examples/use_cases/case12_telnet/conn_telnet.py
new file mode 100644
index 0000000000000000000000000000000000000000..362a6580d7b4385013ea8c1328d2eb4ce054e461
--- /dev/null
+++ b/examples/use_cases/case12_telnet/conn_telnet.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+from netmiko import Netmiko
+from getpass import getpass
+
+cisco1 = {
+    'host': 'cisco1.twb-tech.com', 
+    'username': 'pyclass', 
+    'password': getpass(), 
+    'device_type': 'cisco_ios_telnet',
+}
+
+net_connect = Netmiko(**cisco1)
+print(net_connect.send_command("show ip arp"))
+net_connect.disconnect()
diff --git a/examples/use_cases/case13_term_server/term_server.py b/examples/use_cases/case13_term_server/term_server.py
new file mode 100644
index 0000000000000000000000000000000000000000..1239cab8406038fb127616c796fd55bd0ffcef17
--- /dev/null
+++ b/examples/use_cases/case13_term_server/term_server.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+import time
+from netmiko import ConnectHandler, redispatch
+
+net_connect = ConnectHandler(
+    device_type='terminal_server',
+    ip='10.10.10.10',
+    username='admin',
+    password='admin123',
+    secret='secret123')
+
+# Manually handle interaction in the Terminal Server (fictional example, but 
+# hopefully you see the pattern)
+net_connect.write_channel("\r\n")
+time.sleep(1)
+net_connect.write_channel("\r\n")
+time.sleep(1)
+output = net_connect.read_channel()
+# Should hopefully see the terminal server prompt
+print(output)
+
+# Login to end device from terminal server
+net_connect.write_channel("connect 1\r\n")
+time.sleep(1)
+
+# Manually handle the Username and Password
+max_loops = 10
+i = 1
+while i <= max_loops:
+    output = net_connect.read_channel()
+    
+    if 'Username' in output:
+        net_connect.write_channel(net_connect.username + '\r\n')
+        time.sleep(1)
+        output = net_connect.read_channel()
+
+    # Search for password pattern / send password
+    if 'Password' in output:
+        net_connect.write_channel(net_connect.password + '\r\n')
+        time.sleep(.5)
+        output = net_connect.read_channel()
+        # Did we successfully login
+        if '>' in output or '#' in output:
+            break
+
+    net_connect.write_channel('\r\n')
+    time.sleep(.5)
+    i += 1
+
+# We are now logged into the end device 
+# Dynamically reset the class back to the proper Netmiko class
+redispatch(net_connect, device_type='cisco_ios')
+
+# Now just do your normal Netmiko operations
+new_output = net_connect.send_command("show ip int brief")
diff --git a/examples/use_cases/case14_secure_copy/secure_copy.py b/examples/use_cases/case14_secure_copy/secure_copy.py
new file mode 100644
index 0000000000000000000000000000000000000000..bd67a1594fa2cff92a55adfee5d8b26615f5624d
--- /dev/null
+++ b/examples/use_cases/case14_secure_copy/secure_copy.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+from getpass import getpass
+from netmiko import ConnectHandler, file_transfer
+
+password = getpass()
+
+cisco = { 
+    'device_type': 'cisco_ios',
+    'host': 'cisco1.twb-tech.com',
+    'username': 'pyclass',
+    'password': password,
+}
+
+source_file = 'test1.txt'
+dest_file = 'test1.txt'
+direction = 'put'
+file_system = 'flash:'
+
+ssh_conn = ConnectHandler(**cisco)
+transfer_dict = file_transfer(ssh_conn,
+                              source_file=source_file, 
+                              dest_file=dest_file,
+                              file_system=file_system, 
+                              direction=direction,
+                              overwrite_file=True)
+
+print(transfer_dict)
diff --git a/examples/use_cases/case14_secure_copy/test1.txt b/examples/use_cases/case14_secure_copy/test1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..982793c32ee7f2df6107a721a7814fcf5ec39bbd
--- /dev/null
+++ b/examples/use_cases/case14_secure_copy/test1.txt
@@ -0,0 +1 @@
+whatever
diff --git a/examples/use_cases/case15_netmiko_tools/.netmiko.yml_example b/examples/use_cases/case15_netmiko_tools/.netmiko.yml_example
new file mode 100644
index 0000000000000000000000000000000000000000..147fe98a9a314daa7364f1b6870ec0757a360c7d
--- /dev/null
+++ b/examples/use_cases/case15_netmiko_tools/.netmiko.yml_example
@@ -0,0 +1,69 @@
+---
+
+# Dictionary is a device
+pynet_rtr1:
+  device_type: cisco_ios
+  host: cisco1.twb-tech.com
+  username: admin
+  password: cisco123
+  port: 22
+
+pynet_rtr2:
+  device_type: cisco_ios
+  ip: 10.10.10.71
+  username: admin
+  password: cisco123
+
+arista_sw1:
+  device_type: arista_eos
+  ip: 10.10.10.72
+  username: admin
+  password: cisco123
+
+arista_sw2:
+  device_type: arista_eos
+  ip: 10.10.10.73
+  username: admin
+  password: cisco123
+
+arista_sw3:
+  device_type: arista_eos
+  ip: 10.10.10.74
+  username: admin
+  password: cisco123
+
+arista_sw4:
+  device_type: arista_eos
+  ip: 10.10.10.75
+  username: admin
+  password: cisco123
+
+juniper_srx:
+  device_type: juniper
+  ip: 10.10.10.76
+  username: admin
+  password: cisco123
+
+cisco_asa:
+  device_type: cisco_asa
+  ip: 10.10.10.1
+  username: admin
+  password: cisco123
+  secret: secret
+
+# Any list is group of devices
+cisco:
+  - pynet_rtr1
+  - pynet_rtr2
+
+asa:
+  - cisco_asa
+
+arista:
+  - arista_sw1
+  - arista_sw2
+  - arista_sw3
+  - arista_sw4
+
+juniper:
+  - juniper_srx
diff --git a/examples/use_cases/case15_netmiko_tools/vlans.txt b/examples/use_cases/case15_netmiko_tools/vlans.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b60cdf4bd13e91ea4d9eacafadd9f1a9df55ce7d
--- /dev/null
+++ b/examples/use_cases/case15_netmiko_tools/vlans.txt
@@ -0,0 +1,6 @@
+vlan 100
+  name red100
+vlan 101
+  name red101
+vlan 102
+  name red102
diff --git a/examples/use_cases/case16_concurrency/my_devices.py b/examples/use_cases/case16_concurrency/my_devices.py
new file mode 100644
index 0000000000000000000000000000000000000000..6f3fb673a538f9547e0d0ec360040eec9f933143
--- /dev/null
+++ b/examples/use_cases/case16_concurrency/my_devices.py
@@ -0,0 +1,62 @@
+from getpass import getpass
+
+std_pwd = getpass("Enter standard password: ")
+
+pynet_rtr1 = {
+    'device_type': 'cisco_ios',
+    'ip': '10.10.247.70',
+    'username': 'pyclass',
+    'password': std_pwd,
+}
+
+pynet_rtr2 = {
+    'device_type': 'cisco_ios',
+    'ip': '10.10.247.71',
+    'username': 'pyclass',
+    'password': std_pwd,
+}
+
+pynet_sw1 = {
+    'device_type': 'arista_eos',
+    'ip': '10.10.247.72',
+    'username': 'pyclass',
+    'password': std_pwd,
+}
+
+pynet_sw2 = {
+    'device_type': 'arista_eos',
+    'ip': '10.10.247.73',
+    'username': 'pyclass',
+    'password': std_pwd,
+}
+
+pynet_sw3 = {
+    'device_type': 'arista_eos',
+    'ip': '10.10.247.74',
+    'username': 'pyclass',
+    'password': std_pwd,
+}
+
+pynet_sw4 = {
+    'device_type': 'arista_eos',
+    'ip': '10.10.247.75',
+    'username': 'pyclass',
+    'password': std_pwd,
+}
+
+juniper_srx = {
+    'device_type': 'juniper_junos',
+    'ip': '10.10.247.76',
+    'username': 'pyclass',
+    'password': std_pwd,
+}
+
+device_list = [
+        pynet_rtr1,
+        pynet_rtr2,
+        pynet_sw1,
+        pynet_sw2,
+        pynet_sw3,
+        pynet_sw4,
+        juniper_srx,
+]
diff --git a/examples/use_cases/case16_concurrency/processes_netmiko.py b/examples/use_cases/case16_concurrency/processes_netmiko.py
new file mode 100644
index 0000000000000000000000000000000000000000..7e0761dfedf8cf5dd243c24b0e2240d71dd1432c
--- /dev/null
+++ b/examples/use_cases/case16_concurrency/processes_netmiko.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+'''
+Use processes and Netmiko to connect to each of the devices. Execute
+'show version' on each device. Record the amount of time required to do this.
+'''
+from __future__ import print_function, unicode_literals
+from multiprocessing import Process
+
+from datetime import datetime
+from netmiko import ConnectHandler
+from my_devices import device_list as devices
+
+
+def show_version(a_device):
+    '''Execute show version command using Netmiko.'''
+    remote_conn = ConnectHandler(**a_device)
+    print()
+    print('#' * 80)
+    print(remote_conn.send_command("show version"))
+    print('#' * 80)
+    print()
+
+
+def main():
+    '''
+    Use processes and Netmiko to connect to each of the devices. Execute
+    'show version' on each device. Record the amount of time required to do this.
+    '''
+    start_time = datetime.now()
+
+    procs = []
+    for a_device in devices:
+        my_proc = Process(target=show_version, args=(a_device,))
+        my_proc.start()
+        procs.append(my_proc)
+
+    for a_proc in procs:
+        print(a_proc)
+        a_proc.join()
+
+    print("\nElapsed time: " + str(datetime.now() - start_time))
+
+
+if __name__ == "__main__":
+    main()
diff --git a/examples/use_cases/case16_concurrency/processes_netmiko_queue.py b/examples/use_cases/case16_concurrency/processes_netmiko_queue.py
new file mode 100644
index 0000000000000000000000000000000000000000..00dd8e8ab57d2269370ab711713ac9215788a71e
--- /dev/null
+++ b/examples/use_cases/case16_concurrency/processes_netmiko_queue.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+'''
+Use processes and Netmiko to connect to each of the devices. Execute
+'show version' on each device. Use a queue to pass the output back to the parent process.
+Record the amount of time required to do this.
+'''
+from __future__ import print_function, unicode_literals
+from multiprocessing import Process, Queue
+
+from datetime import datetime
+from netmiko import ConnectHandler
+from my_devices import device_list as devices
+
+
+def show_version_queue(a_device, output_q):
+    '''
+    Use Netmiko to execute show version. Use a queue to pass the data back to
+    the main process.
+    '''
+    output_dict = {}
+    remote_conn = ConnectHandler(**a_device)
+    hostname = remote_conn.base_prompt
+    output = ('#' * 80) + "\n"
+    output += remote_conn.send_command("show version") + "\n"
+    output += ('#' * 80) + "\n"
+    output_dict[hostname] = output
+    output_q.put(output_dict)
+
+
+def main():
+    '''
+    Use processes and Netmiko to connect to each of the devices. Execute
+    'show version' on each device. Use a queue to pass the output back to the parent process.
+    Record the amount of time required to do this.
+    '''
+    start_time = datetime.now()
+    output_q = Queue(maxsize=20)
+
+    procs = []
+    for a_device in devices:
+        my_proc = Process(target=show_version_queue, args=(a_device, output_q))
+        my_proc.start()
+        procs.append(my_proc)
+
+    # Make sure all processes have finished
+    for a_proc in procs:
+        a_proc.join()
+
+    while not output_q.empty():
+        my_dict = output_q.get()
+        for k, val in my_dict.items():
+            print(k)
+            print(val)
+
+    print("\nElapsed time: " + str(datetime.now() - start_time))
+
+
+if __name__ == "__main__":
+    main()
diff --git a/examples/use_cases/case16_concurrency/threads_netmiko.py b/examples/use_cases/case16_concurrency/threads_netmiko.py
new file mode 100644
index 0000000000000000000000000000000000000000..6fcac1bd933c801e51c55c422e11845c972f836b
--- /dev/null
+++ b/examples/use_cases/case16_concurrency/threads_netmiko.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+import threading
+from datetime import datetime
+from netmiko import ConnectHandler
+from my_devices import device_list as devices
+
+
+def show_version(a_device):
+    '''Execute show version command using Netmiko.'''
+    remote_conn = ConnectHandler(**a_device)
+    print()
+    print('#' * 80)
+    print(remote_conn.send_command_expect("show version"))
+    print('#' * 80)
+    print()
+
+
+def main():
+    '''
+    Use threads and Netmiko to connect to each of the devices. Execute
+    'show version' on each device. Record the amount of time required to do this.
+    '''
+    start_time = datetime.now()
+
+    for a_device in devices:
+        my_thread = threading.Thread(target=show_version, args=(a_device,))
+        my_thread.start()
+
+    main_thread = threading.currentThread()
+    for some_thread in threading.enumerate():
+        if some_thread != main_thread:
+            print(some_thread)
+            some_thread.join()
+
+    print("\nElapsed time: " + str(datetime.now() - start_time))
+
+
+if __name__ == "__main__":
+    main()
diff --git a/examples/use_cases/case17_jinja2/jinja2_crypto.py b/examples/use_cases/case17_jinja2/jinja2_crypto.py
new file mode 100755
index 0000000000000000000000000000000000000000..dad05793e7b05eb43258150ae8b19b1670778159
--- /dev/null
+++ b/examples/use_cases/case17_jinja2/jinja2_crypto.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+from __future__ import print_function, unicode_literals
+import jinja2
+
+template_vars = {
+    'isakmp_enable': True,
+    'encryption': 'aes',
+    'dh_group': 5,
+}
+
+cfg_template = '''
+
+{%- if isakmp_enable %}
+crypto isakmp policy 10
+ encr {{ encryption }}
+ authentication pre-share
+ group {{ dh_group }}
+crypto isakmp key my_key address 1.1.1.1 no-xauth
+crypto isakmp keepalive 10 periodic
+{%- endif %}
+
+'''
+
+template = jinja2.Template(cfg_template)
+print(template.render(template_vars))
diff --git a/examples/use_cases/case17_jinja2/jinja2_for_loop.py b/examples/use_cases/case17_jinja2/jinja2_for_loop.py
new file mode 100755
index 0000000000000000000000000000000000000000..caf7d50cfe215e8cd929d3ea222c4eff617c8cfd
--- /dev/null
+++ b/examples/use_cases/case17_jinja2/jinja2_for_loop.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+from __future__ import print_function, unicode_literals
+import jinja2
+
+my_vlans = {
+    '501': 'blue501',
+    '502': 'blue502',
+    '503': 'blue503',
+    '504': 'blue504',
+    '505': 'blue505',
+    '506': 'blue506',
+    '507': 'blue507',
+    '508': 'blue508',
+}
+template_vars = {
+    'vlans': my_vlans
+}
+
+vlan_template = '''
+
+{%- for vlan_id, vlan_name in vlans.items() %}
+vlan {{ vlan_id }}
+   name {{ vlan_name }}
+{%- endfor %}
+
+'''
+
+template = jinja2.Template(vlan_template)
+print(template.render(template_vars))
diff --git a/examples/use_cases/case17_jinja2/jinja2_ospf_file.py b/examples/use_cases/case17_jinja2/jinja2_ospf_file.py
new file mode 100755
index 0000000000000000000000000000000000000000..a3211a365695b7447956f9823de6fe8c2054b172
--- /dev/null
+++ b/examples/use_cases/case17_jinja2/jinja2_ospf_file.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+from __future__ import print_function, unicode_literals
+import jinja2
+
+template_file = 'ospf_config.j2'
+with open(template_file) as f:
+    jinja_template = f.read()
+
+ospf_active_interfaces = ['Vlan1', 'Vlan2']
+area0_networks = [
+    '10.10.10.0/24',
+    '10.10.20.0/24',
+    '10.10.30.0/24',
+]
+template_vars = {
+    'ospf_process_id': 10,
+    'ospf_priority': 100,
+    'ospf_active_interfaces': ospf_active_interfaces,
+    'ospf_area0_networks': area0_networks,
+}
+
+template = jinja2.Template(jinja_template)
+print(template.render(template_vars))
diff --git a/examples/use_cases/case17_jinja2/jinja2_vlans.py b/examples/use_cases/case17_jinja2/jinja2_vlans.py
new file mode 100755
index 0000000000000000000000000000000000000000..58f6842afa84a5d13d77eab4e51afa87a50de7c5
--- /dev/null
+++ b/examples/use_cases/case17_jinja2/jinja2_vlans.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+from __future__ import print_function, unicode_literals
+import jinja2
+
+template_vars = {
+    'vlan_id': 400,
+    'vlan_name': 'red400',
+}
+
+vlan_template = '''
+vlan {{ vlan_id }}
+   name {{ vlan_name }}
+
+'''
+
+template = jinja2.Template(vlan_template)
+print(template.render(template_vars))
diff --git a/examples/use_cases/case17_jinja2/ospf_config.j2 b/examples/use_cases/case17_jinja2/ospf_config.j2
new file mode 100644
index 0000000000000000000000000000000000000000..10f4043a70f9842ca84096841ce1cd7bd43c367c
--- /dev/null
+++ b/examples/use_cases/case17_jinja2/ospf_config.j2
@@ -0,0 +1,16 @@
+
+{%- if ospf_priority is defined %}
+interface Vlan1
+   ip ospf priority {{ ospf_priority }}
+{%- endif %}
+
+router ospf {{ ospf_process_id }}
+   passive-interface default
+   {%- for intf in ospf_active_interfaces %}
+   no passive-interface {{ intf }}
+   {%- endfor %}
+   {%- for network in ospf_area0_networks %}
+   network {{ network }} area 0.0.0.0
+   {%- endfor %}
+   max-lsa 12000
+
diff --git a/examples/use_cases/case1_simple_conn/simple_conn.py b/examples/use_cases/case1_simple_conn/simple_conn.py
new file mode 100644
index 0000000000000000000000000000000000000000..50772791c5bfe1cee8ca7baa72b9aab1580d7114
--- /dev/null
+++ b/examples/use_cases/case1_simple_conn/simple_conn.py
@@ -0,0 +1,9 @@
+#!/usr/bin/env python
+from netmiko import Netmiko
+from getpass import getpass
+
+net_connect = Netmiko('cisco1.twb-tech.com', username='pyclass',
+                      password=getpass(), device_type='cisco_ios')
+
+print(net_connect.find_prompt())
+net_connect.disconnect()
diff --git a/examples/use_cases/case2_using_dict/conn_with_dict.py b/examples/use_cases/case2_using_dict/conn_with_dict.py
new file mode 100644
index 0000000000000000000000000000000000000000..1ad926055f704d7d18c8e6cec453ae1852059d18
--- /dev/null
+++ b/examples/use_cases/case2_using_dict/conn_with_dict.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+from netmiko import Netmiko
+from getpass import getpass
+
+cisco1 = {
+    'host': 'cisco1.twb-tech.com',
+    'username': 'pyclass',
+    'password': getpass(),
+    'device_type': 'cisco_ios',
+}
+
+net_connect = Netmiko(**cisco1)
+print(net_connect.find_prompt())
+net_connect.disconnect()
diff --git a/examples/use_cases/case2_using_dict/enable.py b/examples/use_cases/case2_using_dict/enable.py
new file mode 100644
index 0000000000000000000000000000000000000000..70056c8c1a1a88bfa3abe496a8efbacc2bf4c963
--- /dev/null
+++ b/examples/use_cases/case2_using_dict/enable.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+from netmiko import Netmiko
+from getpass import getpass
+
+password = getpass()
+
+cisco1 = {
+    'host': 'cisco1.twb-tech.com',
+    'username': 'pyclass',
+    'password': password,
+    'device_type': 'cisco_ios',
+    'secret': password,
+}
+
+net_connect = Netmiko(**cisco1)
+print(net_connect.find_prompt())
+net_connect.send_command_timing("disable")
+print(net_connect.find_prompt())
+net_connect.enable()
+print(net_connect.find_prompt())
+
+# Go into config mode
+net_connect.config_mode()
+print(net_connect.find_prompt())
+net_connect.exit_config_mode()
+print(net_connect.find_prompt())
+net_connect.disconnect()
diff --git a/examples/use_cases/case2_using_dict/invalid_device_type.py b/examples/use_cases/case2_using_dict/invalid_device_type.py
new file mode 100644
index 0000000000000000000000000000000000000000..73135213a92c885fbb21738d8a3f20da6d618335
--- /dev/null
+++ b/examples/use_cases/case2_using_dict/invalid_device_type.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+from netmiko import Netmiko
+from getpass import getpass
+
+cisco1 = {
+    'host': 'cisco1.twb-tech.com',
+    'username': 'pyclass',
+    'password': getpass(),
+    'device_type': 'whatever',
+}
+
+net_connect = Netmiko(**cisco1)
+print(net_connect.find_prompt())
+net_connect.disconnect()
diff --git a/examples/use_cases/case3_multiple_devices/conn_multiple_dev.py b/examples/use_cases/case3_multiple_devices/conn_multiple_dev.py
new file mode 100644
index 0000000000000000000000000000000000000000..3ef9bd9a61ee853343d397751c2f54752a722b0b
--- /dev/null
+++ b/examples/use_cases/case3_multiple_devices/conn_multiple_dev.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+from netmiko import Netmiko
+from getpass import getpass
+
+password = getpass()
+
+cisco1 = {
+    'host': 'cisco1.twb-tech.com', 
+    'username': 'pyclass', 
+    'password': password,
+    'device_type': 'cisco_ios',
+}
+
+cisco2 = {
+    'host': 'cisco2.twb-tech.com', 
+    'username': 'pyclass', 
+    'password': password,
+    'device_type': 'cisco_ios',
+}
+
+nxos1 = {
+    'host': 'nxos1.twb-tech.com', 
+    'username': 'pyclass', 
+    'password': password,
+    'device_type': 'cisco_nxos',
+}
+
+srx1 = {
+    'host': 'srx1.twb-tech.com', 
+    'username': 'pyclass', 
+    'password': password,
+    'device_type': 'juniper_junos',
+}
+
+for device in (cisco1, cisco2, nxos1, srx1):
+    net_connect = Netmiko(**device)
+    print(net_connect.find_prompt())
diff --git a/examples/use_cases/case4_show_commands/send_command.py b/examples/use_cases/case4_show_commands/send_command.py
new file mode 100644
index 0000000000000000000000000000000000000000..1294d6717a6fd3e736b10fcd26c8bdeaee175c4a
--- /dev/null
+++ b/examples/use_cases/case4_show_commands/send_command.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+from netmiko import Netmiko
+from getpass import getpass
+
+cisco1 = {
+    'host': 'cisco1.twb-tech.com', 
+    'username': 'pyclass', 
+    'password': getpass(), 
+    'device_type': 'cisco_ios',
+}
+
+net_connect = Netmiko(**cisco1)
+command = 'show ip int brief'
+
+print()
+print(net_connect.find_prompt())
+output = net_connect.send_command(command)
+net_connect.disconnect()
+print(output)
+print()
diff --git a/examples/use_cases/case4_show_commands/send_command_delay.py b/examples/use_cases/case4_show_commands/send_command_delay.py
new file mode 100644
index 0000000000000000000000000000000000000000..d223a59a72ecd15a71c6fa2006d5f2810a5b1360
--- /dev/null
+++ b/examples/use_cases/case4_show_commands/send_command_delay.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+from netmiko import Netmiko
+from getpass import getpass
+
+cisco1 = {
+    'host': 'cisco1.twb-tech.com', 
+    'username': 'pyclass', 
+    'password': getpass(), 
+    'device_type': 'cisco_ios',
+}
+
+net_connect = Netmiko(**cisco1)
+command = 'copy flash:c880data-universalk9-mz.154-2.T1.bin flash:test1.bin'
+
+print()
+print(net_connect.find_prompt())
+output = net_connect.send_command(command, delay_factor=4)
+print(output)
+print()
diff --git a/examples/use_cases/case4_show_commands/send_command_expect.py b/examples/use_cases/case4_show_commands/send_command_expect.py
new file mode 100644
index 0000000000000000000000000000000000000000..3c2441aee37a608a835756b44a0020af39f4fbf4
--- /dev/null
+++ b/examples/use_cases/case4_show_commands/send_command_expect.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+from netmiko import Netmiko
+from getpass import getpass
+
+cisco1 = {
+    'host': 'cisco1.twb-tech.com', 
+    'username': 'pyclass', 
+    'password': getpass(), 
+    'device_type': 'cisco_ios',
+}
+
+net_connect = Netmiko(**cisco1)
+command = 'show ip int brief'
+
+print()
+print(net_connect.find_prompt())
+output = net_connect.send_command(command, expect_string=r'#')
+net_connect.disconnect()
+print(output)
+print()
diff --git a/examples/use_cases/case4_show_commands/send_command_textfsm.py b/examples/use_cases/case4_show_commands/send_command_textfsm.py
new file mode 100644
index 0000000000000000000000000000000000000000..517705a7fc700c1ae4013ca29545dab48bdcb07e
--- /dev/null
+++ b/examples/use_cases/case4_show_commands/send_command_textfsm.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+from netmiko import Netmiko
+from getpass import getpass
+
+cisco1 = {
+    'host': 'cisco1.twb-tech.com', 
+    'username': 'pyclass', 
+    'password': getpass(), 
+    'device_type': 'cisco_ios',
+}
+
+net_connect = Netmiko(**cisco1)
+command = 'show ip int brief'
+
+print()
+print(net_connect.find_prompt())
+output = net_connect.send_command(command, use_textfsm=True)
+net_connect.disconnect()
+print(output)
+print()
diff --git a/examples/use_cases/case5_prompting/send_command_prompting.py b/examples/use_cases/case5_prompting/send_command_prompting.py
new file mode 100644
index 0000000000000000000000000000000000000000..e9cee9b0d29975f013e2abb2372a6e9069258bd7
--- /dev/null
+++ b/examples/use_cases/case5_prompting/send_command_prompting.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+from netmiko import Netmiko
+from getpass import getpass
+
+cisco1 = {
+    'host': 'cisco1.twb-tech.com', 
+    'username': 'pyclass', 
+    'password': getpass(), 
+    'device_type': 'cisco_ios',
+}
+
+net_connect = Netmiko(**cisco1)
+command = 'del flash:/test1.txt'
+print()
+print(net_connect.find_prompt())
+output = net_connect.send_command_timing(command)
+if 'confirm' in output:
+    output += net_connect.send_command_timing('y', strip_prompt=False, strip_command=False)
+net_connect.disconnect()
+print(output)
+print()
diff --git a/examples/use_cases/case6_config_change/config_change.py b/examples/use_cases/case6_config_change/config_change.py
new file mode 100644
index 0000000000000000000000000000000000000000..8afa9ca52ce0c467819f25bb66b43467dddb6d3d
--- /dev/null
+++ b/examples/use_cases/case6_config_change/config_change.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+from netmiko import Netmiko
+from getpass import getpass
+
+nxos1 = {
+    'host': 'nxos1.twb-tech.com', 
+    'username': 'pyclass', 
+    'password': getpass(), 
+    'device_type': 'cisco_nxos',
+}
+
+commands = [
+    'logging history size 500'
+]
+
+net_connect = Netmiko(**nxos1)
+
+print()
+print(net_connect.find_prompt())
+output = net_connect.send_config_set(commands)
+output += net_connect.send_command("copy run start")
+print(output)
+print()
diff --git a/examples/use_cases/case6_config_change/config_change_file.py b/examples/use_cases/case6_config_change/config_change_file.py
new file mode 100644
index 0000000000000000000000000000000000000000..e2bde411f101e0040f904548e84afc779cc98dce
--- /dev/null
+++ b/examples/use_cases/case6_config_change/config_change_file.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+from netmiko import Netmiko
+from getpass import getpass
+
+nxos1 = {
+    'host': 'nxos1.twb-tech.com', 
+    'username': 'pyclass', 
+    'password': getpass(), 
+    'device_type': 'cisco_nxos',
+}
+
+cfg_file = 'config_changes.txt'
+net_connect = Netmiko(**nxos1)
+
+print()
+print(net_connect.find_prompt())
+output = net_connect.send_config_from_file(cfg_file)
+print(output)
+print()
+
+net_connect.save_config()
+net_connect.disconnect()
diff --git a/examples/use_cases/case6_config_change/config_changes.txt b/examples/use_cases/case6_config_change/config_changes.txt
new file mode 100644
index 0000000000000000000000000000000000000000..35d43ba8940749b1eb2434710af5f9ca634b65f8
--- /dev/null
+++ b/examples/use_cases/case6_config_change/config_changes.txt
@@ -0,0 +1,6 @@
+vlan 100
+ name blue100
+vlan 101
+ name blue101
+vlan 102
+ name blue102
diff --git a/examples/use_cases/case7_commit/config_change_jnpr.py b/examples/use_cases/case7_commit/config_change_jnpr.py
new file mode 100644
index 0000000000000000000000000000000000000000..1fccaa1883654743284edd95b55416dda4f2a687
--- /dev/null
+++ b/examples/use_cases/case7_commit/config_change_jnpr.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+from netmiko import Netmiko
+from getpass import getpass
+
+device = {
+    'host': 'srx1.twb-tech.com', 
+    'username': 'pyclass', 
+    'password': getpass(), 
+    'device_type': 'juniper_junos',
+}
+
+commands = [
+    'set system syslog archive size 240k files 3 '
+]
+
+net_connect = Netmiko(**device)
+
+print()
+print(net_connect.find_prompt())
+output = net_connect.send_config_set(commands, exit_config_mode=False)
+output += net_connect.commit(and_quit=True)
+print(output)
+print()
+
+net_connect.disconnect()
diff --git a/examples/use_cases/case8_autodetect/autodetect_snmp.py b/examples/use_cases/case8_autodetect/autodetect_snmp.py
new file mode 100644
index 0000000000000000000000000000000000000000..0c60eca15c1c913913e808ef691f3cd7adb1b78a
--- /dev/null
+++ b/examples/use_cases/case8_autodetect/autodetect_snmp.py
@@ -0,0 +1,18 @@
+from netmiko.snmp_autodetect import SNMPDetect
+from netmiko import Netmiko
+from getpass import getpass
+
+device = {
+    'host': 'cisco1.twb-tech.com', 
+    'username': 'pyclass', 
+    'password': getpass(), 
+}
+
+snmp_community = getpass("Enter SNMP community: ")
+my_snmp = SNMPDetect("cisco1.twb-tech.com", snmp_version="v2c", community=snmp_community)
+device_type = my_snmp.autodetect()
+print(device_type)
+
+device['device_type'] = device_type
+net_connect = Netmiko(**device)
+print(net_connect.find_prompt())
diff --git a/examples/use_cases/case8_autodetect/autodetect_snmp_v3.py b/examples/use_cases/case8_autodetect/autodetect_snmp_v3.py
new file mode 100644
index 0000000000000000000000000000000000000000..65b726d1a8c714ac952ba28af1f8853ec4bb1f92
--- /dev/null
+++ b/examples/use_cases/case8_autodetect/autodetect_snmp_v3.py
@@ -0,0 +1,21 @@
+# SNMPv3
+from netmiko.snmp_autodetect import SNMPDetect
+from netmiko import Netmiko
+from getpass import getpass
+
+device = {
+    'host': 'cisco1.twb-tech.com', 
+    'username': 'pyclass', 
+    'password': getpass(), 
+}
+
+snmp_key = getpass("Enter SNMP community: ")
+my_snmp = SNMPDetect("cisco1.twb-tech.com", snmp_version="v3", user='pysnmp',
+                     auth_key=snmp_key, encrypt_key=snmp_key, auth_proto="sha",
+                     encrypt_proto="aes128")
+device_type = my_snmp.autodetect()
+print(device_type)
+
+device['device_type'] = device_type
+net_connect = Netmiko(**device)
+print(net_connect.find_prompt())
diff --git a/examples/use_cases/case8_autodetect/autodetect_ssh.py b/examples/use_cases/case8_autodetect/autodetect_ssh.py
new file mode 100644
index 0000000000000000000000000000000000000000..0f95c3323bb02ddc5dec2854795f27d8d888dd26
--- /dev/null
+++ b/examples/use_cases/case8_autodetect/autodetect_ssh.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+from netmiko import SSHDetect, Netmiko
+from getpass import getpass
+
+device = {
+    'device_type': 'autodetect',
+    'host': 'cisco1.twb-tech.com', 
+    'username': 'pyclass', 
+    'password': getpass(), 
+}
+
+guesser = SSHDetect(**device)
+best_match = guesser.autodetect()
+print(best_match)                   # Name of the best device_type to use further
+print(guesser.potential_matches)    # Dictionary of the whole matching result
+
+device['device_type'] = best_match
+connection = Netmiko(**device)
+
+print(connection.find_prompt())
diff --git a/examples/use_cases/case9_ssh_keys/conn_ssh_keys.py b/examples/use_cases/case9_ssh_keys/conn_ssh_keys.py
new file mode 100644
index 0000000000000000000000000000000000000000..a1c17bed07ff460df56e5c8191ea5b42ccf1e6fa
--- /dev/null
+++ b/examples/use_cases/case9_ssh_keys/conn_ssh_keys.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+from netmiko import Netmiko
+from getpass import getpass
+
+key_file = "/home/gituser/.ssh/test_rsa"
+
+cisco1 = {
+    'device_type': 'cisco_ios',
+    'host': 'cisco1.twb-tech.com', 
+    'username': 'testuser',
+    'use_keys': True,
+    'key_file': key_file,
+}
+
+net_connect = Netmiko(**cisco1)
+print(net_connect.find_prompt())
+output = net_connect.send_command("show ip arp")
+print(output)
diff --git a/netmiko/__init__.py b/netmiko/__init__.py
index f2f600d9cb7dddf6762469dd5d5eb55a8d1b491e..e5e3c69d2d7b8d93765ac8cb067d7b3c144f5111 100644
--- a/netmiko/__init__.py
+++ b/netmiko/__init__.py
@@ -23,7 +23,7 @@ NetmikoTimeoutError = NetMikoTimeoutException
 NetmikoAuthError = NetMikoAuthenticationException
 Netmiko = ConnectHandler
 
-__version__ = '2.1.1'
+__version__ = '2.2.0'
 __all__ = ('ConnectHandler', 'ssh_dispatcher', 'platforms', 'SCPConn', 'FileTransfer',
            'NetMikoTimeoutException', 'NetMikoAuthenticationException',
            'NetmikoTimeoutError', 'NetmikoAuthError', 'InLineTransfer', 'redispatch',
diff --git a/netmiko/apresia/__init__.py b/netmiko/apresia/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e15e8702a22b18b8293b2076b87b14602aa9e46c
--- /dev/null
+++ b/netmiko/apresia/__init__.py
@@ -0,0 +1,4 @@
+from __future__ import unicode_literals
+from netmiko.apresia.apresia_aeos import ApresiaAeosSSH, ApresiaAeosTelnet
+
+__all__ = ['ApresiaAeosSSH', 'ApresiaAeosTelnet']
diff --git a/netmiko/apresia/apresia_aeos.py b/netmiko/apresia/apresia_aeos.py
new file mode 100644
index 0000000000000000000000000000000000000000..e310218ad6a45b9b779e32dd278506c70f3180e0
--- /dev/null
+++ b/netmiko/apresia/apresia_aeos.py
@@ -0,0 +1,39 @@
+from __future__ import unicode_literals
+import time
+from netmiko.cisco_base_connection import CiscoSSHConnection
+
+
+class ApresiaAeosBase(CiscoSSHConnection):
+    def session_preparation(self):
+        """Prepare the session after the connection has been established."""
+        self._test_channel_read(pattern=r'[>#]')
+        self.set_base_prompt()
+        self.disable_paging()
+        self.set_terminal_width(command='terminal width 511')
+        # Clear the read buffer
+        time.sleep(.3 * self.global_delay_factor)
+        self.clear_buffer()
+
+    def disable_paging(self, command="", delay_factor=1):
+        self.enable()
+        check_command = "show running-config | include terminal length 0"
+        output = self.send_command(check_command)
+
+        if "terminal length 0" not in output:
+            self.send_config_set("terminal length 0")
+        self.exit_enable_mode()
+
+    def set_terminal_width(self, command="", delay_factor=1):
+        """No terminal width command mode on AEOS"""
+        pass
+
+
+class ApresiaAeosSSH(ApresiaAeosBase):
+    pass
+
+
+class ApresiaAeosTelnet(ApresiaAeosBase):
+    def __init__(self, *args, **kwargs):
+        default_enter = kwargs.get('default_enter')
+        kwargs['default_enter'] = '\r\n' if default_enter is None else default_enter
+        super(ApresiaAeosTelnet, self).__init__(*args, **kwargs)
diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py
index baf4da046f8af1218610515595556c5ec69728f1..975e7ada3679523ff00cef7205a0221583d22827 100644
--- a/netmiko/base_connection.py
+++ b/netmiko/base_connection.py
@@ -10,21 +10,22 @@ Also defines methods that should generally be supported by child classes
 from __future__ import print_function
 from __future__ import unicode_literals
 
-import paramiko
+import io
+import re
+import socket
 import telnetlib
 import time
-import socket
-import re
-import io
 from os import path
 from threading import Lock
 
+import paramiko
+import serial
+
+from netmiko import log
 from netmiko.netmiko_globals import MAX_BUFFER, BACKSPACE_CHAR
+from netmiko.py23_compat import string_types, bufferedio_types
 from netmiko.ssh_exception import NetMikoTimeoutException, NetMikoAuthenticationException
 from netmiko.utilities import write_bytes, check_serial_port, get_structured_data
-from netmiko.py23_compat import string_types
-from netmiko import log
-import serial
 
 
 class BaseConnection(object):
@@ -36,9 +37,10 @@ class BaseConnection(object):
     def __init__(self, ip='', host='', username='', password='', secret='', port=None,
                  device_type='', verbose=False, global_delay_factor=1, use_keys=False,
                  key_file=None, allow_agent=False, ssh_strict=False, system_host_keys=False,
-                 alt_host_keys=False, alt_key_file='', ssh_config_file=None, timeout=90,
+                 alt_host_keys=False, alt_key_file='', ssh_config_file=None, timeout=100,
                  session_timeout=60, blocking_timeout=8, keepalive=0, default_enter=None,
-                 response_return=None, serial_settings=None):
+                 response_return=None, serial_settings=None, fast_cli=False, session_log=None,
+                 session_log_record_writes=False, session_log_file_mode='write'):
         """
         Initialize attributes for establishing connection to target device.
 
@@ -116,6 +118,23 @@ class BaseConnection(object):
         :param response_return: Character(s) to use in normalized return data to represent
                 enter key (default: '\n')
         :type response_return: str
+
+        :param fast_cli: Provide a way to optimize for performance. Converts select_delay_factor
+                to select smallest of global and specific. Sets default global_delay_factor to .1
+                (default: False)
+        :type fast_cli: boolean
+
+        :param session_log: File path or BufferedIOBase subclass object to write the session log to.
+        :type session_log: str
+
+        :param session_log_record_writes: The session log generally only records channel reads due
+                to eliminate command duplication due to command echo. You can enable this if you
+                want to record both channel reads and channel writes in the log (default: False).
+        :type session_log_record_writes: boolean
+
+        :param session_log_file_mode: "write" or "append" for session_log file mode
+                (default: "write")
+        :type session_log_file_mode: str
         """
         self.remote_conn = None
         self.RETURN = '\n' if default_enter is None else default_enter
@@ -147,6 +166,23 @@ class BaseConnection(object):
         self.blocking_timeout = blocking_timeout
         self.keepalive = keepalive
 
+        # Netmiko will close the session_log if we open the file
+        self.session_log = None
+        self.session_log_record_writes = session_log_record_writes
+        self._session_log_close = False
+        # Ensures last write operations prior to disconnect are recorded.
+        self._session_log_fin = False
+        if session_log is not None:
+            if isinstance(session_log, string_types):
+                # If session_log is a string, open a file corresponding to string name.
+                self.open_session_log(filename=session_log, mode=session_log_file_mode)
+            elif isinstance(session_log, bufferedio_types):
+                # In-memory buffer or an already open file handle
+                self.session_log = session_log
+            else:
+                raise ValueError("session_log must be a path to a file, a file handle, "
+                                 "or a BufferedIOBase subclass.")
+
         # Default values
         self.serial_settings = {
             'port': 'COM1',
@@ -166,8 +202,10 @@ class BaseConnection(object):
             comm_port = check_serial_port(comm_port)
             self.serial_settings.update({'port': comm_port})
 
-        # Use the greater of global_delay_factor or delay_factor local to method
+        self.fast_cli = fast_cli
         self.global_delay_factor = global_delay_factor
+        if self.fast_cli and self.global_delay_factor == 1:
+            self.global_delay_factor = .1
 
         # set in set_base_prompt method
         self.base_prompt = ''
@@ -275,10 +313,17 @@ class BaseConnection(object):
             raise ValueError("Invalid protocol specified")
         try:
             log.debug("write_channel: {}".format(write_bytes(out_data)))
+            if self._session_log_fin or self.session_log_record_writes:
+                self._write_session_log(out_data)
         except UnicodeDecodeError:
             # Don't log non-ASCII characters; this is null characters and telnet IAC (PY2)
             pass
 
+    def _write_session_log(self, data):
+        if self.session_log is not None and len(data) > 0:
+            self.session_log.write(write_bytes(data))
+            self.session_log.flush()
+
     def write_channel(self, out_data):
         """Generic handler that will write to both SSH and telnet channel.
 
@@ -339,6 +384,7 @@ class BaseConnection(object):
             while (self.remote_conn.in_waiting > 0):
                 output += self.remote_conn.read(self.remote_conn.in_waiting)
         log.debug("read_channel: {}".format(output))
+        self._write_session_log(output)
         return output
 
     def read_channel(self):
@@ -399,6 +445,7 @@ class BaseConnection(object):
                     new_data = new_data.decode('utf-8', 'ignore')
                     log.debug("_read_channel_expect read_data: {}".format(new_data))
                     output += new_data
+                    self._write_session_log(new_data)
                 except socket.timeout:
                     raise NetMikoTimeoutException("Timed-out reading channel, data not available.")
                 finally:
@@ -491,7 +538,7 @@ class BaseConnection(object):
                           pwd_pattern, delay_factor, max_loops)
 
     def telnet_login(self, pri_prompt_terminator=r'#\s*$', alt_prompt_terminator=r'>\s*$',
-                     username_pattern=r"(?:[Uu]ser:|sername|ogin)", pwd_pattern=r"assword",
+                     username_pattern=r"(?:user:|username|login|user name)", pwd_pattern=r"assword",
                      delay_factor=1, max_loops=20):
         """Telnet login. Can be username/password or just password.
 
@@ -522,14 +569,14 @@ class BaseConnection(object):
                 return_msg += output
 
                 # Search for username pattern / send username
-                if re.search(username_pattern, output):
+                if re.search(username_pattern, output, flags=re.I):
                     self.write_channel(self.username + self.TELNET_RETURN)
                     time.sleep(1 * delay_factor)
                     output = self.read_channel()
                     return_msg += output
 
                 # Search for password pattern / send password
-                if re.search(pwd_pattern, output):
+                if re.search(pwd_pattern, output, flags=re.I):
                     self.write_channel(self.password + self.TELNET_RETURN)
                     time.sleep(.5 * delay_factor)
                     output = self.read_channel()
@@ -547,7 +594,8 @@ class BaseConnection(object):
                 time.sleep(.5 * delay_factor)
                 i += 1
             except EOFError:
-                msg = "Telnet login failed: {}".format(self.host)
+                self.remote_conn.close()
+                msg = "Login failed: {}".format(self.host)
                 raise NetMikoAuthenticationException(msg)
 
         # Last try to see if we already logged in
@@ -559,7 +607,8 @@ class BaseConnection(object):
                 or re.search(alt_prompt_terminator, output, flags=re.M)):
             return return_msg
 
-        msg = "Telnet login failed: {}".format(self.host)
+        msg = "Login failed: {}".format(self.host)
+        self.remote_conn.close()
         raise NetMikoAuthenticationException(msg)
 
     def session_preparation(self):
@@ -688,17 +737,19 @@ class BaseConnection(object):
             try:
                 self.remote_conn_pre.connect(**ssh_connect_params)
             except socket.error:
+                self.paramiko_cleanup()
                 msg = "Connection to device timed-out: {device_type} {ip}:{port}".format(
                     device_type=self.device_type, ip=self.host, port=self.port)
                 raise NetMikoTimeoutException(msg)
             except paramiko.ssh_exception.AuthenticationException as auth_err:
+                self.paramiko_cleanup()
                 msg = "Authentication failure: unable to connect {device_type} {ip}:{port}".format(
                     device_type=self.device_type, ip=self.host, port=self.port)
                 msg += self.RETURN + str(auth_err)
                 raise NetMikoAuthenticationException(msg)
 
             if self.verbose:
-                print("SSH connection established to {0}:{1}".format(self.host, self.port))
+                print("SSH connection established to {}:{}".format(self.host, self.port))
 
             # Use invoke_shell to establish an 'interactive session'
             if width and height:
@@ -771,15 +822,23 @@ class BaseConnection(object):
         return remote_conn_pre
 
     def select_delay_factor(self, delay_factor):
-        """Choose the greater of delay_factor or self.global_delay_factor.
+        """
+        Choose the greater of delay_factor or self.global_delay_factor (default).
+        In fast_cli choose the lesser of delay_factor of self.global_delay_factor.
 
         :param delay_factor: See __init__: global_delay_factor
         :type delay_factor: int
         """
-        if delay_factor >= self.global_delay_factor:
-            return delay_factor
+        if self.fast_cli:
+            if delay_factor <= self.global_delay_factor:
+                return delay_factor
+            else:
+                return self.global_delay_factor
         else:
-            return self.global_delay_factor
+            if delay_factor >= self.global_delay_factor:
+                return delay_factor
+            else:
+                return self.global_delay_factor
 
     def special_login_handler(self, delay_factor=1):
         """Handler for devices like WLC, Avaya ERS that throw up characters prior to login."""
@@ -1028,6 +1087,8 @@ class BaseConnection(object):
         while i <= max_loops:
             new_data = self.read_channel()
             if new_data:
+                if self.ansi_escape_codes:
+                    new_data = self.strip_ansi_escape_codes(new_data)
                 output += new_data
                 try:
                     lines = output.split(self.RETURN)
@@ -1043,8 +1104,8 @@ class BaseConnection(object):
                     pass
                 if re.search(search_pattern, output):
                     break
-            else:
-                time.sleep(delay_factor * loop_delay)
+
+            time.sleep(delay_factor * loop_delay)
             i += 1
         else:   # nobreak
             raise IOError("Search pattern never detected in send_command_expect: {}".format(
@@ -1225,7 +1286,7 @@ class BaseConnection(object):
             output = self.read_until_pattern(pattern=pattern)
             if self.check_config_mode():
                 raise ValueError("Failed to exit configuration mode")
-        log.debug("exit_config_mode: {0}".format(output))
+        log.debug("exit_config_mode: {}".format(output))
         return output
 
     def send_config_from_file(self, config_file=None, **kwargs):
@@ -1292,7 +1353,10 @@ class BaseConnection(object):
         output = self.config_mode(*cfg_mode_args)
         for cmd in config_commands:
             self.write_channel(self.normalize_cmd(cmd))
-            time.sleep(delay_factor * .5)
+            if self.fast_cli:
+                pass
+            else:
+                time.sleep(delay_factor * .05)
 
         # Gather output
         output += self._read_channel_timing(delay_factor=delay_factor, max_loops=max_loops)
@@ -1331,9 +1395,9 @@ class BaseConnection(object):
 
         :param string_buffer: The string to be processed to remove ANSI escape codes
         :type string_buffer: str
-        """
+        """         # noqa
         log.debug("In strip_ansi_escape_codes")
-        log.debug("repr = {0}".format(repr(string_buffer)))
+        log.debug("repr = {}".format(repr(string_buffer)))
 
         code_position_cursor = chr(27) + r'\[\d+;\d+H'
         code_show_cursor = chr(27) + r'\[\?25h'
@@ -1346,16 +1410,20 @@ class BaseConnection(object):
         code_carriage_return = chr(27) + r'\[1M'
         code_disable_line_wrapping = chr(27) + r'\[\?7l'
         code_reset_mode_screen_options = chr(27) + r'\[\?\d+l'
+        code_reset_graphics_mode = chr(27) + r'\[00m'
         code_erase_display = chr(27) + r'\[2J'
         code_graphics_mode = chr(27) + r'\[\d\d;\d\dm'
         code_graphics_mode2 = chr(27) + r'\[\d\d;\d\d;\d\dm'
         code_get_cursor_position = chr(27) + r'\[6n'
+        code_cursor_position = chr(27) + r'\[m'
+        code_erase_display = chr(27) + r'\[J'
 
         code_set = [code_position_cursor, code_show_cursor, code_erase_line, code_enable_scroll,
                     code_erase_start_line, code_form_feed, code_carriage_return,
                     code_disable_line_wrapping, code_erase_line_end,
-                    code_reset_mode_screen_options, code_erase_display,
-                    code_graphics_mode, code_graphics_mode2, code_get_cursor_position]
+                    code_reset_mode_screen_options, code_reset_graphics_mode, code_erase_display,
+                    code_graphics_mode, code_graphics_mode2, code_get_cursor_position,
+                    code_cursor_position, code_erase_display]
 
         output = string_buffer
         for ansi_esc_code in code_set:
@@ -1373,19 +1441,28 @@ class BaseConnection(object):
         """Any needed cleanup before closing connection."""
         pass
 
+    def paramiko_cleanup(self):
+        """Cleanup Paramiko to try to gracefully handle SSH session ending."""
+        self.remote_conn_pre.close()
+        del self.remote_conn_pre
+
     def disconnect(self):
         """Try to gracefully close the SSH connection."""
         try:
             self.cleanup()
             if self.protocol == 'ssh':
-                self.remote_conn_pre.close()
-            elif self.protocol == 'telnet' or 'serial':
+                self.paramiko_cleanup()
+            elif self.protocol == 'telnet':
+                self.remote_conn.close()
+            elif self.protocol == 'serial':
                 self.remote_conn.close()
         except Exception:
             # There have been race conditions observed on disconnect.
             pass
         finally:
+            self.remote_conn_pre = None
             self.remote_conn = None
+            self.close_session_log()
 
     def commit(self):
         """Commit method for platforms that support this."""
@@ -1395,6 +1472,20 @@ class BaseConnection(object):
         """Not Implemented"""
         raise NotImplementedError
 
+    def open_session_log(self, filename, mode="write"):
+        """Open the session_log file."""
+        if mode == 'append':
+            self.session_log = open(filename, mode="ab")
+        else:
+            self.session_log = open(filename, mode="wb")
+        self._session_log_close = True
+
+    def close_session_log(self):
+        """Close the session_log file (if it is a file that we opened)."""
+        if self.session_log is not None and self._session_log_close:
+            self.session_log.close()
+            self.session_log = None
+
 
 class TelnetConnection(BaseConnection):
     pass
diff --git a/netmiko/calix/calix_b6.py b/netmiko/calix/calix_b6.py
index c8b9b1d4079a851c97f9ea2226f34e11d4d6cc69..bd9bbb355cdd3170e9aa0df3714ae2ecf04700bd 100644
--- a/netmiko/calix/calix_b6.py
+++ b/netmiko/calix/calix_b6.py
@@ -21,7 +21,7 @@ class CalixB6Base(CiscoSSHConnection):
     def __init__(self, *args, **kwargs):
         default_enter = kwargs.get('default_enter')
         kwargs['default_enter'] = '\r\n' if default_enter is None else default_enter
-        super(CalixB6SSH, self).__init__(*args, **kwargs)
+        super(CalixB6Base, self).__init__(*args, **kwargs)
 
     def session_preparation(self):
         """Prepare the session after the connection has been established."""
diff --git a/netmiko/cisco/cisco_wlc_ssh.py b/netmiko/cisco/cisco_wlc_ssh.py
index 2e65241bd5ccab14b6d75553ea4e297d69bf94b5..d903321eca4a06865b8e8074960ec58c6d1ab888 100644
--- a/netmiko/cisco/cisco_wlc_ssh.py
+++ b/netmiko/cisco/cisco_wlc_ssh.py
@@ -159,6 +159,18 @@ class CiscoWlcSSH(BaseConnection):
         log.debug("{}".format(output))
         return output
 
-    def save_config(self, cmd='save config', confirm=True, confirm_response='y'):
-        return super(CiscoWlcSSH, self).save_config(cmd=cmd, confirm=confirm,
-                                                    confirm_response=confirm_response)
+    def save_config(self, cmd='save config', confirm=True,
+                    confirm_response='y'):
+        """Saves Config."""
+        self.enable()
+        if confirm:
+            output = self.send_command_timing(command_string=cmd)
+            if confirm_response:
+                output += self.send_command_timing(confirm_response)
+            else:
+                # Send enter by default
+                output += self.send_command_timing(self.RETURN)
+        else:
+            # Some devices are slow so match on trailing-prompt if you can
+            output = self.send_command(command_string=cmd)
+        return output
diff --git a/netmiko/cisco_base_connection.py b/netmiko/cisco_base_connection.py
index d90f2a3b1fc0c11a67fbcc8e5386f1c2fa7efd2c..cba487fadcf73532168be83d679b741751f283ce 100644
--- a/netmiko/cisco_base_connection.py
+++ b/netmiko/cisco_base_connection.py
@@ -41,15 +41,13 @@ class CiscoBaseConnection(BaseConnection):
         return super(CiscoBaseConnection, self).config_mode(config_command=config_command,
                                                             pattern=pattern)
 
-    def exit_config_mode(self, exit_config='end', pattern=''):
+    def exit_config_mode(self, exit_config='end', pattern='#'):
         """Exit from configuration mode."""
-        if not pattern:
-            pattern = re.escape(self.base_prompt[:16])
         return super(CiscoBaseConnection, self).exit_config_mode(exit_config=exit_config,
                                                                  pattern=pattern)
 
     def serial_login(self, pri_prompt_terminator=r'#\s*$', alt_prompt_terminator=r'>\s*$',
-                     username_pattern=r"(?:[Uu]ser:|sername|ogin)", pwd_pattern=r"assword",
+                     username_pattern=r"(?:user:|username|login)", pwd_pattern=r"assword",
                      delay_factor=1, max_loops=20):
         self.write_channel(self.TELNET_RETURN)
         output = self.read_channel()
@@ -61,7 +59,7 @@ class CiscoBaseConnection(BaseConnection):
                                      username_pattern, pwd_pattern, delay_factor, max_loops)
 
     def telnet_login(self, pri_prompt_terminator=r'#\s*$', alt_prompt_terminator=r'>\s*$',
-                     username_pattern=r"(?:[Uu]ser:|sername|ogin|User Name)",
+                     username_pattern=r"(?:user:|username|login|user name)",
                      pwd_pattern=r"assword",
                      delay_factor=1, max_loops=20):
         """Telnet login. Can be username/password or just password."""
@@ -77,14 +75,14 @@ class CiscoBaseConnection(BaseConnection):
                 return_msg += output
 
                 # Search for username pattern / send username
-                if re.search(username_pattern, output):
+                if re.search(username_pattern, output, flags=re.I):
                     self.write_channel(self.username + self.TELNET_RETURN)
                     time.sleep(1 * delay_factor)
                     output = self.read_channel()
                     return_msg += output
 
                 # Search for password pattern / send password
-                if re.search(pwd_pattern, output):
+                if re.search(pwd_pattern, output, flags=re.I):
                     self.write_channel(self.password + self.TELNET_RETURN)
                     time.sleep(.5 * delay_factor)
                     output = self.read_channel()
@@ -109,7 +107,8 @@ class CiscoBaseConnection(BaseConnection):
 
                 # Check for device with no password configured
                 if re.search(r"assword required, but none set", output):
-                    msg = "Telnet login failed - Password required, but none set: {}".format(
+                    self.remote_conn.close()
+                    msg = "Login failed - Password required, but none set: {}".format(
                         self.host)
                     raise NetMikoAuthenticationException(msg)
 
@@ -122,7 +121,8 @@ class CiscoBaseConnection(BaseConnection):
                 time.sleep(.5 * delay_factor)
                 i += 1
             except EOFError:
-                msg = "Telnet login failed: {}".format(self.host)
+                self.remote_conn.close()
+                msg = "Login failed: {}".format(self.host)
                 raise NetMikoAuthenticationException(msg)
 
         # Last try to see if we already logged in
@@ -134,7 +134,8 @@ class CiscoBaseConnection(BaseConnection):
                 or re.search(alt_prompt_terminator, output, flags=re.M)):
             return return_msg
 
-        msg = "Telnet login failed: {}".format(self.host)
+        self.remote_conn.close()
+        msg = "Login failed: {}".format(self.host)
         raise NetMikoAuthenticationException(msg)
 
     def cleanup(self):
@@ -144,6 +145,7 @@ class CiscoBaseConnection(BaseConnection):
         except Exception:
             # Always try to send 'exit' regardless of whether exit_config_mode works or not.
             pass
+        self._session_log_fin = True
         self.write_channel("exit" + self.RETURN)
 
     def _autodetect_fs(self, cmd='dir', pattern=r'Directory of (.*)/'):
diff --git a/netmiko/citrix/__init__.py b/netmiko/citrix/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..cd2372af472a37496a3edaae63d3a94e3da7f468
--- /dev/null
+++ b/netmiko/citrix/__init__.py
@@ -0,0 +1,4 @@
+from __future__ import unicode_literals
+from netmiko.citrix.netscaler_ssh import NetscalerSSH
+
+__all__ = ['NetscalerSSH']
diff --git a/netmiko/citrix/netscaler_ssh.py b/netmiko/citrix/netscaler_ssh.py
new file mode 100644
index 0000000000000000000000000000000000000000..73b3cb84428caebe762b2b9638d74980362f5b66
--- /dev/null
+++ b/netmiko/citrix/netscaler_ssh.py
@@ -0,0 +1,59 @@
+import time
+
+from netmiko.base_connection import BaseConnection
+
+
+class NetscalerSSH(BaseConnection):
+    """ Netscaler SSH class. """
+
+    def session_preparation(self):
+        """Prepare the session after the connection has been established."""
+        # 0 will defer to the global delay factor
+        delay_factor = self.select_delay_factor(delay_factor=0)
+        self._test_channel_read()
+        self.set_base_prompt()
+        cmd = "{}set cli mode -page OFF{}".format(self.RETURN, self.RETURN)
+        self.disable_paging(command=cmd)
+        time.sleep(1 * delay_factor)
+        self.set_base_prompt()
+        time.sleep(.3 * delay_factor)
+        self.clear_buffer()
+
+    def set_base_prompt(self, pri_prompt_terminator='#',
+                        alt_prompt_terminator='>', delay_factor=1):
+        """Sets self.base_prompt.
+
+        Netscaler has '>' for the prompt.
+        """
+        prompt = self.find_prompt(delay_factor=delay_factor)
+        if not prompt[-1] in (pri_prompt_terminator, alt_prompt_terminator):
+            raise ValueError("Router prompt not found: {}".format(repr(prompt)))
+
+        prompt = prompt.strip()
+        if len(prompt) == 1:
+            self.base_prompt = prompt
+        else:
+            # Strip off trailing terminator
+            self.base_prompt = prompt[:-1]
+        return self.base_prompt
+
+    def check_config_mode(self):
+        """Netscaler devices do not have a config mode."""
+        return False
+
+    def config_mode(self):
+        """Netscaler devices do not have a config mode."""
+        return ''
+
+    def exit_config_mode(self):
+        """Netscaler devices do not have a config mode."""
+        return ''
+
+    def strip_prompt(self, a_string):
+        """ Strip 'Done' from command output """
+        output = super(NetscalerSSH, self).strip_prompt(a_string)
+        lines = output.split(self.RESPONSE_RETURN)
+        if "Done" in lines[-1]:
+            return 'self.RESPONSE_RETURN'.join(lines[:-1])
+        else:
+            return output
diff --git a/netmiko/dell/__init__.py b/netmiko/dell/__init__.py
index 40d7888500005769daf438c08c89920ab4a7f58c..c2958189cbe8013540e6da228d8bcdb8e9803005 100644
--- a/netmiko/dell/__init__.py
+++ b/netmiko/dell/__init__.py
@@ -1,6 +1,9 @@
 from __future__ import unicode_literals
 from netmiko.dell.dell_force10_ssh import DellForce10SSH
+from netmiko.dell.dell_os10_ssh import DellOS10SSH, DellOS10FileTransfer
 from netmiko.dell.dell_powerconnect import DellPowerConnectSSH
 from netmiko.dell.dell_powerconnect import DellPowerConnectTelnet
+from netmiko.dell.dell_isilon_ssh import DellIsilonSSH
 
-__all__ = ['DellForce10SSH', 'DellPowerConnectSSH', 'DellPowerConnectTelnet']
+__all__ = ['DellForce10SSH', 'DellPowerConnectSSH', 'DellPowerConnectTelnet',
+           'DellOS10SSH', 'DellOS10FileTransfer', 'DellIsilonSSH']
diff --git a/netmiko/dell/dell_isilon_ssh.py b/netmiko/dell/dell_isilon_ssh.py
new file mode 100644
index 0000000000000000000000000000000000000000..3e181cea341b4de75b365b0d39542fbff212179d
--- /dev/null
+++ b/netmiko/dell/dell_isilon_ssh.py
@@ -0,0 +1,85 @@
+from __future__ import unicode_literals
+
+import time
+import re
+
+from netmiko.base_connection import BaseConnection
+
+
+class DellIsilonSSH(BaseConnection):
+    def set_base_prompt(self, pri_prompt_terminator='$',
+                        alt_prompt_terminator='#', delay_factor=1):
+        """Determine base prompt."""
+        return super(DellIsilonSSH, self).set_base_prompt(
+            pri_prompt_terminator=pri_prompt_terminator,
+            alt_prompt_terminator=alt_prompt_terminator,
+            delay_factor=delay_factor)
+
+    def strip_ansi_escape_codes(self, string_buffer):
+        """Remove Null code"""
+        output = re.sub(r'\x00', '', string_buffer)
+        return super(DellIsilonSSH, self).strip_ansi_escape_codes(output)
+
+    def session_preparation(self):
+        """Prepare the session after the connection has been established."""
+        self.ansi_escape_codes = True
+        self.zsh_mode()
+        self.find_prompt(delay_factor=1)
+        self.set_base_prompt()
+        # Clear the read buffer
+        time.sleep(.3 * self.global_delay_factor)
+        self.clear_buffer()
+
+    def zsh_mode(self, delay_factor=1, prompt_terminator="$"):
+        """Run zsh command to unify the environment"""
+        delay_factor = self.select_delay_factor(delay_factor)
+        self.clear_buffer()
+        command = self.RETURN + "zsh" + self.RETURN
+        self.write_channel(command)
+        time.sleep(1 * delay_factor)
+        self.set_prompt()
+        self.clear_buffer()
+
+    def set_prompt(self, prompt_terminator="$"):
+        prompt = "PROMPT='%m{}'".format(prompt_terminator)
+        command = self.RETURN + prompt + self.RETURN
+        self.write_channel(command)
+
+    def disable_paging(self, *args, **kwargs):
+        """Isilon doesn't have paging by default."""
+        pass
+
+    def check_enable_mode(self, *args, **kwargs):
+        """No enable mode on Isilon."""
+        pass
+
+    def enable(self, *args, **kwargs):
+        """No enable mode on Isilon."""
+        pass
+
+    def exit_enable_mode(self, *args, **kwargs):
+        """No enable mode on Isilon."""
+        pass
+
+    def check_config_mode(self, check_string='#'):
+        return super(DellIsilonSSH, self).check_config_mode(check_string=check_string)
+
+    def config_mode(self, config_command='sudo su'):
+        """Attempt to become root."""
+        delay_factor = self.select_delay_factor(delay_factor=1)
+        output = ""
+        if not self.check_config_mode():
+            output += self.send_command_timing(config_command, strip_prompt=False,
+                                               strip_command=False)
+            if 'Password:' in output:
+                output = self.write_channel(self.normalize_cmd(self.secret))
+            self.set_prompt(prompt_terminator="#")
+            time.sleep(1 * delay_factor)
+            self.set_base_prompt()
+            if not self.check_config_mode():
+                raise ValueError("Failed to configuration mode")
+        return output
+
+    def exit_config_mode(self, exit_config='exit'):
+        """Exit enable mode."""
+        return super(DellIsilonSSH, self).exit_config_mode(exit_config=exit_config)
diff --git a/netmiko/dell/dell_os10_ssh.py b/netmiko/dell/dell_os10_ssh.py
new file mode 100644
index 0000000000000000000000000000000000000000..27f7d5f3660b6124e6df5827ab80f2c38d664f8b
--- /dev/null
+++ b/netmiko/dell/dell_os10_ssh.py
@@ -0,0 +1,91 @@
+"""Dell EMC Networking OS10 Driver - supports dellos10."""
+
+from netmiko.cisco_base_connection import CiscoSSHConnection
+from netmiko.scp_handler import BaseFileTransfer
+import os
+import re
+
+
+class DellOS10SSH(CiscoSSHConnection):
+    """Dell EMC Networking OS10 Driver - supports dellos10."""
+    def save_config(self, cmd='copy running-configuration startup-configuration', confirm=False):
+        """Saves Config"""
+        return super(DellOS10SSH, self).save_config(cmd=cmd, confirm=confirm)
+
+
+class DellOS10FileTransfer(BaseFileTransfer):
+    """Dell EMC Networking OS10 SCP File Transfer driver."""
+    def __init__(self, ssh_conn, source_file, dest_file, file_system=None, direction='put'):
+        if file_system is None:
+            file_system = '/home/admin'
+        super(DellOS10FileTransfer, self).__init__(ssh_conn=ssh_conn, source_file=source_file,
+                                                   dest_file=dest_file, file_system=file_system,
+                                                   direction=direction)
+        self.folder_name = '/config'
+
+    def remote_file_size(self, remote_cmd='', remote_file=None):
+        """Get the file size of the remote file."""
+        if remote_file is None:
+            if self.direction == 'put':
+                remote_file = self.dest_file
+            elif self.direction == 'get':
+                remote_file = self.source_file
+        remote_cmd = 'system "ls -l {}/{}"'.format(self.file_system, remote_file)
+        remote_out = self.ssh_ctl_chan.send_command(remote_cmd)
+        for line in remote_out.splitlines():
+            if remote_file in line:
+                file_size = line.split()[4]
+                break
+        if 'Error opening' in remote_out or 'No such file or directory' in remote_out:
+            raise IOError("Unable to find file on remote system")
+        else:
+            return int(file_size)
+
+    def remote_space_available(self, search_pattern=r"(\d+) bytes free"):
+        """Return space available on remote device."""
+        remote_cmd = 'system "df {}"'.format(self.folder_name)
+        remote_output = self.ssh_ctl_chan.send_command_expect(remote_cmd)
+        for line in remote_output.splitlines():
+            if self.folder_name in line:
+                space_available = line.split()[-3]
+                break
+        return int(space_available)
+
+    @staticmethod
+    def process_md5(md5_output, pattern=r'(.*) (.*)'):
+        return super(DellOS10FileTransfer, DellOS10FileTransfer).process_md5(md5_output,
+                                                                             pattern=r'(.*) (.*)')
+
+    def remote_md5(self, base_cmd='verify /md5', remote_file=None):
+        """Calculate remote MD5 and returns the hash. """
+        if remote_file is None:
+            if self.direction == 'put':
+                remote_file = self.dest_file
+            elif self.direction == 'get':
+                remote_file = self.source_file
+        remote_md5_cmd = 'system "md5sum {}/{}"'.format(self.file_system, remote_file)
+        dest_md5 = self.ssh_ctl_chan.send_command(remote_md5_cmd, max_loops=1500)
+        dest_md5 = self.process_md5(dest_md5)
+        return dest_md5.strip()
+
+    def check_file_exists(self, remote_cmd="dir home"):
+        """Check if the dest_file already exists on the file system (return boolean)."""
+        if self.direction == 'put':
+            remote_out = self.ssh_ctl_chan.send_command_expect(remote_cmd)
+            search_string = r"Directory contents .*{}".format(self.dest_file)
+            return bool(re.search(search_string, remote_out, flags=re.DOTALL))
+        elif self.direction == 'get':
+            return os.path.exists(self.dest_file)
+
+    def put_file(self):
+        """SCP copy the file from the local system to the remote device."""
+        destination = "{}".format(self.dest_file)
+        self.scp_conn.scp_transfer_file(self.source_file, destination)
+        # Must close the SCP connection to get the file written (flush)
+        self.scp_conn.close()
+
+    def get_file(self):
+        """SCP copy the file from the remote device to local system."""
+        source_file = "{}".format(self.source_file)
+        self.scp_conn.scp_get_file(source_file, self.dest_file)
+        self.scp_conn.close()
diff --git a/netmiko/dell/dell_powerconnect.py b/netmiko/dell/dell_powerconnect.py
index f85ea22a4535c6b46aa134b0b55387c8b23d3c6b..04c8646ca51bddda5164a9c6bec3369778509bb0 100644
--- a/netmiko/dell/dell_powerconnect.py
+++ b/netmiko/dell/dell_powerconnect.py
@@ -3,7 +3,7 @@ from __future__ import unicode_literals
 from paramiko import SSHClient
 import time
 from os import path
-from netmiko.cisco_base_connection import CiscoSSHConnection
+from netmiko.cisco_base_connection import CiscoBaseConnection
 
 
 class SSHClient_noauth(SSHClient):
@@ -12,13 +12,14 @@ class SSHClient_noauth(SSHClient):
         return
 
 
-class DellPowerConnectBase(CiscoSSHConnection):
+class DellPowerConnectBase(CiscoBaseConnection):
     """Dell PowerConnect Driver."""
     def session_preparation(self):
         """Prepare the session after the connection has been established."""
         self.ansi_escape_codes = True
         self._test_channel_read()
         self.set_base_prompt()
+        self.enable()
         self.disable_paging(command="terminal datadump")
         # Clear the read buffer
         time.sleep(.3 * self.global_delay_factor)
@@ -100,14 +101,5 @@ class DellPowerConnectSSH(DellPowerConnectBase):
 
 
 class DellPowerConnectTelnet(DellPowerConnectBase):
-    def session_preparation(self):
-        """Prepare the session after the connection has been established."""
-        self.ansi_escape_codes = True
-        self._test_channel_read()
-        self.set_base_prompt()
-        self.enable()
-        self.disable_paging(command="terminal length 0")
-        self.set_terminal_width()
-        # Clear the read buffer
-        time.sleep(.3 * self.global_delay_factor)
-        self.clear_buffer()
+    """Dell PowerConnect Telnet Driver."""
+    pass
diff --git a/netmiko/extreme/extreme_wing_ssh.py b/netmiko/extreme/extreme_wing_ssh.py
index c026d7e21506d78c8a56703c249a114369b30cae..aabeb828d4fa7c0e04806b6cf759ce7f8a43b8b2 100644
--- a/netmiko/extreme/extreme_wing_ssh.py
+++ b/netmiko/extreme/extreme_wing_ssh.py
@@ -6,11 +6,10 @@ from netmiko.cisco_base_connection import CiscoSSHConnection
 class ExtremeWingSSH(CiscoSSHConnection):
     """Extreme WiNG support."""
     def session_preparation(self):
-        self.set_base_prompt(pri_prompt_terminator='>',
-                             alt_prompt_terminator='#',
-                             delay_factor=2)
+        """Disable paging and set Max term width"""
+        self._test_channel_read(pattern=r">|#")
+        self.set_base_prompt()
         self.disable_paging(command="no page")
         self.set_terminal_width(command='terminal width 512')
-        # Clear the read buffer
         time.sleep(.3 * self.global_delay_factor)
         self.clear_buffer()
diff --git a/netmiko/fortinet/fortinet_ssh.py b/netmiko/fortinet/fortinet_ssh.py
index 793d28311b296a240e0455cc82f643fbd33ba298..f20231334f1f3a4dffb086717c2d3a33a95eebde 100644
--- a/netmiko/fortinet/fortinet_ssh.py
+++ b/netmiko/fortinet/fortinet_ssh.py
@@ -1,6 +1,7 @@
 from __future__ import unicode_literals
 import paramiko
 import time
+import re
 from netmiko.cisco_base_connection import CiscoSSHConnection
 
 
@@ -28,6 +29,7 @@ class FortinetSSH(CiscoSSHConnection):
         output = self.send_command_timing(check_command)
         self.allow_disable_global = True
         self.vdoms = False
+        self._output_mode = 'more'
 
         if "Virtual domain configuration: enable" in output:
             self.vdoms = True
@@ -40,6 +42,7 @@ class FortinetSSH(CiscoSSHConnection):
 
         new_output = ''
         if self.allow_disable_global:
+            self._retrieve_output_mode()
             disable_paging_commands = ["config system console", "set output standard", "end"]
             # There is an extra 'end' required if in multi-vdoms are enabled
             if self.vdoms:
@@ -51,10 +54,24 @@ class FortinetSSH(CiscoSSHConnection):
 
         return output + new_output
 
+    def _retrieve_output_mode(self):
+        """Save the state of the output mode so it can be reset at the end of the session."""
+        reg_mode = re.compile(r'output\s+:\s+(?P<mode>.*)\s+\n')
+        output = self.send_command("get system console")
+        result_mode_re = reg_mode.search(output)
+        if result_mode_re:
+            result_mode = result_mode_re.group('mode').strip()
+            if result_mode in ['more', 'standard']:
+                self._output_mode = result_mode
+
     def cleanup(self):
         """Re-enable paging globally."""
         if self.allow_disable_global:
-            enable_paging_commands = ["config system console", "set output more", "end"]
+            # Return paging state
+            output_mode_cmd = "set output {}".format(self._output_mode)
+            enable_paging_commands = ["config system console",
+                                      output_mode_cmd,
+                                      "end"]
             if self.vdoms:
                 enable_paging_commands.insert(0, "config global")
             # Should test output is valid
diff --git a/netmiko/hp/__init__.py b/netmiko/hp/__init__.py
index 46a953d8defc3009cb70d4c80c478bb3252486fe..5eefcbc0c2cc12b1f2efb47193d12e4d31711445 100644
--- a/netmiko/hp/__init__.py
+++ b/netmiko/hp/__init__.py
@@ -1,5 +1,5 @@
 from __future__ import unicode_literals
-from netmiko.hp.hp_procurve_ssh import HPProcurveSSH
-from netmiko.hp.hp_comware_ssh import HPComwareSSH
+from netmiko.hp.hp_procurve import HPProcurveSSH, HPProcurveTelnet
+from netmiko.hp.hp_comware import HPComwareSSH, HPComwareTelnet
 
-__all__ = ['HPProcurveSSH', 'HPComwareSSH']
+__all__ = ['HPProcurveSSH', 'HPProcurveTelnet', 'HPComwareSSH', 'HPComwareTelnet']
diff --git a/netmiko/hp/hp_comware_ssh.py b/netmiko/hp/hp_comware.py
similarity index 74%
rename from netmiko/hp/hp_comware_ssh.py
rename to netmiko/hp/hp_comware.py
index 76d867084f33c9525c8ff0420154e2102ba014e4..18cc3c7dba927bf77b2a73e04ac2db9d1f995256 100644
--- a/netmiko/hp/hp_comware_ssh.py
+++ b/netmiko/hp/hp_comware.py
@@ -4,7 +4,7 @@ import time
 from netmiko.cisco_base_connection import CiscoSSHConnection
 
 
-class HPComwareSSH(CiscoSSHConnection):
+class HPComwareBase(CiscoSSHConnection):
 
     def session_preparation(self):
         """
@@ -32,15 +32,16 @@ class HPComwareSSH(CiscoSSHConnection):
 
     def config_mode(self, config_command='system-view'):
         """Enter configuration mode."""
-        return super(HPComwareSSH, self).config_mode(config_command=config_command)
+        return super(HPComwareBase, self).config_mode(config_command=config_command)
 
-    def exit_config_mode(self, exit_config='return'):
+    def exit_config_mode(self, exit_config='return', pattern=r'>'):
         """Exit config mode."""
-        return super(HPComwareSSH, self).exit_config_mode(exit_config=exit_config)
+        return super(HPComwareBase, self).exit_config_mode(exit_config=exit_config,
+                                                           pattern=pattern)
 
     def check_config_mode(self, check_string=']'):
         """Check whether device is in configuration mode. Return a boolean."""
-        return super(HPComwareSSH, self).check_config_mode(check_string=check_string)
+        return super(HPComwareBase, self).check_config_mode(check_string=check_string)
 
     def set_base_prompt(self, pri_prompt_terminator='>', alt_prompt_terminator=']',
                         delay_factor=1):
@@ -54,7 +55,7 @@ class HPComwareSSH(CiscoSSHConnection):
 
         This will be set on logging in, but not when entering system-view
         """
-        prompt = super(HPComwareSSH, self).set_base_prompt(
+        prompt = super(HPComwareBase, self).set_base_prompt(
             pri_prompt_terminator=pri_prompt_terminator,
             alt_prompt_terminator=alt_prompt_terminator,
             delay_factor=delay_factor)
@@ -79,4 +80,15 @@ class HPComwareSSH(CiscoSSHConnection):
 
     def save_config(self, cmd='save force', confirm=False):
         """Save Config."""
-        return super(HPComwareSSH, self).save_config(cmd=cmd, confirm=confirm)
+        return super(HPComwareBase, self).save_config(cmd=cmd, confirm=confirm)
+
+
+class HPComwareSSH(HPComwareBase):
+    pass
+
+
+class HPComwareTelnet(HPComwareBase):
+    def __init__(self, *args, **kwargs):
+        default_enter = kwargs.get('default_enter')
+        kwargs['default_enter'] = '\r\n' if default_enter is None else default_enter
+        super(HPComwareTelnet, self).__init__(*args, **kwargs)
diff --git a/netmiko/hp/hp_procurve_ssh.py b/netmiko/hp/hp_procurve.py
similarity index 72%
rename from netmiko/hp/hp_procurve_ssh.py
rename to netmiko/hp/hp_procurve.py
index fadaa6a592358368258546dbbcc3d14a24841610..3f30ebb9a22d8fa5d513ad63c505daed6c4c857f 100644
--- a/netmiko/hp/hp_procurve_ssh.py
+++ b/netmiko/hp/hp_procurve.py
@@ -7,7 +7,7 @@ from netmiko.cisco_base_connection import CiscoSSHConnection
 from netmiko import log
 
 
-class HPProcurveSSH(CiscoSSHConnection):
+class HPProcurveBase(CiscoSSHConnection):
 
     def session_preparation(self):
         """
@@ -44,6 +44,8 @@ class HPProcurveSSH(CiscoSSHConnection):
     def enable(self, cmd='enable', pattern='password', re_flags=re.IGNORECASE,
                default_username='manager'):
         """Enter enable mode"""
+        if self.check_enable_mode():
+            return ''
         output = self.send_command_timing(cmd)
         if 'username' in output.lower() or 'login name' in output.lower() or \
                 'user name' in output.lower():
@@ -63,10 +65,13 @@ class HPProcurveSSH(CiscoSSHConnection):
             time.sleep(.5)
             output = self.read_channel()
             if 'Do you want to log out' in output:
+                self._session_log_fin = True
                 self.write_channel("y" + self.RETURN)
             # Don't automatically save the config (user's responsibility)
             elif 'Do you want to save the current' in output:
+                self._session_log_fin = True
                 self.write_channel("n" + self.RETURN)
+
             try:
                 self.write_channel(self.RETURN)
             except socket.error:
@@ -75,4 +80,22 @@ class HPProcurveSSH(CiscoSSHConnection):
 
     def save_config(self, cmd='write memory', confirm=False):
         """Save Config."""
-        return super(HPProcurveSSH, self).save_config(cmd=cmd, confirm=confirm)
+        return super(HPProcurveBase, self).save_config(cmd=cmd, confirm=confirm)
+
+
+class HPProcurveSSH(HPProcurveBase):
+    pass
+
+
+class HPProcurveTelnet(HPProcurveBase):
+    def telnet_login(self, pri_prompt_terminator='#', alt_prompt_terminator='>',
+                     username_pattern=r"Login Name:", pwd_pattern=r"assword",
+                     delay_factor=1, max_loops=60):
+        """Telnet login: can be username/password or just password."""
+        super(HPProcurveTelnet, self).telnet_login(
+                pri_prompt_terminator=pri_prompt_terminator,
+                alt_prompt_terminator=alt_prompt_terminator,
+                username_pattern=username_pattern,
+                pwd_pattern=pwd_pattern,
+                delay_factor=delay_factor,
+                max_loops=max_loops)
diff --git a/netmiko/linux/linux_ssh.py b/netmiko/linux/linux_ssh.py
index b08425e9962709e305759479878db92ce008a46b..44215f3efbf5d266629b82e0df5c0a33ca5947c7 100644
--- a/netmiko/linux/linux_ssh.py
+++ b/netmiko/linux/linux_ssh.py
@@ -93,6 +93,7 @@ class LinuxSSH(CiscoSSHConnection):
 
     def cleanup(self):
         """Try to Gracefully exit the SSH session."""
+        self._session_log_fin = True
         self.write_channel("exit" + self.RETURN)
 
     def save_config(self, cmd='', confirm=True, confirm_response=''):
diff --git a/netmiko/py23_compat.py b/netmiko/py23_compat.py
index 570092e4b3c0ee6585453e67e840262a8565eaca..cda8d3f34f6cddeacb36142be765190c92f8f74b 100644
--- a/netmiko/py23_compat.py
+++ b/netmiko/py23_compat.py
@@ -2,6 +2,7 @@
 from __future__ import print_function
 from __future__ import unicode_literals
 
+import io
 import sys
 
 PY2 = sys.version_info.major == 2
@@ -10,6 +11,8 @@ PY3 = sys.version_info.major == 3
 if PY3:
     string_types = (str,)
     text_type = str
+    bufferedio_types = io.BufferedIOBase
 else:
     string_types = (basestring,)  # noqa
     text_type = unicode  # noqa
+    bufferedio_types = (io.BufferedIOBase, file)    # noqa
diff --git a/netmiko/quanta/quanta_mesh_ssh.py b/netmiko/quanta/quanta_mesh_ssh.py
index ddca0961e1beb175824fde02cea259ccfa38f70c..f98dcd7074eb5609ea048cd27f09f813af30b3bb 100644
--- a/netmiko/quanta/quanta_mesh_ssh.py
+++ b/netmiko/quanta/quanta_mesh_ssh.py
@@ -11,6 +11,6 @@ class QuantaMeshSSH(CiscoSSHConnection):
         """Enter configuration mode."""
         return super(QuantaMeshSSH, self).config_mode(config_command=config_command)
 
-    def save_config(self, cmd='', confirm=True, confirm_response=''):
-        """Not Implemented"""
-        raise NotImplementedError
+    def save_config(self, cmd='copy running-config startup-config', confirm=False):
+        """Saves Config"""
+        return super(QuantaMeshSSH, self).save_config(cmd=cmd, confirm=confirm)
diff --git a/netmiko/snmp_autodetect.py b/netmiko/snmp_autodetect.py
index 2779224da30f05479384da99308e67b74db25977..29d819a2f0dd1ac3f2eb86ef0ef6de3ef8163dc8 100644
--- a/netmiko/snmp_autodetect.py
+++ b/netmiko/snmp_autodetect.py
@@ -36,6 +36,9 @@ SNMP_MAPPER_BASE = {
     'arista_eos': {"oid": ".1.3.6.1.2.1.1.1.0",
                    "expr": re.compile(r".*Arista Networks EOS.*", re.IGNORECASE),
                    "priority": 99},
+    'paloalto_panos': {"oid": ".1.3.6.1.2.1.1.1.0",
+                       "expr": re.compile(r".*Palo Alto Networks.*", re.IGNORECASE),
+                       "priority": 99},
     'hp_comware': {"oid": ".1.3.6.1.2.1.1.1.0",
                    "expr": re.compile(r".*HP Comware.*", re.IGNORECASE),
                    "priority": 99},
diff --git a/netmiko/ssh_autodetect.py b/netmiko/ssh_autodetect.py
index 89d0a4cf4eec182d865f54022c866987a01abf8f..8297f704dd5c99e0a57d83267f593f4d5970742f 100644
--- a/netmiko/ssh_autodetect.py
+++ b/netmiko/ssh_autodetect.py
@@ -52,12 +52,12 @@ from netmiko.base_connection import BaseConnection
 SSH_MAPPER_BASE = {
     'alcatel_aos': {
         "cmd": "show system",
-        "search_patterns": ["Alcatel-Lucent"],
+        "search_patterns": [r"Alcatel-Lucent"],
         "priority": 99,
         "dispatch": "_autodetect_std",
     },
     'alcatel_sros': {
-        "cmd": "show version | match TiMOS",
+        "cmd": "show version",
         "search_patterns": [
             "Nokia",
             "Alcatel",
@@ -65,14 +65,20 @@ SSH_MAPPER_BASE = {
         "priority": 99,
         "dispatch": "_autodetect_std",
     },
+    'apresia_aeos': {
+        "cmd": "show system",
+        "search_patterns": ["Apresia"],
+        "priority": 99,
+        "dispatch": "_autodetect_std",
+    },
     'arista_eos': {
-        "cmd": "show version | inc rist",
-        "search_patterns": ["Arista"],
+        "cmd": "show version",
+        "search_patterns": [r"Arista"],
         "priority": 99,
         "dispatch": "_autodetect_std",
     },
     'cisco_ios': {
-        "cmd": "show version | inc Cisco",
+        "cmd": "show version",
         "search_patterns": [
            "Cisco IOS Software",
            "Cisco Internetwork Operating System Software"
@@ -81,45 +87,51 @@ SSH_MAPPER_BASE = {
         "dispatch": "_autodetect_std",
     },
     'cisco_asa': {
-        "cmd": "show version | inc Cisco",
-        "search_patterns": ["Cisco Adaptive Security Appliance", "Cisco ASA"],
+        "cmd": "show version",
+        "search_patterns": [r"Cisco Adaptive Security Appliance", r"Cisco ASA"],
         "priority": 99,
         "dispatch": "_autodetect_std",
     },
     'cisco_nxos': {
-        "cmd": "show version | inc Cisco",
-        "search_patterns": ["Cisco Nexus Operating System", "NX-OS"],
+        "cmd": "show version",
+        "search_patterns": [r"Cisco Nexus Operating System", r"NX-OS"],
         "priority": 99,
         "dispatch": "_autodetect_std",
     },
     'cisco_xr': {
-        "cmd": "show version | inc Cisco",
-        "search_patterns": ["Cisco IOS XR"],
+        "cmd": "show version",
+        "search_patterns": [r"Cisco IOS XR"],
         "priority": 99,
         "dispatch": "_autodetect_std",
     },
     'huawei': {
-        "cmd": "display version | inc Huawei",
+        "cmd": "display version",
         "search_patterns": [
-            "Huawei Technologies",
-            "Huawei Versatile Routing Platform Software"
+            r"Huawei Technologies",
+            r"Huawei Versatile Routing Platform Software"
         ],
         "priority": 99,
         "dispatch": "_autodetect_std",
     },
     'juniper_junos': {
-        "cmd": "show version | match JUNOS",
+        "cmd": "show version",
         "search_patterns": [
-            "JUNOS Software Release",
-            "JUNOS .+ Software",
-            "JUNOS OS Kernel",
+            r"JUNOS Software Release",
+            r"JUNOS .+ Software",
+            r"JUNOS OS Kernel",
         ],
         "priority": 99,
         "dispatch": "_autodetect_std",
     },
     'dell_force10': {
-        "cmd": "show version | grep Type",
-        "search_patterns": ["S4048-ON"],
+        "cmd": "show version",
+        "search_patterns": [r"S4048-ON"],
+        "priority": 99,
+        "dispatch": "_autodetect_std",
+    },
+    'dell_os10': {
+        "cmd": "show version",
+        "search_patterns": [r"Dell EMC Networking OS10-Enterprise"],
         "priority": 99,
         "dispatch": "_autodetect_std",
     },
@@ -267,6 +279,7 @@ class SSHDetect(object):
         if not cmd or not search_patterns:
             return 0
         try:
+            # _send_command_wrapper will use already cached results if available
             response = self._send_command_wrapper(cmd)
             # Look for error conditions in output
             for pattern in invalid_responses:
diff --git a/netmiko/ssh_dispatcher.py b/netmiko/ssh_dispatcher.py
index 6309a9bef02c9bc7c33e6bbb50bebb9b7fea9155..987def3764e80e4444e6ecedf3b8729b6137fd93 100644
--- a/netmiko/ssh_dispatcher.py
+++ b/netmiko/ssh_dispatcher.py
@@ -7,6 +7,7 @@ from netmiko.alcatel import AlcatelAosSSH
 from netmiko.alcatel import AlcatelSrosSSH
 from netmiko.arista import AristaSSH, AristaTelnet
 from netmiko.arista import AristaFileTransfer
+from netmiko.apresia import ApresiaAeosSSH, ApresiaAeosTelnet
 from netmiko.aruba import ArubaSSH
 from netmiko.avaya import AvayaErsSSH
 from netmiko.avaya import AvayaVspSSH
@@ -23,10 +24,13 @@ from netmiko.cisco import CiscoS300SSH
 from netmiko.cisco import CiscoTpTcCeSSH
 from netmiko.cisco import CiscoWlcSSH
 from netmiko.cisco import CiscoXrSSH, CiscoXrFileTransfer
+from netmiko.citrix import NetscalerSSH
 from netmiko.coriant import CoriantSSH
 from netmiko.dell import DellForce10SSH
+from netmiko.dell import DellOS10SSH, DellOS10FileTransfer
 from netmiko.dell import DellPowerConnectSSH
 from netmiko.dell import DellPowerConnectTelnet
+from netmiko.dell import DellIsilonSSH
 from netmiko.eltex import EltexSSH
 from netmiko.enterasys import EnterasysSSH
 from netmiko.extreme import ExtremeSSH
@@ -34,7 +38,7 @@ from netmiko.extreme import ExtremeWingSSH
 from netmiko.extreme import ExtremeTelnet
 from netmiko.f5 import F5LtmSSH
 from netmiko.fortinet import FortinetSSH
-from netmiko.hp import HPProcurveSSH, HPComwareSSH
+from netmiko.hp import HPProcurveSSH, HPProcurveTelnet, HPComwareSSH, HPComwareTelnet
 from netmiko.huawei import HuaweiSSH, HuaweiVrpv8SSH
 from netmiko.juniper import JuniperSSH, JuniperTelnet
 from netmiko.juniper import JuniperFileTransfer
@@ -60,6 +64,7 @@ CLASS_MAPPER_BASE = {
     'accedian': AccedianSSH,
     'alcatel_aos': AlcatelAosSSH,
     'alcatel_sros': AlcatelSrosSSH,
+    'apresia_aeos': ApresiaAeosSSH,
     'arista_eos': AristaSSH,
     'aruba_os': ArubaSSH,
     'avaya_ers': AvayaErsSSH,
@@ -82,7 +87,9 @@ CLASS_MAPPER_BASE = {
     'cisco_xr': CiscoXrSSH,
     'coriant': CoriantSSH,
     'dell_force10': DellForce10SSH,
+    'dell_os10': DellOS10SSH,
     'dell_powerconnect': DellPowerConnectSSH,
+    'dell_isilon': DellIsilonSSH,
     'eltex': EltexSSH,
     'enterasys': EnterasysSSH,
     'extreme': ExtremeSSH,
@@ -100,6 +107,7 @@ CLASS_MAPPER_BASE = {
     'mellanox': MellanoxSSH,
     'mrv_optiswitch': MrvOptiswitchSSH,
     'netapp_cdot': NetAppcDotSSH,
+    'netscaler': NetscalerSSH,
     'ovs_linux': OvsLinuxSSH,
     'paloalto_panos': PaloAltoPanosSSH,
     'pluribus': PluribusSSH,
@@ -115,6 +123,7 @@ FILE_TRANSFER_MAP = {
     'arista_eos': AristaFileTransfer,
     'cisco_asa': CiscoAsaFileTransfer,
     'cisco_ios': CiscoIosFileTransfer,
+    'dell_os10': DellOS10FileTransfer,
     'cisco_nxos': CiscoNxosFileTransfer,
     'cisco_xe': CiscoIosFileTransfer,
     'cisco_xr': CiscoXrFileTransfer,
@@ -141,7 +150,10 @@ FILE_TRANSFER_MAP = new_mapper
 CLASS_MAPPER['brocade_fastiron_telnet'] = RuckusFastironTelnet
 CLASS_MAPPER['brocade_netiron_telnet'] = BrocadeNetironTelnet
 CLASS_MAPPER['cisco_ios_telnet'] = CiscoIosTelnet
+CLASS_MAPPER['apresia_aeos_telnet'] = ApresiaAeosTelnet
 CLASS_MAPPER['arista_eos_telnet'] = AristaTelnet
+CLASS_MAPPER['hp_procurve_telnet'] = HPProcurveTelnet
+CLASS_MAPPER['hp_comware_telnet'] = HPComwareTelnet
 CLASS_MAPPER['juniper_junos_telnet'] = JuniperTelnet
 CLASS_MAPPER['calix_b6_telnet'] = CalixB6Telnet
 CLASS_MAPPER['dell_powerconnect_telnet'] = DellPowerConnectTelnet
diff --git a/netmiko/vyos/vyos_ssh.py b/netmiko/vyos/vyos_ssh.py
index f44b6e26580a83cf639b6c532455fd0d9d24eb85..8799499a39c8df3425b28e14685a598fabe8464a 100644
--- a/netmiko/vyos/vyos_ssh.py
+++ b/netmiko/vyos/vyos_ssh.py
@@ -62,7 +62,7 @@ class VyOSSSH(CiscoSSHConnection):
 
         """
         delay_factor = self.select_delay_factor(delay_factor)
-        error_marker = 'Failed to generate committed config'
+        error_marker = ['Failed to generate committed config', 'Commit failed']
         command_string = 'commit'
 
         if comment:
@@ -72,7 +72,7 @@ class VyOSSSH(CiscoSSHConnection):
         output += self.send_command_expect(command_string, strip_prompt=False,
                                            strip_command=False, delay_factor=delay_factor)
 
-        if error_marker in output:
+        if any(x in output for x in error_marker):
             raise ValueError('Commit failed with following errors:\n\n{}'.format(output))
         return output
 
diff --git a/requirements.txt b/requirements.txt
index 0a7f52f20406c7cf67bb7ea0e0f26ffaf564ce23..cd8c47d3d7e46ef695ddb5cc3b9c2d4dfc633d8d 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,3 @@
-paramiko>=2.0.0
-scp>=0.10.0
-pyyaml
-pyserial
-textfsm
+--index-url https://pypi.python.org/simple/
+
+-e .
diff --git a/setup.cfg b/setup.cfg
index 8ba5463ba2c6f62ac6bfc6282a1fd0dcdd164c81..fcd66a95e853af75e5b7fae44ed06e24f58b3152 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,7 +1,7 @@
 [pylama]
 linters = mccabe,pep8,pyflakes
 ignore = D203,C901
-skip = tests/*,build/*,.tox/*,netmiko/_textfsm/*
+skip = tests/*,build/*,.tox/*,netmiko/_textfsm/*,examples/use_cases/*
 
 [pylama:pep8]
 max_line_length = 100
diff --git a/setup.py b/setup.py
index 6330dd553a0aca293942ec40914d3ceece02dd41..d0e25269c9e4e0fccb2ecc7c7b8c824536523f24 100644
--- a/setup.py
+++ b/setup.py
@@ -40,7 +40,13 @@ setup(
         'Programming Language :: Python :: 3.6',
     ],
     packages=find_packages(exclude=("test*", )),
-    install_requires=['paramiko>=2.0.0', 'scp>=0.10.0', 'pyyaml', 'pyserial', 'textfsm'],
+    install_requires=[
+        'paramiko>=2.0.0',
+        'scp>=0.10.0',
+        'pyyaml',
+        'pyserial',
+        'textfsm'
+    ],
     extras_require={
         'test': ['pytest>=3.2.5', ]
     },
diff --git a/tests/SLOG/cisco881_slog.log b/tests/SLOG/cisco881_slog.log
new file mode 100644
index 0000000000000000000000000000000000000000..358220887d430166e4303aeb44e499ffa15a9c46
--- /dev/null
+++ b/tests/SLOG/cisco881_slog.log
@@ -0,0 +1,20 @@
+pynet-rtr1#
+
+pynet-rtr1#terminal length 0
+terminal length 0
+pynet-rtr1#terminal width 511
+terminal width 511
+pynet-rtr1#
+
+pynet-rtr1#show ip interface brief
+show ip interface brief
+Interface                  IP-Address      OK? Method Status                Protocol
+FastEthernet0              unassigned      YES unset  down                  down    
+FastEthernet1              unassigned      YES unset  down                  down    
+FastEthernet2              unassigned      YES unset  down                  down    
+FastEthernet3              unassigned      YES unset  down                  down    
+FastEthernet4              10.220.88.20    YES NVRAM  up                    up      
+Vlan1                      unassigned      YES unset  down                  down    
+pynet-rtr1#
+
+pynet-rtr1#exit
diff --git a/tests/SLOG/cisco881_slog_append.log b/tests/SLOG/cisco881_slog_append.log
new file mode 100644
index 0000000000000000000000000000000000000000..b4fcf3a2df129c101e948b12aff951885dda1f8c
--- /dev/null
+++ b/tests/SLOG/cisco881_slog_append.log
@@ -0,0 +1,16 @@
+Initial file contents
+
+pynet-rtr1#
+pynet-rtr1#terminal length 0
+pynet-rtr1#terminal width 511
+pynet-rtr1#
+pynet-rtr1#show ip interface brief
+Interface                  IP-Address      OK? Method Status                Protocol
+FastEthernet0              unassigned      YES unset  down                  down    
+FastEthernet1              unassigned      YES unset  down                  down    
+FastEthernet2              unassigned      YES unset  down                  down    
+FastEthernet3              unassigned      YES unset  down                  down    
+FastEthernet4              10.220.88.20    YES NVRAM  up                    up      
+Vlan1                      unassigned      YES unset  down                  down    
+pynet-rtr1#
+pynet-rtr1#exit
diff --git a/tests/SLOG/cisco881_slog_append_compare.log b/tests/SLOG/cisco881_slog_append_compare.log
new file mode 100644
index 0000000000000000000000000000000000000000..8d9f79606ccb15d899dd2e52609e7bf98707acac
--- /dev/null
+++ b/tests/SLOG/cisco881_slog_append_compare.log
@@ -0,0 +1,14 @@
+pynet-rtr1#
+pynet-rtr1#terminal length 0
+pynet-rtr1#terminal width 511
+pynet-rtr1#
+pynet-rtr1#show ip interface brief
+Interface                  IP-Address      OK? Method Status                Protocol
+FastEthernet0              unassigned      YES unset  down                  down    
+FastEthernet1              unassigned      YES unset  down                  down    
+FastEthernet2              unassigned      YES unset  down                  down    
+FastEthernet3              unassigned      YES unset  down                  down    
+FastEthernet4              10.220.88.20    YES NVRAM  up                    up      
+Vlan1                      unassigned      YES unset  down                  down    
+pynet-rtr1#
+pynet-rtr1#exit
diff --git a/tests/SLOG/cisco881_slog_compare.log b/tests/SLOG/cisco881_slog_compare.log
new file mode 100644
index 0000000000000000000000000000000000000000..8d9f79606ccb15d899dd2e52609e7bf98707acac
--- /dev/null
+++ b/tests/SLOG/cisco881_slog_compare.log
@@ -0,0 +1,14 @@
+pynet-rtr1#
+pynet-rtr1#terminal length 0
+pynet-rtr1#terminal width 511
+pynet-rtr1#
+pynet-rtr1#show ip interface brief
+Interface                  IP-Address      OK? Method Status                Protocol
+FastEthernet0              unassigned      YES unset  down                  down    
+FastEthernet1              unassigned      YES unset  down                  down    
+FastEthernet2              unassigned      YES unset  down                  down    
+FastEthernet3              unassigned      YES unset  down                  down    
+FastEthernet4              10.220.88.20    YES NVRAM  up                    up      
+Vlan1                      unassigned      YES unset  down                  down    
+pynet-rtr1#
+pynet-rtr1#exit
diff --git a/tests/SLOG/cisco881_slog_wr_compare.log b/tests/SLOG/cisco881_slog_wr_compare.log
new file mode 100644
index 0000000000000000000000000000000000000000..358220887d430166e4303aeb44e499ffa15a9c46
--- /dev/null
+++ b/tests/SLOG/cisco881_slog_wr_compare.log
@@ -0,0 +1,20 @@
+pynet-rtr1#
+
+pynet-rtr1#terminal length 0
+terminal length 0
+pynet-rtr1#terminal width 511
+terminal width 511
+pynet-rtr1#
+
+pynet-rtr1#show ip interface brief
+show ip interface brief
+Interface                  IP-Address      OK? Method Status                Protocol
+FastEthernet0              unassigned      YES unset  down                  down    
+FastEthernet1              unassigned      YES unset  down                  down    
+FastEthernet2              unassigned      YES unset  down                  down    
+FastEthernet3              unassigned      YES unset  down                  down    
+FastEthernet4              10.220.88.20    YES NVRAM  up                    up      
+Vlan1                      unassigned      YES unset  down                  down    
+pynet-rtr1#
+
+pynet-rtr1#exit
diff --git a/tests/conftest.py b/tests/conftest.py
index 7baa85f32e16003a4843a538d81e57a6f1cd4186..32f1b069fe8b9526bcdd4712d8af654f29a2acb9 100755
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -48,6 +48,37 @@ def net_connect_cm(request):
     return my_prompt
 
 
+@pytest.fixture(scope='module')
+def net_connect_slog_wr(request):
+    """
+    Create the SSH connection to the remote device. Modify session_log init arguments.
+
+    Return the netmiko connection object.
+    """
+    device_under_test = request.config.getoption('test_device')
+    test_devices = parse_yaml(PWD + "/etc/test_devices.yml")
+    device = test_devices[device_under_test]
+    device['verbose'] = False
+    device['session_log_record_writes'] = True
+    conn = ConnectHandler(**device)
+    return conn
+
+
+@pytest.fixture(scope='module')
+def device_slog(request):
+    """
+    Create the SSH connection to the remote device. Modify session_log init arguments.
+
+    Return the netmiko device (not connected)
+    """
+    device_under_test = request.config.getoption('test_device')
+    test_devices = parse_yaml(PWD + "/etc/test_devices.yml")
+    device = test_devices[device_under_test]
+    device['verbose'] = False
+    device['session_log_file_mode'] = 'append'
+    return device
+
+
 @pytest.fixture(scope='module')
 def expected_responses(request):
     '''
@@ -113,6 +144,18 @@ def delete_file_ios(ssh_conn, dest_file_system, dest_file):
 
     raise ValueError("An error happened deleting file on Cisco IOS")
 
+def delete_file_dellos10(ssh_conn, dest_file_system, dest_file):
+    """Delete a remote file for a Dell OS10 device."""
+    if not dest_file:
+        raise ValueError("Invalid dest file specified")
+
+    cmd = "delete home://{}".format(dest_file)
+    output = ssh_conn.send_command_timing(cmd)
+    if "Proceed to delete" in output:
+        output = ssh_conn.send_command_timing("yes")
+        return output
+
+    raise ValueError("An error happened deleting file on Dell OS10")
 
 def delete_file_generic(ssh_conn, dest_file_system, dest_file):
     """Delete a remote file for a Junos device."""
@@ -337,5 +380,11 @@ def get_platform_args():
             'enable_scp': False,
             'delete_file': delete_file_generic,
         },
+
+        'dellos10': {
+            'file_system': '/home/admin',
+            'enable_scp': False,
+            'delete_file': delete_file_dellos10,
+        },
     }
 
diff --git a/tests/etc/commands.yml.example b/tests/etc/commands.yml.example
index e3ef91cb1787aeaeddafc0855bc98f678d77f210..4715ee8d1395bc08b45d4ac994cf79a6ebd2871a 100644
--- a/tests/etc/commands.yml.example
+++ b/tests/etc/commands.yml.example
@@ -126,6 +126,16 @@ ubiquiti_edge:
     - "logging persistent 4"
   config_verification: "show running-config | include 'logging'"
 
+dellos10:
+  version: "show version"
+  basic: "show ip interface brief"
+  extended_output: "show running-config"
+  config:
+    - "host-description test"
+    - "no host-description"
+    - "host-description node"
+  config_verification: "show running-config"
+
 dell_powerconnect:
   version: "show version"
   basic: "show ip interface vlan 1"
@@ -153,6 +163,11 @@ alcatel_aos:
   config:
     - 'VLAN 666'
   config_verification: "show vlan"
+  
+netscaler:
+  version: "show version"
+  basic: "show ip -summary"
+  extended_output: "show interfaces"
 
 calix_b6_ssh:
   version: "show version"
diff --git a/tests/etc/responses.yml.example b/tests/etc/responses.yml.example
index 12ffc6b8262dbcf29fdb49b09516809e1f4a4563..d900fbc6e7052928cda66e3fa6f0e428cb6ae529 100644
--- a/tests/etc/responses.yml.example
+++ b/tests/etc/responses.yml.example
@@ -78,6 +78,17 @@ ubiquiti_edge:
   cmd_response_init: ""
   cmd_response_final: "logging persistent 4"
 
+dellos10:
+  base_prompt: OS10
+  router_prompt : OS10#
+  enable_prompt: OS10#
+  interface_ip: 192.168.23.129
+  version_banner: "Dell EMC Networking OS10-Enterprise"
+  multiple_line_output: "Last configuration change"
+  cmd_response_init: "host-description test"
+  cmd_response_final: "host-description node"
+  scp_remote_space: 1000
+
 dell_powerconnect:
   base_prompt: myswitch
   router_prompt : myswitch#
@@ -104,6 +115,14 @@ alcatel_aos:
   version_banner: "Alcatel-Lucent OS6250-24 6.7.1.108.R04 Service Release, January 04, 2017"
   multiple_line_output: "FC - ForcedCopper PC - PreferredCopper C - Copper"
 
+netscaler:
+  base_prompt: ">"
+  router_prompt: ">"
+  enable_prompt: ">"
+  interface_ip: "192.168.10.10"
+  multiple_line_output: "Netscaler Loopback interface"
+  version_banner: "NetScaler"
+
 calix_b6_ssh:
   base_prompt: CALIX-B6-TEST
   router_prompt: CALIX-B6-TEST>
@@ -112,4 +131,4 @@ calix_b6_ssh:
   version_banner: "Kernel build id 8.0.30.0"
   multiple_line_output: "rtcPwrUptimeTotal"
   cmd_response_init: "Building configuration...    Done"
-  cmd_response_final: "access-list ethernet 999 permit ip"
\ No newline at end of file
+  cmd_response_final: "access-list ethernet 999 permit ip"
diff --git a/tests/etc/test_devices.yml.example b/tests/etc/test_devices.yml.example
index 5c7a041331d992f0da2d55c9c9fb7c5827286ec9..d322da5be16dcc14ca862437fd284a21795b8af7 100644
--- a/tests/etc/test_devices.yml.example
+++ b/tests/etc/test_devices.yml.example
@@ -89,6 +89,12 @@ dell_powerconnect:
   username: admin
   password: admin
 
+dellos10:
+  device_type: dellos10
+  ip: 192.168.23.129
+  username: admin
+  password: admin
+
 pluribus:
   device_type: pluribus_ssh
   ip: 172.17.19.1
@@ -100,10 +106,16 @@ alcatel_aos:
   ip: 192.168.1.154
   username: admin
   password: switch
+  
+netscaler:
+  device_type: netscaler
+  ip: 192.168.10.10
+  username: admin
+  password: admin
 
 calix_b6_ssh:
   device_type: calix_b6_ssh
   ip: 192.168.99.99
   username: cli
   password: occam
-  secret: razor
\ No newline at end of file
+  secret: razor
diff --git a/tests/test_apresia_aeos.sh b/tests/test_apresia_aeos.sh
new file mode 100755
index 0000000000000000000000000000000000000000..ecdecdccc49a4b08bc0b6aecb743918ef428093a
--- /dev/null
+++ b/tests/test_apresia_aeos.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+RETURN_CODE=0
+
+# Exit on the first test failure and set RETURN_CODE = 1
+echo "Starting tests...good luck:" \
+&& py.test -v test_netmiko_show.py --test_device apresia_aeos_telnet \
+&& py.test -v test_netmiko_config.py --test_device apresia_aeos_telnet \
+|| RETURN_CODE=1
+
+exit $RETURN_CODE
diff --git a/tests/test_cisco.sh b/tests/test_cisco.sh
index cb4e5f3417bd8152cd10647a6431af5d7b8d712a..4d4f6b6f238df9d91de37c029b1f437c390b5290 100755
--- a/tests/test_cisco.sh
+++ b/tests/test_cisco.sh
@@ -4,9 +4,11 @@ RETURN_CODE=0
 
 # Exit on the first test failure and set RETURN_CODE = 1
 echo "Cisco IOS SSH" \
-&& py.test -v test_netmiko_show.py --test_device cisco881_ssh_config \
-&& py.test -v test_netmiko_config.py --test_device cisco881_ssh_config \
+&& date \
+&& py.test -v test_netmiko_show.py --test_device cisco881_fast \
+&& date \
+&& py.test -v test_netmiko_config.py --test_device cisco881_fast \
+&& date \
 || RETURN_CODE=1
 
 exit $RETURN_CODE
-
diff --git a/tests/test_dellos10.sh b/tests/test_dellos10.sh
new file mode 100755
index 0000000000000000000000000000000000000000..f4ab8422497ec4665507be328fd442d84c1f5e83
--- /dev/null
+++ b/tests/test_dellos10.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+RETURN_CODE=0
+
+# Exit on the first test failure and set RETURN_CODE = 1
+echo "Starting tests...good luck:" \
+&& echo "Dell EMC Networking dellos10" \
+&& py.test -v test_netmiko_show.py --test_device dellos10 \
+&& py.test -v test_netmiko_config.py --test_device dellos10 \
+&& py.test -v test_netmiko_scp.py --test_device dellos10 \
+|| RETURN_CODE=1
+
+exit $RETURN_CODE
diff --git a/tests/test_hp_comware_telnet.sh b/tests/test_hp_comware_telnet.sh
new file mode 100755
index 0000000000000000000000000000000000000000..e55e048358698bf7b82891f4b60adaede6198ecf
--- /dev/null
+++ b/tests/test_hp_comware_telnet.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+RETURN_CODE=0
+
+# Exit on the first test failure and set RETURN_CODE = 1
+echo "Starting tests...good luck:" \
+&& py.test -v test_netmiko_show.py --test_device hp_comware_telnet \
+&& py.test -v test_netmiko_config.py --test_device hp_comware_telnet \
+|| RETURN_CODE=1
+
+exit $RETURN_CODE
diff --git a/tests/test_hp_telnet.sh b/tests/test_hp_telnet.sh
new file mode 100644
index 0000000000000000000000000000000000000000..625773c8110a30dd7f552543bb88f28af2adacef
--- /dev/null
+++ b/tests/test_hp_telnet.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+RETURN_CODE=0
+
+# Exit on the first test failure and set RETURN_CODE = 1
+echo "Starting tests...good luck:" \
+&& py.test -v test_netmiko_show.py --test_device hp_procurve_telnet \
+&& py.test -v test_netmiko_config.py --test_device hp_procurve_telnet \
+|| RETURN_CODE=1
+
+exit $RETURN_CODE
\ No newline at end of file
diff --git a/tests/test_netmiko_sesssion_log.py b/tests/test_netmiko_sesssion_log.py
new file mode 100755
index 0000000000000000000000000000000000000000..e04d9f1d98ea589f773d2e9778c0313a94214e6b
--- /dev/null
+++ b/tests/test_netmiko_sesssion_log.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python
+from __future__ import print_function
+from __future__ import unicode_literals
+import time
+import hashlib
+import io
+from netmiko import ConnectHandler
+
+
+def calc_md5(file_name=None, contents=None):
+    """Compute MD5 hash of file."""
+    if contents is not None:
+        pass
+    elif file_name:
+        with open(file_name, "rb") as f:
+            contents = f.read()
+    else:
+        raise ValueError("Most specify either file_name or contents")
+
+    return hashlib.md5(contents).hexdigest()
+
+
+def read_session_log(session_file, append=False):
+    """Leading white-space can vary. Strip off leading white-space."""
+    with open(session_file, "rb") as f:
+        if append is True:
+            line = f.readline().decode()
+            assert 'Initial file contents' in line
+        log_content = f.read().lstrip()
+        return log_content
+
+
+def session_action(my_connect, command):
+    """Common actions in the netmiko session to generate the session log."""
+    time.sleep(1)
+    my_connect.clear_buffer()
+    output = my_connect.send_command(command)
+    my_connect.disconnect()
+    return output
+
+
+def session_log_md5(session_file, compare_file):
+    """Compare the session_log MD5 to the compare_file MD5"""
+    compare_log_md5 = calc_md5(file_name=compare_file)
+    log_content = read_session_log(session_file)
+    session_log_md5 = calc_md5(contents=log_content)
+    assert session_log_md5 == compare_log_md5
+
+
+def session_log_md5_append(session_file, compare_file):
+    """Compare the session_log MD5 to the compare_file MD5"""
+    compare_log_md5 = calc_md5(file_name=compare_file)
+    log_content = read_session_log(session_file, append=True)
+    session_log_md5 = calc_md5(contents=log_content)
+    assert session_log_md5 == compare_log_md5
+
+
+def test_session_log(net_connect, commands, expected_responses):
+    """Verify session_log matches expected content."""
+    command = commands["basic"]
+    session_action(net_connect, command)
+
+    compare_file = expected_responses['compare_log']
+    session_file = expected_responses['session_log']
+
+    session_log_md5(session_file, compare_file)
+
+
+def test_session_log_write(net_connect_slog_wr, commands, expected_responses):
+    """Verify session_log matches expected content, but when channel writes are also logged."""
+    command = commands["basic"]
+    session_action(net_connect_slog_wr, command)
+
+    compare_file = expected_responses['compare_log_wr']
+    session_file = expected_responses['session_log']
+    session_log_md5(session_file, compare_file)
+
+
+def test_session_log_append(device_slog, commands, expected_responses):
+    """Verify session_log matches expected content, but when channel writes are also logged."""
+    session_file = expected_responses['session_log_append']
+    # Create a starting file
+    with open(session_file, "wb") as f:
+        f.write(b"Initial file contents\n\n")
+
+    # The netmiko connection has not been established yet.
+    device_slog['session_log'] = session_file
+
+    conn = ConnectHandler(**device_slog)
+    command = commands["basic"]
+    session_action(conn, command)
+
+    compare_file = expected_responses['compare_log_append']
+    session_log_md5_append(session_file, compare_file)
+
+
+def test_session_log_bytesio(device_slog, commands, expected_responses):
+    """Verify session_log matches expected content, but when channel writes are also logged."""
+    s_log = io.BytesIO()
+
+    # The netmiko connection has not been established yet.
+    device_slog['session_log'] = s_log
+    device_slog['session_log_file_mode'] = 'write'
+
+    conn = ConnectHandler(**device_slog)
+    command = commands["basic"]
+    session_action(conn, command)
+
+    compare_file = expected_responses['compare_log']
+    compare_log_md5 = calc_md5(file_name=compare_file)
+
+    log_content = s_log.getvalue()
+    session_log_md5 = calc_md5(contents=log_content)
+    assert session_log_md5 == compare_log_md5
diff --git a/tests/test_netmiko_show.py b/tests/test_netmiko_show.py
index 9f9b7c416b2314656b85c9649f8c716c603f3b5e..bf5359b7ba066d3896a374a4ae1c3fb824efe1a3 100755
--- a/tests/test_netmiko_show.py
+++ b/tests/test_netmiko_show.py
@@ -63,6 +63,8 @@ def test_base_prompt(net_connect, commands, expected_responses):
 
 def test_strip_prompt(net_connect, commands, expected_responses):
     """Ensure the router prompt is not in the command output."""
+    if expected_responses['base_prompt'] == '':
+        return
     show_ip = net_connect.send_command_timing(commands["basic"])
     show_ip_alt = net_connect.send_command_expect(commands["basic"])
     assert expected_responses['base_prompt'] not in show_ip
diff --git a/tests/test_suite_alt.sh b/tests/test_suite_alt.sh
index d81d8ef9dbcf323fb5ae68459830f25796321639..c84b6e424638c8c3045a4fca317db854db126e0e 100755
--- a/tests/test_suite_alt.sh
+++ b/tests/test_suite_alt.sh
@@ -15,6 +15,13 @@ echo "Starting tests...good luck:" \
 && py.test -v test_netmiko_tcl.py --test_device cisco881 \
 && py.test -v test_netmiko_show.py --test_device cisco881 \
 && py.test -v test_netmiko_config.py --test_device cisco881 \
+&& py.test -v test_netmiko_sesssion_log.py --test_device cisco881_slog \
+\
+&& echo "Cisco IOS SSH fast_cli (including SCP)" \
+&& py.test -v test_netmiko_scp.py --test_device cisco881_fast \
+&& py.test -v test_netmiko_tcl.py --test_device cisco881_fast \
+&& py.test -v test_netmiko_show.py --test_device cisco881_fast \
+&& py.test -v test_netmiko_config.py --test_device cisco881_fast \
 \
 && echo "Cisco IOS using SSH config with SSH Proxy" \
 && py.test -v test_netmiko_show.py --test_device cisco881_ssh_config \