Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Base.lproj/Main.storyboard.iqiyi
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Base.lproj/Main.storyboard.iqiyi	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Base.lproj/Main.storyboard.iqiyi	(working copy)
@@ -0,0 +1,3604 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="idK-RG-cFM">
+    <device id="retina4_7" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--About-->
+        <scene sceneID="7GW-1c-C65">
+            <objects>
+                <viewController id="mDt-jA-kKK" customClass="AboutViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="yyK-sb-qiP"/>
+                        <viewControllerLayoutGuide type="bottom" id="f3i-hb-d4V"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="oK0-bX-MM2">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="GatewayAppIcon" translatesAutoresizingMaskIntoConstraints="NO" id="UYO-df-3Os">
+                                <rect key="frame" x="149.5" y="30" width="76" height="76"/>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="76" id="DTU-jS-aHj"/>
+                                    <constraint firstAttribute="width" constant="76" id="iYc-cD-iOI"/>
+                                </constraints>
+                            </imageView>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="iQIYI VPN" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="yV0-g6-UFN">
+                                <rect key="frame" x="150.5" y="116" width="74" height="21"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <tableView clipsSubviews="YES" contentMode="scaleToFill" bounces="NO" scrollEnabled="NO" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="66" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="jPq-XV-RSO">
+                                <rect key="frame" x="0.0" y="167" width="375" height="192"/>
+                                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="192" id="UZO-4R-Fbh"/>
+                                </constraints>
+                                <prototypes>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="VersionCellID" id="knd-UO-Qgh">
+                                        <rect key="frame" x="0.0" y="28" width="375" height="66"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="knd-UO-Qgh" id="eNV-yN-0ho">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="66"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Version" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TvU-VQ-ZFz">
+                                                    <rect key="frame" x="23" y="9" width="57" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2.0" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GxL-yD-Lwm">
+                                                    <rect key="frame" x="23" y="40" width="21" height="17"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <button opaque="NO" tag="2" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Fvq-rT-MUU">
+                                                    <rect key="frame" x="230" y="18" width="129" height="30"/>
+                                                    <state key="normal" title="Check for Updates">
+                                                        <color key="titleColor" red="0.0" green="0.86274509803921573" blue="0.3529411764705882" alpha="1" colorSpace="calibratedRGB"/>
+                                                    </state>
+                                                </button>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="GxL-yD-Lwm" secondAttribute="trailingMargin" id="Cae-dG-aed"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="TvU-VQ-ZFz" secondAttribute="trailingMargin" id="NiB-R5-rN7"/>
+                                                <constraint firstItem="TvU-VQ-ZFz" firstAttribute="top" secondItem="eNV-yN-0ho" secondAttribute="topMargin" constant="-2" id="UNb-dT-B9f"/>
+                                                <constraint firstItem="GxL-yD-Lwm" firstAttribute="top" secondItem="TvU-VQ-ZFz" secondAttribute="bottom" constant="10" id="fjh-H6-KQL"/>
+                                                <constraint firstItem="Fvq-rT-MUU" firstAttribute="centerY" secondItem="eNV-yN-0ho" secondAttribute="centerY" id="hiu-yG-n3U"/>
+                                                <constraint firstItem="Fvq-rT-MUU" firstAttribute="trailing" secondItem="eNV-yN-0ho" secondAttribute="trailingMargin" id="iz2-WF-66m"/>
+                                                <constraint firstItem="GxL-yD-Lwm" firstAttribute="leading" secondItem="eNV-yN-0ho" secondAttribute="leadingMargin" constant="7" id="lCK-q6-Z6o"/>
+                                                <constraint firstItem="TvU-VQ-ZFz" firstAttribute="leading" secondItem="eNV-yN-0ho" secondAttribute="leadingMargin" constant="7" id="tMZ-46-NSR"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="CopyrightCellID" id="Gps-sY-MiT">
+                                        <rect key="frame" x="0.0" y="94" width="375" height="66"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Gps-sY-MiT" id="Xlc-az-jE4">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="66"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Copyright" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XgP-Wz-cuu">
+                                                    <rect key="frame" x="23" y="9" width="75" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="©2014-2017 Array Networks, Inc. All rights reserved." textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TeR-BG-hdj">
+                                                    <rect key="frame" x="23" y="38" width="341.5" height="17"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="XgP-Wz-cuu" firstAttribute="leading" secondItem="Xlc-az-jE4" secondAttribute="leadingMargin" constant="7" id="9ot-jp-oFq"/>
+                                                <constraint firstItem="TeR-BG-hdj" firstAttribute="leading" secondItem="Xlc-az-jE4" secondAttribute="leadingMargin" constant="7" id="LMY-ul-z2L"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="XgP-Wz-cuu" secondAttribute="trailingMargin" id="MlM-MA-0l7"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="TeR-BG-hdj" secondAttribute="trailingMargin" id="TE1-g6-gaJ"/>
+                                                <constraint firstItem="TeR-BG-hdj" firstAttribute="top" secondItem="XgP-Wz-cuu" secondAttribute="bottom" constant="8" id="qDp-nt-e90"/>
+                                                <constraint firstItem="XgP-Wz-cuu" firstAttribute="top" secondItem="Xlc-az-jE4" secondAttribute="topMargin" constant="-2" id="tIf-t4-A1h"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="DeviceIDCellID" id="Iuh-31-jb1">
+                                        <rect key="frame" x="0.0" y="160" width="375" height="66"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Iuh-31-jb1" id="Y4d-8k-xeJ">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="66"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="DeviceID" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jJq-QL-oqs">
+                                                    <rect key="frame" x="23" y="9" width="68" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="NTp-GP-Z5I">
+                                                    <rect key="frame" x="23" y="34" width="337" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="12"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="jJq-QL-oqs" firstAttribute="top" secondItem="Y4d-8k-xeJ" secondAttribute="topMargin" constant="-2" id="KQR-hC-IcE"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="jJq-QL-oqs" secondAttribute="trailingMargin" id="M68-5s-V79"/>
+                                                <constraint firstItem="jJq-QL-oqs" firstAttribute="leading" secondItem="Y4d-8k-xeJ" secondAttribute="leadingMargin" constant="7" id="Pb7-yN-Cn9"/>
+                                                <constraint firstItem="NTp-GP-Z5I" firstAttribute="top" secondItem="jJq-QL-oqs" secondAttribute="bottom" constant="4" id="Zvt-nU-uF7"/>
+                                                <constraint firstItem="NTp-GP-Z5I" firstAttribute="leading" secondItem="Y4d-8k-xeJ" secondAttribute="leadingMargin" constant="7" id="hNp-KB-ueS"/>
+                                                <constraint firstAttribute="trailing" secondItem="NTp-GP-Z5I" secondAttribute="trailing" constant="15" id="kdp-Vp-lSY"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </prototypes>
+                                <sections/>
+                                <connections>
+                                    <outlet property="dataSource" destination="mDt-jA-kKK" id="VBW-ZX-ZbJ"/>
+                                    <outlet property="delegate" destination="mDt-jA-kKK" id="rHz-CR-7rG"/>
+                                </connections>
+                            </tableView>
+                        </subviews>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <constraints>
+                            <constraint firstItem="UYO-df-3Os" firstAttribute="top" secondItem="yyK-sb-qiP" secondAttribute="bottom" constant="30" id="AjB-ng-LjJ"/>
+                            <constraint firstItem="jPq-XV-RSO" firstAttribute="top" secondItem="yV0-g6-UFN" secondAttribute="bottom" constant="30" id="KkI-dB-0fk"/>
+                            <constraint firstItem="UYO-df-3Os" firstAttribute="centerX" secondItem="oK0-bX-MM2" secondAttribute="centerX" id="LVv-vQ-aju"/>
+                            <constraint firstAttribute="trailing" secondItem="jPq-XV-RSO" secondAttribute="trailing" id="S3g-6a-rE4"/>
+                            <constraint firstItem="yV0-g6-UFN" firstAttribute="centerX" secondItem="oK0-bX-MM2" secondAttribute="centerX" id="ezD-ra-hWD"/>
+                            <constraint firstItem="yV0-g6-UFN" firstAttribute="top" secondItem="UYO-df-3Os" secondAttribute="bottom" constant="10" id="kSb-wW-OTS"/>
+                            <constraint firstItem="jPq-XV-RSO" firstAttribute="leading" secondItem="oK0-bX-MM2" secondAttribute="leading" id="zLj-0q-0qb"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" title="About" id="IH6-7b-axS"/>
+                    <connections>
+                        <outlet property="imageView" destination="UYO-df-3Os" id="uHz-Ki-dMY"/>
+                        <outlet property="tableView" destination="jPq-XV-RSO" id="nus-Oe-AHd"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="StR-Mv-Pcp" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="117.59999999999999" y="-116.49175412293854"/>
+        </scene>
+        <!--Log-->
+        <scene sceneID="XoK-4M-eYE">
+            <objects>
+                <tableViewController id="fhm-J3-Mni" customClass="LogSettingsViewController" sceneMemberID="viewController">
+                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="hps-j4-jFV">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
+                        <color key="separatorColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="calibratedRGB"/>
+                        <sections>
+                            <tableViewSection id="CBw-Nm-plJ">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="IjV-wP-MYk">
+                                        <rect key="frame" x="0.0" y="18" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="IjV-wP-MYk" id="zJl-Z7-1Jr">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Enable Log" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Vye-sA-djA">
+                                                    <rect key="frame" x="23" y="11.5" width="86" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Fd8-FI-uVp">
+                                                    <rect key="frame" x="310" y="6.5" width="51" height="31"/>
+                                                    <connections>
+                                                        <action selector="enableLogSwitched:" destination="fhm-J3-Mni" eventType="valueChanged" id="wX4-eK-ZPS"/>
+                                                    </connections>
+                                                </switch>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="Vye-sA-djA" firstAttribute="leading" secondItem="zJl-Z7-1Jr" secondAttribute="leadingMargin" constant="7" id="LzQ-Vh-bQ0"/>
+                                                <constraint firstAttribute="trailing" secondItem="Fd8-FI-uVp" secondAttribute="trailing" constant="16" id="b1z-OG-FEk"/>
+                                                <constraint firstItem="Vye-sA-djA" firstAttribute="centerY" secondItem="zJl-Z7-1Jr" secondAttribute="centerY" id="dvL-uE-CZz"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="Vye-sA-djA" secondAttribute="trailingMargin" id="wCn-cB-VvR"/>
+                                                <constraint firstItem="Fd8-FI-uVp" firstAttribute="centerY" secondItem="zJl-Z7-1Jr" secondAttribute="centerY" id="yqA-dO-DMH"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="jFq-eh-rOS">
+                                        <rect key="frame" x="0.0" y="62" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="jFq-eh-rOS" id="9II-d0-lJc">
+                                            <rect key="frame" x="0.0" y="0.0" width="348" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Log Level" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="NKn-hb-JOP">
+                                                    <rect key="frame" x="23" y="11.5" width="74" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="NKn-hb-JOP" firstAttribute="leading" secondItem="9II-d0-lJc" secondAttribute="leadingMargin" constant="7" id="Btz-zo-MEF"/>
+                                                <constraint firstItem="NKn-hb-JOP" firstAttribute="centerY" secondItem="9II-d0-lJc" secondAttribute="centerY" id="Pd9-Yi-oba"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="NKn-hb-JOP" secondAttribute="trailingMargin" id="yP2-8s-zPc"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <connections>
+                                            <segue destination="d9b-zV-ilK" kind="show" identifier="GatewayLogSettingsToLogLevel" id="NJX-0i-NN5"/>
+                                        </connections>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="eW7-Se-Bzn">
+                                        <rect key="frame" x="0.0" y="106" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="eW7-Se-Bzn" id="2pV-FB-JHZ">
+                                            <rect key="frame" x="0.0" y="0.0" width="348" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Send Log" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="o4t-io-Lws">
+                                                    <rect key="frame" x="23" y="11.5" width="74" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="o4t-io-Lws" firstAttribute="leading" secondItem="2pV-FB-JHZ" secondAttribute="leadingMargin" constant="7" id="KrR-jm-6d0"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="o4t-io-Lws" secondAttribute="trailingMargin" id="ZDE-bQ-D4G"/>
+                                                <constraint firstItem="o4t-io-Lws" firstAttribute="centerY" secondItem="2pV-FB-JHZ" secondAttribute="centerY" id="yBS-su-Taq"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                        </sections>
+                        <connections>
+                            <outlet property="dataSource" destination="fhm-J3-Mni" id="2lw-Bm-v3m"/>
+                            <outlet property="delegate" destination="fhm-J3-Mni" id="Bcr-zL-QSH"/>
+                        </connections>
+                    </tableView>
+                    <navigationItem key="navigationItem" title="Log" id="TMW-3I-ErZ"/>
+                    <connections>
+                        <outlet property="enableLogSwitch" destination="Fd8-FI-uVp" id="lJJ-Rh-wPI"/>
+                        <outlet property="logLevelCell" destination="jFq-eh-rOS" id="p80-l5-8tz"/>
+                        <outlet property="sendLogCell" destination="eW7-Se-Bzn" id="Zez-jP-LF4"/>
+                    </connections>
+                </tableViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="gxP-7L-2XX" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="1013.6" y="-116.49175412293854"/>
+        </scene>
+        <!--Log Level-->
+        <scene sceneID="efT-r9-Bdc">
+            <objects>
+                <tableViewController id="d9b-zV-ilK" customClass="LogLevelViewController" sceneMemberID="viewController">
+                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="Y1k-b5-WQA">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
+                        <sections>
+                            <tableViewSection id="jht-Md-VQb">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="m45-ml-D4t">
+                                        <rect key="frame" x="0.0" y="18" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="m45-ml-D4t" id="xqE-3G-tfz">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Debug" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="s6d-5f-7hz">
+                                                    <rect key="frame" x="23" y="11.5" width="52" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginSelected" translatesAutoresizingMaskIntoConstraints="NO" id="1ay-Hu-rXk">
+                                                    <rect key="frame" x="338" y="15" width="14" height="14"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="14" id="A7H-xA-2wI"/>
+                                                        <constraint firstAttribute="height" constant="14" id="Bbc-IM-Ez8"/>
+                                                    </constraints>
+                                                </imageView>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="s6d-5f-7hz" firstAttribute="centerY" secondItem="xqE-3G-tfz" secondAttribute="centerY" id="fbq-tJ-xlc"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="1ay-Hu-rXk" secondAttribute="trailing" constant="7" id="oK6-Vo-FIa"/>
+                                                <constraint firstItem="1ay-Hu-rXk" firstAttribute="centerY" secondItem="xqE-3G-tfz" secondAttribute="centerY" id="rPz-ak-7li"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="s6d-5f-7hz" secondAttribute="trailingMargin" id="u2b-Wc-xtk"/>
+                                                <constraint firstItem="s6d-5f-7hz" firstAttribute="leading" secondItem="xqE-3G-tfz" secondAttribute="leadingMargin" constant="7" id="v2a-MB-kSG"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="gGs-sB-9Op">
+                                        <rect key="frame" x="0.0" y="62" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="gGs-sB-9Op" id="L1E-7S-vyc">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Info" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YSf-2U-wvg">
+                                                    <rect key="frame" x="23" y="11.5" width="30" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginSelected" translatesAutoresizingMaskIntoConstraints="NO" id="BjP-i8-8tR">
+                                                    <rect key="frame" x="338" y="15" width="14" height="14"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="14" id="8oq-wd-fFl"/>
+                                                        <constraint firstAttribute="height" constant="14" id="UGy-Xh-hsS"/>
+                                                    </constraints>
+                                                </imageView>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="YSf-2U-wvg" secondAttribute="trailingMargin" id="2Eb-ub-m82"/>
+                                                <constraint firstItem="YSf-2U-wvg" firstAttribute="leading" secondItem="L1E-7S-vyc" secondAttribute="leadingMargin" constant="7" id="GgW-pK-kdk"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="BjP-i8-8tR" secondAttribute="trailing" constant="7" id="lLE-3y-wyG"/>
+                                                <constraint firstItem="BjP-i8-8tR" firstAttribute="centerY" secondItem="L1E-7S-vyc" secondAttribute="centerY" id="xBU-Ti-KGP"/>
+                                                <constraint firstItem="YSf-2U-wvg" firstAttribute="centerY" secondItem="L1E-7S-vyc" secondAttribute="centerY" id="yes-ws-bKG"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="AD4-YV-Ynz">
+                                        <rect key="frame" x="0.0" y="106" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="AD4-YV-Ynz" id="4qm-5A-q3C">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="fA9-kc-A2w">
+                                                    <rect key="frame" x="23" y="12" width="65" height="20.5"/>
+                                                    <subviews>
+                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Warning" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VZj-7h-puW">
+                                                            <rect key="frame" x="0.0" y="0.0" width="65" height="20.5"/>
+                                                            <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                            <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                            <nil key="highlightedColor"/>
+                                                        </label>
+                                                    </subviews>
+                                                </stackView>
+                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginSelected" translatesAutoresizingMaskIntoConstraints="NO" id="yJI-XU-Ken">
+                                                    <rect key="frame" x="338" y="15" width="14" height="14"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="height" constant="14" id="9aG-wb-OcZ"/>
+                                                        <constraint firstAttribute="width" constant="14" id="Lc4-CQ-dXe"/>
+                                                    </constraints>
+                                                </imageView>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="fA9-kc-A2w" firstAttribute="centerY" secondItem="4qm-5A-q3C" secondAttribute="centerY" id="AoO-PV-5M6"/>
+                                                <constraint firstItem="yJI-XU-Ken" firstAttribute="centerY" secondItem="4qm-5A-q3C" secondAttribute="centerY" id="XAn-2E-psQ"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="yJI-XU-Ken" secondAttribute="trailing" constant="7" id="c7N-I4-A1m"/>
+                                                <constraint firstItem="fA9-kc-A2w" firstAttribute="leading" secondItem="4qm-5A-q3C" secondAttribute="leadingMargin" constant="7" id="uoe-R5-Bhs"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="xUK-pv-SXi">
+                                        <rect key="frame" x="0.0" y="150" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="xUK-pv-SXi" id="l0W-t2-qFd">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Error" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bLR-Il-PfP">
+                                                    <rect key="frame" x="23" y="11.5" width="39" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginSelected" translatesAutoresizingMaskIntoConstraints="NO" id="VwM-Cg-1Ga">
+                                                    <rect key="frame" x="338" y="15" width="14" height="14"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="14" id="3b0-rD-mo0"/>
+                                                        <constraint firstAttribute="height" constant="14" id="vbF-wX-HPy"/>
+                                                    </constraints>
+                                                </imageView>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="VwM-Cg-1Ga" firstAttribute="centerY" secondItem="l0W-t2-qFd" secondAttribute="centerY" id="AAm-QQ-ytV"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="bLR-Il-PfP" secondAttribute="trailingMargin" id="HQ6-Zu-YbY"/>
+                                                <constraint firstItem="bLR-Il-PfP" firstAttribute="leading" secondItem="l0W-t2-qFd" secondAttribute="leadingMargin" constant="7" id="fww-Qz-HS2"/>
+                                                <constraint firstItem="bLR-Il-PfP" firstAttribute="centerY" secondItem="l0W-t2-qFd" secondAttribute="centerY" id="hYU-ZC-JDl"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="VwM-Cg-1Ga" secondAttribute="trailing" constant="7" id="lm5-4L-6a7"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                        </sections>
+                        <connections>
+                            <outlet property="dataSource" destination="d9b-zV-ilK" id="VCO-5I-etF"/>
+                            <outlet property="delegate" destination="d9b-zV-ilK" id="PHA-hb-Tya"/>
+                        </connections>
+                    </tableView>
+                    <navigationItem key="navigationItem" title="Log Level" id="X0g-6U-zwd"/>
+                    <connections>
+                        <outlet property="debugImageView" destination="1ay-Hu-rXk" id="IIp-mF-oaz"/>
+                        <outlet property="errorImageView" destination="VwM-Cg-1Ga" id="5m6-iU-9fa"/>
+                        <outlet property="infoImageView" destination="BjP-i8-8tR" id="1Xf-ra-8Lu"/>
+                        <outlet property="warnImageView" destination="yJI-XU-Ken" id="0vI-FQ-Hmg"/>
+                    </connections>
+                </tableViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="wGe-HE-oct" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="1924" y="-116.49175412293854"/>
+        </scene>
+        <!--Gateway-->
+        <scene sceneID="tne-QT-ifu">
+            <objects>
+                <viewController id="BYZ-38-t0r" customClass="GatewayViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
+                        <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <pageControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" numberOfPages="3" translatesAutoresizingMaskIntoConstraints="NO" id="mwE-yG-bSp">
+                                <rect key="frame" x="126.5" y="546.5" width="122.5" height="27.5"/>
+                            </pageControl>
+                            <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="fg1-cd-yLy">
+                                <rect key="frame" x="0.0" y="45" width="375" height="493.5"/>
+                                <color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="pW1-0w-lFs">
+                                    <size key="itemSize" width="50" height="50"/>
+                                    <size key="headerReferenceSize" width="0.0" height="0.0"/>
+                                    <size key="footerReferenceSize" width="0.0" height="0.0"/>
+                                    <inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                </collectionViewFlowLayout>
+                                <cells/>
+                                <connections>
+                                    <outlet property="dataSource" destination="BYZ-38-t0r" id="ECu-vD-skG"/>
+                                    <outlet property="delegate" destination="BYZ-38-t0r" id="ksO-KQ-AU1"/>
+                                </connections>
+                            </collectionView>
+                        </subviews>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <constraints>
+                            <constraint firstItem="mwE-yG-bSp" firstAttribute="top" secondItem="fg1-cd-yLy" secondAttribute="bottom" constant="8" id="C9M-rf-249"/>
+                            <constraint firstItem="fg1-cd-yLy" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="NGt-u6-dC6"/>
+                            <constraint firstItem="mwE-yG-bSp" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="NYa-Em-5f3"/>
+                            <constraint firstAttribute="trailing" secondItem="fg1-cd-yLy" secondAttribute="trailing" id="nTs-JZ-bmk"/>
+                            <constraint firstItem="wfy-db-euE" firstAttribute="top" secondItem="mwE-yG-bSp" secondAttribute="bottom" constant="49" id="qei-ed-2w6"/>
+                            <constraint firstItem="fg1-cd-yLy" firstAttribute="top" secondItem="y3c-jy-aDJ" secondAttribute="bottom" constant="45" id="z3E-39-gb1"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" title="Gateway" id="ZG6-h2-0de">
+                        <rightBarButtonItems>
+                            <barButtonItem image="GatewayItemMore" id="KRr-gB-RmH">
+                                <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            </barButtonItem>
+                            <barButtonItem image="GatewayItemAdd" id="zmx-jG-321">
+                                <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            </barButtonItem>
+                        </rightBarButtonItems>
+                    </navigationItem>
+                    <connections>
+                        <outlet property="addGatewayButton" destination="zmx-jG-321" id="ziN-t7-mcd"/>
+                        <outlet property="collectionView" destination="fg1-cd-yLy" id="CbQ-e1-fFl"/>
+                        <outlet property="moreButton" destination="KRr-gB-RmH" id="sqc-hK-arP"/>
+                        <outlet property="pageControl" destination="mwE-yG-bSp" id="LIY-gJ-Zqj"/>
+                        <segue destination="LP6-tU-vWi" kind="presentation" identifier="GatewayToSettings" modalPresentationStyle="fullScreen" id="LDy-gx-0Ka"/>
+                        <segue destination="nnp-7I-qjc" kind="presentation" identifier="GatewayToLogin" modalPresentationStyle="fullScreen" id="mxa-fV-Mab"/>
+                        <segue destination="LZd-Ei-vmr" kind="presentation" identifier="GatewayToResource" modalPresentationStyle="fullScreen" id="2v7-vL-Q1V"/>
+                        <segue destination="fhm-J3-Mni" kind="show" identifier="GatewayToLogSettings" id="Ul7-yp-Smk"/>
+                        <segue destination="mDt-jA-kKK" kind="show" identifier="GatewayToAbout" id="Cre-3M-bGE"/>
+                        <segue destination="AQs-MT-X4V" kind="presentation" identifier="GatewayToWebAuth" modalPresentationStyle="fullScreen" id="ES7-sm-Mde"/>
+                        <segue destination="Qv9-5w-hBC" kind="show" identifier="LoginToChallenge" id="xSQ-ko-f4a"/>
+                        <segue destination="MGw-hc-Bqe" kind="show" identifier="LoginToChangePassword" id="iir-Mp-9Rd"/>
+                        <segue destination="axh-t8-XkJ" kind="show" identifier="LoginToSMS" id="bRA-r2-9bC"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="1013.6" y="689.5052473763119"/>
+        </scene>
+        <!--GatewaySettingsViewController-->
+        <scene sceneID="gfw-gV-BAU">
+            <objects>
+                <tableViewController title="GatewaySettingsViewController" id="XsL-WP-fGg" customClass="GatewaySettingsViewController" sceneMemberID="viewController">
+                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" bounces="NO" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="15" sectionFooterHeight="1" id="y11-ii-gOR">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="calibratedRGB"/>
+                        <color key="separatorColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="calibratedRGB"/>
+                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                        <sections>
+                            <tableViewSection id="NvI-RD-qCm">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="Nle-U0-aG9">
+                                        <rect key="frame" x="0.0" y="15" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Nle-U0-aG9" id="WIf-cx-jpE">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="right" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="DM1-M4-GJ6">
+                                                    <rect key="frame" x="65.5" y="0.0" width="294.5" height="44"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <textInputTraits key="textInputTraits" returnKeyType="next"/>
+                                                    <connections>
+                                                        <outlet property="delegate" destination="XsL-WP-fGg" id="bn0-5u-yVR"/>
+                                                    </connections>
+                                                </textField>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="1000" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="imK-Z9-nrn">
+                                                    <rect key="frame" x="23" y="11.5" width="34.5" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="DM1-M4-GJ6" firstAttribute="leading" secondItem="imK-Z9-nrn" secondAttribute="trailing" constant="8" id="Bhl-f3-XvW"/>
+                                                <constraint firstItem="imK-Z9-nrn" firstAttribute="leading" secondItem="WIf-cx-jpE" secondAttribute="leadingMargin" constant="7" id="H5k-gc-MCR"/>
+                                                <constraint firstAttribute="trailing" secondItem="DM1-M4-GJ6" secondAttribute="trailing" constant="15" id="IdM-tA-2CB"/>
+                                                <constraint firstItem="imK-Z9-nrn" firstAttribute="centerY" secondItem="WIf-cx-jpE" secondAttribute="centerY" id="MuH-JA-dF8"/>
+                                                <constraint firstAttribute="bottom" secondItem="DM1-M4-GJ6" secondAttribute="bottom" id="T3y-Wu-8zB"/>
+                                                <constraint firstItem="DM1-M4-GJ6" firstAttribute="top" secondItem="WIf-cx-jpE" secondAttribute="top" id="sUP-CB-PyF"/>
+                                                <constraint firstItem="DM1-M4-GJ6" firstAttribute="centerY" secondItem="WIf-cx-jpE" secondAttribute="centerY" id="uKl-kr-pLe"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="Ac8-m4-rin">
+                                        <rect key="frame" x="0.0" y="59" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Ac8-m4-rin" id="oo1-HA-eIT">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Gateway" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="CDP-Hx-Q1x">
+                                                    <rect key="frame" x="23" y="11.5" width="68" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="right" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="ih1-uB-gvq">
+                                                    <rect key="frame" x="99" y="0.0" width="261" height="44"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <textInputTraits key="textInputTraits" returnKeyType="next"/>
+                                                    <connections>
+                                                        <outlet property="delegate" destination="XsL-WP-fGg" id="r2m-qS-BQQ"/>
+                                                    </connections>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="ih1-uB-gvq" firstAttribute="leading" secondItem="CDP-Hx-Q1x" secondAttribute="trailing" constant="8" id="012-r5-g4H"/>
+                                                <constraint firstItem="ih1-uB-gvq" firstAttribute="top" secondItem="oo1-HA-eIT" secondAttribute="top" id="6ym-fX-AyR"/>
+                                                <constraint firstAttribute="bottom" secondItem="ih1-uB-gvq" secondAttribute="bottom" id="DOg-V3-r1x"/>
+                                                <constraint firstAttribute="trailing" secondItem="ih1-uB-gvq" secondAttribute="trailing" constant="15" id="FS1-n5-aTx"/>
+                                                <constraint firstItem="CDP-Hx-Q1x" firstAttribute="leading" secondItem="oo1-HA-eIT" secondAttribute="leadingMargin" constant="7" id="Suh-0S-0EX"/>
+                                                <constraint firstItem="CDP-Hx-Q1x" firstAttribute="centerY" secondItem="oo1-HA-eIT" secondAttribute="centerY" id="VAJ-a4-n0U"/>
+                                                <constraint firstItem="ih1-uB-gvq" firstAttribute="centerY" secondItem="oo1-HA-eIT" secondAttribute="centerY" id="b4X-IQ-gzy"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="dBG-TA-7PV">
+                                        <rect key="frame" x="0.0" y="103" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="dBG-TA-7PV" id="zJI-zU-MPb">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Username" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eAY-Im-Jhi">
+                                                    <rect key="frame" x="23" y="11.5" width="80.5" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="right" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="Wo1-jU-MJP">
+                                                    <rect key="frame" x="111.5" y="0.0" width="248.5" height="44"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <textInputTraits key="textInputTraits" returnKeyType="next"/>
+                                                    <connections>
+                                                        <outlet property="delegate" destination="XsL-WP-fGg" id="L1X-e3-65a"/>
+                                                    </connections>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="Wo1-jU-MJP" firstAttribute="leading" secondItem="eAY-Im-Jhi" secondAttribute="trailing" constant="8" id="5WR-5P-X2G"/>
+                                                <constraint firstAttribute="trailing" secondItem="Wo1-jU-MJP" secondAttribute="trailing" constant="15" id="KE8-Eu-gYA"/>
+                                                <constraint firstAttribute="bottom" secondItem="Wo1-jU-MJP" secondAttribute="bottom" id="Lw4-C5-7wb"/>
+                                                <constraint firstItem="eAY-Im-Jhi" firstAttribute="centerY" secondItem="zJI-zU-MPb" secondAttribute="centerY" id="Uq5-WN-rHs"/>
+                                                <constraint firstItem="eAY-Im-Jhi" firstAttribute="leading" secondItem="zJI-zU-MPb" secondAttribute="leadingMargin" constant="7" id="XR0-Ek-ypL"/>
+                                                <constraint firstItem="Wo1-jU-MJP" firstAttribute="top" secondItem="zJI-zU-MPb" secondAttribute="top" id="afB-ZI-1Ae"/>
+                                                <constraint firstItem="Wo1-jU-MJP" firstAttribute="centerY" secondItem="zJI-zU-MPb" secondAttribute="centerY" id="wvB-lx-LYs"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="ujt-ww-Fhf">
+                                        <rect key="frame" x="0.0" y="147" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ujt-ww-Fhf" id="GaZ-1l-iKS">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Port" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OvA-2F-uTb">
+                                                    <rect key="frame" x="23" y="11.5" width="33.5" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="443" textAlignment="right" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="Pmm-6N-Veq">
+                                                    <rect key="frame" x="64.5" y="0.0" width="295.5" height="44"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <textInputTraits key="textInputTraits" returnKeyType="next"/>
+                                                    <connections>
+                                                        <outlet property="delegate" destination="XsL-WP-fGg" id="1jx-5V-egx"/>
+                                                    </connections>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="Pmm-6N-Veq" firstAttribute="top" secondItem="GaZ-1l-iKS" secondAttribute="top" id="14C-sr-uLo"/>
+                                                <constraint firstItem="Pmm-6N-Veq" firstAttribute="centerY" secondItem="GaZ-1l-iKS" secondAttribute="centerY" id="4oO-r7-4Is"/>
+                                                <constraint firstAttribute="trailing" secondItem="Pmm-6N-Veq" secondAttribute="trailing" constant="15" id="JjM-Pl-KQa"/>
+                                                <constraint firstItem="OvA-2F-uTb" firstAttribute="leading" secondItem="GaZ-1l-iKS" secondAttribute="leadingMargin" constant="7" id="aqZ-qW-bI4"/>
+                                                <constraint firstAttribute="bottom" secondItem="Pmm-6N-Veq" secondAttribute="bottom" id="ge2-wq-eXb"/>
+                                                <constraint firstItem="Pmm-6N-Veq" firstAttribute="leading" secondItem="OvA-2F-uTb" secondAttribute="trailing" constant="8" id="jc8-MP-e0S"/>
+                                                <constraint firstItem="OvA-2F-uTb" firstAttribute="centerY" secondItem="GaZ-1l-iKS" secondAttribute="centerY" id="wNL-bv-a5C"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="uVr-lX-t6T">
+                                        <rect key="frame" x="0.0" y="191" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="uVr-lX-t6T" id="bDL-ff-tsO">
+                                            <rect key="frame" x="0.0" y="0.0" width="348" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Certificate" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Icn-qp-fkF">
+                                                    <rect key="frame" x="23" y="11.5" width="83" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fdn-RX-tgS">
+                                                    <rect key="frame" x="220" y="22" width="120" height="0.0"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="120" id="Kr0-Tf-SdA"/>
+                                                    </constraints>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="fdn-RX-tgS" firstAttribute="trailing" secondItem="bDL-ff-tsO" secondAttribute="trailingMargin" id="4Cg-5r-HiZ"/>
+                                                <constraint firstItem="fdn-RX-tgS" firstAttribute="centerY" secondItem="bDL-ff-tsO" secondAttribute="centerY" id="A34-mf-syj"/>
+                                                <constraint firstItem="Icn-qp-fkF" firstAttribute="centerY" secondItem="bDL-ff-tsO" secondAttribute="centerY" id="RUD-BX-7j0"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="Icn-qp-fkF" secondAttribute="trailingMargin" id="cpa-yV-EWg"/>
+                                                <constraint firstItem="Icn-qp-fkF" firstAttribute="leading" secondItem="bDL-ff-tsO" secondAttribute="leadingMargin" constant="7" id="d8S-Ke-Nu2"/>
+                                                <constraint firstItem="fdn-RX-tgS" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="bDL-ff-tsO" secondAttribute="leadingMargin" id="eEY-gY-qrt"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                            <tableViewSection id="1Jk-Fx-ZsE">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="owE-rV-dI2">
+                                        <rect key="frame" x="0.0" y="251" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="owE-rV-dI2" id="nWr-Y8-p8j">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Enable Secure Tunnel" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="96T-X7-oAM">
+                                                    <rect key="frame" x="23" y="11.5" width="169" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Xds-Qx-gOv">
+                                                    <rect key="frame" x="311" y="6.5" width="51" height="31"/>
+                                                </switch>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="96T-X7-oAM" secondAttribute="trailingMargin" id="0cA-cd-IJP"/>
+                                                <constraint firstItem="96T-X7-oAM" firstAttribute="centerY" secondItem="nWr-Y8-p8j" secondAttribute="centerY" id="KHV-Wa-Eqr"/>
+                                                <constraint firstItem="Xds-Qx-gOv" firstAttribute="centerY" secondItem="nWr-Y8-p8j" secondAttribute="centerY" id="ORV-HF-OlT"/>
+                                                <constraint firstItem="96T-X7-oAM" firstAttribute="leading" secondItem="nWr-Y8-p8j" secondAttribute="leadingMargin" constant="7" id="uXl-cq-lkw"/>
+                                                <constraint firstAttribute="trailing" secondItem="Xds-Qx-gOv" secondAttribute="trailing" constant="15" id="v6u-Pu-gNl"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="Nse-L7-SKx">
+                                        <rect key="frame" x="0.0" y="295" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Nse-L7-SKx" id="0g0-ig-6AT">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Save Password" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sbQ-bg-DE3">
+                                                    <rect key="frame" x="23" y="11.5" width="118" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="DQb-pJ-7b1">
+                                                    <rect key="frame" x="311" y="6.5" width="51" height="31"/>
+                                                    <connections>
+                                                        <action selector="savePasswordSwitched:" destination="XsL-WP-fGg" eventType="valueChanged" id="u04-3J-6nI"/>
+                                                    </connections>
+                                                </switch>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="DQb-pJ-7b1" firstAttribute="centerY" secondItem="0g0-ig-6AT" secondAttribute="centerY" id="13L-vF-FMq"/>
+                                                <constraint firstAttribute="trailing" secondItem="DQb-pJ-7b1" secondAttribute="trailing" constant="15" id="3KS-Oj-dJB"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="sbQ-bg-DE3" secondAttribute="trailingMargin" id="NIa-5V-2pI"/>
+                                                <constraint firstItem="sbQ-bg-DE3" firstAttribute="leading" secondItem="0g0-ig-6AT" secondAttribute="leadingMargin" constant="7" id="QLK-L2-70a"/>
+                                                <constraint firstItem="sbQ-bg-DE3" firstAttribute="centerY" secondItem="0g0-ig-6AT" secondAttribute="centerY" id="a9I-Qe-JGO"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="JaO-ND-HoQ">
+                                        <rect key="frame" x="0.0" y="339" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="JaO-ND-HoQ" id="4SZ-I7-kRU">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Show Login Dialog" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8qU-Mv-Wgb">
+                                                    <rect key="frame" x="23" y="11.5" width="144" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="VMt-Fa-LDJ">
+                                                    <rect key="frame" x="311" y="6.5" width="51" height="31"/>
+                                                </switch>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="VMt-Fa-LDJ" firstAttribute="centerY" secondItem="4SZ-I7-kRU" secondAttribute="centerY" id="9t0-0B-gIg"/>
+                                                <constraint firstAttribute="trailing" secondItem="VMt-Fa-LDJ" secondAttribute="trailing" constant="15" id="DZa-3U-DkU"/>
+                                                <constraint firstItem="8qU-Mv-Wgb" firstAttribute="centerY" secondItem="4SZ-I7-kRU" secondAttribute="centerY" id="Gjf-SR-jNh"/>
+                                                <constraint firstItem="8qU-Mv-Wgb" firstAttribute="leading" secondItem="4SZ-I7-kRU" secondAttribute="leadingMargin" constant="7" id="WLD-9J-He2"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="8qU-Mv-Wgb" secondAttribute="trailingMargin" id="oPU-R5-Jvl"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="5Hy-9R-m62">
+                                        <rect key="frame" x="0.0" y="383" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="5Hy-9R-m62" id="70z-38-z3w">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Enable Web SSO" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gJ3-Oy-fYa">
+                                                    <rect key="frame" x="23" y="11.5" width="131" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="hFW-eO-lIL">
+                                                    <rect key="frame" x="311" y="6.5" width="51" height="31"/>
+                                                </switch>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="trailing" secondItem="hFW-eO-lIL" secondAttribute="trailing" constant="15" id="NiJ-9i-jxI"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="gJ3-Oy-fYa" secondAttribute="trailingMargin" id="OXX-zl-Scr"/>
+                                                <constraint firstItem="hFW-eO-lIL" firstAttribute="centerY" secondItem="70z-38-z3w" secondAttribute="centerY" id="XCd-9N-wR2"/>
+                                                <constraint firstItem="gJ3-Oy-fYa" firstAttribute="centerY" secondItem="70z-38-z3w" secondAttribute="centerY" id="hN1-OW-lKC"/>
+                                                <constraint firstItem="gJ3-Oy-fYa" firstAttribute="leading" secondItem="70z-38-z3w" secondAttribute="leadingMargin" constant="7" id="xaw-MA-3Mu"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="5QK-8c-cDU">
+                                        <rect key="frame" x="0.0" y="427" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="5QK-8c-cDU" id="mO4-r1-ygQ">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Enable WebAuth" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wea-au-VtG">
+                                                    <rect key="frame" x="23" y="11.5" width="129" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="yaV-d9-dhg">
+                                                    <rect key="frame" x="311" y="6.5" width="51" height="31"/>
+                                                </switch>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="wea-au-VtG" firstAttribute="leading" secondItem="mO4-r1-ygQ" secondAttribute="leadingMargin" constant="7" id="01Z-tc-PWU"/>
+                                                <constraint firstAttribute="trailing" secondItem="yaV-d9-dhg" secondAttribute="trailing" constant="15" id="4jr-md-A8n"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="wea-au-VtG" secondAttribute="trailingMargin" id="JtY-SE-v7k"/>
+                                                <constraint firstItem="wea-au-VtG" firstAttribute="centerY" secondItem="mO4-r1-ygQ" secondAttribute="centerY" id="YQn-f4-kPg"/>
+                                                <constraint firstItem="yaV-d9-dhg" firstAttribute="centerY" secondItem="mO4-r1-ygQ" secondAttribute="centerY" id="kY5-wJ-S1C"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                            <tableViewSection id="5jR-Lb-3fv">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="FuL-oC-auO">
+                                        <rect key="frame" x="0.0" y="487" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="FuL-oC-auO" id="Pui-Mn-Fr1">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="SyferLock Authentication" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wym-Rd-iq1">
+                                                    <rect key="frame" x="23" y="11.5" width="197" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="mS8-5h-yHM">
+                                                    <rect key="frame" x="311" y="6.5" width="51" height="31"/>
+                                                </switch>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="wym-Rd-iq1" firstAttribute="centerY" secondItem="Pui-Mn-Fr1" secondAttribute="centerY" id="XyL-ky-7KZ"/>
+                                                <constraint firstAttribute="trailing" secondItem="mS8-5h-yHM" secondAttribute="trailing" constant="15" id="bGK-Ut-j4F"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="wym-Rd-iq1" secondAttribute="trailingMargin" id="kTg-Z0-e6s"/>
+                                                <constraint firstItem="mS8-5h-yHM" firstAttribute="centerY" secondItem="Pui-Mn-Fr1" secondAttribute="centerY" id="w6A-1J-6mI"/>
+                                                <constraint firstItem="wym-Rd-iq1" firstAttribute="leading" secondItem="Pui-Mn-Fr1" secondAttribute="leadingMargin" constant="7" id="zld-tq-J6T"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                        </sections>
+                        <connections>
+                            <outlet property="dataSource" destination="XsL-WP-fGg" id="1d5-zs-e3T"/>
+                            <outlet property="delegate" destination="XsL-WP-fGg" id="19a-tO-de5"/>
+                        </connections>
+                    </tableView>
+                    <navigationItem key="navigationItem" title="Gateway" id="WG0-kd-ZSL">
+                        <barButtonItem key="leftBarButtonItem" title="Cancel" id="5dD-Oo-s8d">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            <connections>
+                                <action selector="cancelButtonClicked:" destination="XsL-WP-fGg" id="akT-WQ-jcr"/>
+                            </connections>
+                        </barButtonItem>
+                        <barButtonItem key="rightBarButtonItem" title="Save" id="Hle-HP-ZfN">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            <connections>
+                                <action selector="saveButtonClicked:" destination="XsL-WP-fGg" id="mtr-Sb-mXe"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                    <connections>
+                        <outlet property="certNameLabel" destination="fdn-RX-tgS" id="UNf-TJ-gy6"/>
+                        <outlet property="enableSecureTunnelSwitch" destination="Xds-Qx-gOv" id="4DY-vR-HFf"/>
+                        <outlet property="enableWebAuthSwitch" destination="yaV-d9-dhg" id="WZq-8I-z6g"/>
+                        <outlet property="enableWebSSOSwitch" destination="hFW-eO-lIL" id="kes-CB-Lj4"/>
+                        <outlet property="gatewayTextField" destination="ih1-uB-gvq" id="x4l-hH-wRb"/>
+                        <outlet property="portTextField" destination="Pmm-6N-Veq" id="Q0k-Tm-8Ed"/>
+                        <outlet property="savePasswordSwitch" destination="DQb-pJ-7b1" id="KKP-9M-JKV"/>
+                        <outlet property="showLoginDialogSwitch" destination="VMt-Fa-LDJ" id="263-78-bGd"/>
+                        <outlet property="syferlockAuthSwitch" destination="mS8-5h-yHM" id="Ibk-hj-uAP"/>
+                        <outlet property="titleTextField" destination="DM1-M4-GJ6" id="Hf4-UI-jSQ"/>
+                        <outlet property="usernameTextField" destination="Wo1-jU-MJP" id="i3q-xf-vek"/>
+                        <segue destination="kQL-Cp-vCp" kind="show" identifier="GatewaySettingsToCertificates" id="dwI-hk-mt6"/>
+                        <segue destination="l9d-Rt-vCd" kind="show" identifier="GatewaySettingsToInstallCertificate" id="bpD-LK-kUE"/>
+                    </connections>
+                </tableViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="fa1-2L-7U9" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="2792.8000000000002" y="689.5052473763119"/>
+        </scene>
+        <!--Certificates-->
+        <scene sceneID="2oM-db-nzH">
+            <objects>
+                <tableViewController storyboardIdentifier="CertificateViewControllerID" modalPresentationStyle="fullScreen" id="kQL-Cp-vCp" customClass="CertificatesViewController" sceneMemberID="viewController">
+                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" allowsSelection="NO" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="GoU-Ly-mPU">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="calibratedRGB"/>
+                        <color key="separatorColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="calibratedRGB"/>
+                        <inset key="separatorInset" minX="40" minY="0.0" maxX="0.0" maxY="0.0"/>
+                        <prototypes>
+                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="CertificateNameID" id="TE0-lz-m2p" customClass="CertificateNameCell">
+                                <rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
+                                <autoresizingMask key="autoresizingMask"/>
+                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="TE0-lz-m2p" id="IMh-6R-E7p">
+                                    <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                    <autoresizingMask key="autoresizingMask"/>
+                                    <subviews>
+                                        <button opaque="NO" tag="2" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kQf-vV-n7A" customClass="ANImageButton">
+                                            <rect key="frame" x="338" y="15" width="14" height="14"/>
+                                            <constraints>
+                                                <constraint firstAttribute="width" constant="14" id="AkZ-sR-ssc"/>
+                                                <constraint firstAttribute="height" constant="14" id="Bkh-sL-TqA"/>
+                                            </constraints>
+                                            <state key="normal" title="Button" image="CertificateDelete">
+                                                <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                            </state>
+                                            <connections>
+                                                <action selector="deleteButtonClicked:" destination="TE0-lz-m2p" eventType="touchUpInside" id="kUS-hv-d26"/>
+                                            </connections>
+                                        </button>
+                                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="r21-cF-CVj" customClass="ANImageButton">
+                                            <rect key="frame" x="18" y="11" width="22" height="22"/>
+                                            <constraints>
+                                                <constraint firstAttribute="height" constant="22" id="Gar-w6-io5"/>
+                                                <constraint firstAttribute="width" constant="22" id="nSn-HD-Oz7"/>
+                                            </constraints>
+                                            <state key="normal" image="CertificateUnselected"/>
+                                            <connections>
+                                                <action selector="selecteButtonClicked:" destination="TE0-lz-m2p" eventType="touchUpInside" id="Nd1-Jr-gOC"/>
+                                            </connections>
+                                        </button>
+                                        <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wrc-lZ-DBp">
+                                            <rect key="frame" x="48" y="12.5" width="46" height="21"/>
+                                            <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                            <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                            <nil key="highlightedColor"/>
+                                        </label>
+                                    </subviews>
+                                    <constraints>
+                                        <constraint firstItem="wrc-lZ-DBp" firstAttribute="centerY" secondItem="IMh-6R-E7p" secondAttribute="centerY" constant="1" id="7ly-MO-ceF"/>
+                                        <constraint firstItem="kQf-vV-n7A" firstAttribute="centerY" secondItem="IMh-6R-E7p" secondAttribute="centerY" id="BxA-23-FCN"/>
+                                        <constraint firstItem="kQf-vV-n7A" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="IMh-6R-E7p" secondAttribute="leadingMargin" id="DQ2-oe-HMG"/>
+                                        <constraint firstAttribute="trailingMargin" secondItem="kQf-vV-n7A" secondAttribute="trailing" constant="7" id="Kg3-RE-kZN"/>
+                                        <constraint firstItem="r21-cF-CVj" firstAttribute="leading" secondItem="IMh-6R-E7p" secondAttribute="leadingMargin" constant="2" id="OeM-1d-D1N"/>
+                                        <constraint firstItem="wrc-lZ-DBp" firstAttribute="leading" secondItem="r21-cF-CVj" secondAttribute="trailing" constant="8" id="RAr-41-Xq4"/>
+                                        <constraint firstItem="r21-cF-CVj" firstAttribute="centerY" secondItem="IMh-6R-E7p" secondAttribute="centerY" id="XnB-pO-qnB"/>
+                                        <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="wrc-lZ-DBp" secondAttribute="trailing" constant="20" symbolic="YES" id="bcu-nS-qmL"/>
+                                    </constraints>
+                                </tableViewCellContentView>
+                                <color key="backgroundColor" systemColor="tableCellGroupedBackgroundColor"/>
+                                <connections>
+                                    <outlet property="deleteButton" destination="kQf-vV-n7A" id="c2o-wD-HFI"/>
+                                    <outlet property="nameLabel" destination="wrc-lZ-DBp" id="buX-EG-VDB"/>
+                                    <outlet property="selectButton" destination="r21-cF-CVj" id="vVC-AA-5M7"/>
+                                </connections>
+                            </tableViewCell>
+                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="CertificateSubjectID" id="CJX-bt-rbE">
+                                <rect key="frame" x="0.0" y="99.5" width="375" height="44"/>
+                                <autoresizingMask key="autoresizingMask"/>
+                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="CJX-bt-rbE" id="3nQ-Ed-66T">
+                                    <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                    <autoresizingMask key="autoresizingMask"/>
+                                    <subviews>
+                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Subject" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SI4-0H-aeD">
+                                            <rect key="frame" x="48" y="11.5" width="58" height="21"/>
+                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                            <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                            <nil key="highlightedColor"/>
+                                        </label>
+                                        <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="&lt;subject&gt;" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fdz-NZ-lcr">
+                                            <rect key="frame" x="275" y="11.5" width="77" height="21"/>
+                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                            <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                            <nil key="highlightedColor"/>
+                                        </label>
+                                    </subviews>
+                                    <constraints>
+                                        <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="SI4-0H-aeD" secondAttribute="trailingMargin" id="UCP-Zz-nnZ"/>
+                                        <constraint firstAttribute="trailingMargin" secondItem="fdz-NZ-lcr" secondAttribute="trailing" constant="7" id="YGX-VK-xbn"/>
+                                        <constraint firstItem="fdz-NZ-lcr" firstAttribute="centerY" secondItem="3nQ-Ed-66T" secondAttribute="centerY" id="e02-f3-rbd"/>
+                                        <constraint firstItem="SI4-0H-aeD" firstAttribute="centerY" secondItem="3nQ-Ed-66T" secondAttribute="centerY" id="jM5-Zh-nD4"/>
+                                        <constraint firstItem="SI4-0H-aeD" firstAttribute="leading" secondItem="3nQ-Ed-66T" secondAttribute="leadingMargin" constant="32" id="q9h-7y-F83"/>
+                                        <constraint firstItem="fdz-NZ-lcr" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="3nQ-Ed-66T" secondAttribute="leadingMargin" id="vKQ-dh-yrM"/>
+                                    </constraints>
+                                </tableViewCellContentView>
+                                <color key="backgroundColor" systemColor="tableCellGroupedBackgroundColor"/>
+                            </tableViewCell>
+                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="CertificateIssuerID" id="Lcc-N2-VRt">
+                                <rect key="frame" x="0.0" y="143.5" width="375" height="44"/>
+                                <autoresizingMask key="autoresizingMask"/>
+                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Lcc-N2-VRt" id="Zs6-9V-VLy">
+                                    <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                    <autoresizingMask key="autoresizingMask"/>
+                                    <subviews>
+                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Issued by" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zn0-OY-lhN">
+                                            <rect key="frame" x="48" y="11.5" width="73" height="21"/>
+                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                            <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                            <nil key="highlightedColor"/>
+                                        </label>
+                                        <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="&lt;issuer&gt;" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lg2-Oh-23a">
+                                            <rect key="frame" x="286" y="11.5" width="66" height="21"/>
+                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                            <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                            <nil key="highlightedColor"/>
+                                        </label>
+                                    </subviews>
+                                    <constraints>
+                                        <constraint firstItem="lg2-Oh-23a" firstAttribute="centerY" secondItem="Zs6-9V-VLy" secondAttribute="centerY" id="3Ix-yh-M5h"/>
+                                        <constraint firstAttribute="trailingMargin" secondItem="lg2-Oh-23a" secondAttribute="trailing" constant="7" id="5zo-hp-HWT"/>
+                                        <constraint firstItem="zn0-OY-lhN" firstAttribute="leading" secondItem="Zs6-9V-VLy" secondAttribute="leadingMargin" constant="32" id="WBF-Jd-ete"/>
+                                        <constraint firstItem="lg2-Oh-23a" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Zs6-9V-VLy" secondAttribute="leadingMargin" id="hYH-6i-W3c"/>
+                                        <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="zn0-OY-lhN" secondAttribute="trailingMargin" id="iIG-fc-eBE"/>
+                                        <constraint firstItem="zn0-OY-lhN" firstAttribute="centerY" secondItem="Zs6-9V-VLy" secondAttribute="centerY" id="uYv-Nt-zw7"/>
+                                    </constraints>
+                                </tableViewCellContentView>
+                                <color key="backgroundColor" systemColor="tableCellGroupedBackgroundColor"/>
+                            </tableViewCell>
+                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="CertificateExpireID" id="Yyt-Ju-TMm">
+                                <rect key="frame" x="0.0" y="187.5" width="375" height="44"/>
+                                <autoresizingMask key="autoresizingMask"/>
+                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Yyt-Ju-TMm" id="E09-vo-lio">
+                                    <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                    <autoresizingMask key="autoresizingMask"/>
+                                    <subviews>
+                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Expires" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pxh-Lt-m9c">
+                                            <rect key="frame" x="48" y="11.5" width="56" height="21"/>
+                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                            <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                            <nil key="highlightedColor"/>
+                                        </label>
+                                        <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="&lt;time&gt;" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uj8-n9-k7D">
+                                            <rect key="frame" x="298" y="11.5" width="54" height="21"/>
+                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                            <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                            <nil key="highlightedColor"/>
+                                        </label>
+                                    </subviews>
+                                    <constraints>
+                                        <constraint firstItem="pxh-Lt-m9c" firstAttribute="leading" secondItem="E09-vo-lio" secondAttribute="leadingMargin" constant="32" id="4aK-C0-70z"/>
+                                        <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="pxh-Lt-m9c" secondAttribute="trailingMargin" id="6CP-qv-w1d"/>
+                                        <constraint firstItem="uj8-n9-k7D" firstAttribute="centerY" secondItem="E09-vo-lio" secondAttribute="centerY" id="MGc-L1-YW8"/>
+                                        <constraint firstItem="uj8-n9-k7D" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="E09-vo-lio" secondAttribute="leadingMargin" id="NFl-ag-x9I"/>
+                                        <constraint firstAttribute="trailingMargin" secondItem="uj8-n9-k7D" secondAttribute="trailing" constant="7" id="evq-jR-RkP"/>
+                                        <constraint firstItem="pxh-Lt-m9c" firstAttribute="centerY" secondItem="E09-vo-lio" secondAttribute="centerY" id="sO5-Dw-eik"/>
+                                    </constraints>
+                                </tableViewCellContentView>
+                                <color key="backgroundColor" systemColor="tableCellGroupedBackgroundColor"/>
+                            </tableViewCell>
+                        </prototypes>
+                        <connections>
+                            <outlet property="dataSource" destination="kQL-Cp-vCp" id="9QL-T1-JeR"/>
+                            <outlet property="delegate" destination="kQL-Cp-vCp" id="tU8-KO-Iem"/>
+                        </connections>
+                    </tableView>
+                    <navigationItem key="navigationItem" title="Certificates" id="3s4-cm-cci">
+                        <barButtonItem key="rightBarButtonItem" systemItem="add" id="zGS-SE-sa8">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            <connections>
+                                <segue destination="l9d-Rt-vCd" kind="presentation" modalPresentationStyle="fullScreen" id="4WH-pD-NYb"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                </tableViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="jRg-da-dNl" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="3665" y="690"/>
+        </scene>
+        <!--Certificate-->
+        <scene sceneID="6Tc-Pi-DBe">
+            <objects>
+                <viewController modalPresentationStyle="fullScreen" id="ge6-AP-0um" customClass="CertificateInstallViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="JbV-43-RVv"/>
+                        <viewControllerLayoutGuide type="bottom" id="vta-U8-txv"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="4fd-Yp-3nJ">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Arr-MX-tZv" customClass="ANImageButton">
+                                <rect key="frame" x="18" y="20" width="22" height="22"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="22" id="hjR-f0-dbl"/>
+                                    <constraint firstAttribute="width" constant="22" id="wI7-Wa-Cce"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="18"/>
+                                <state key="normal" image="CertificateUnselected"/>
+                                <connections>
+                                    <action selector="urlSelecteButtonClicked:" destination="ge6-AP-0um" eventType="touchUpInside" id="Qlh-bl-xhg"/>
+                                </connections>
+                            </button>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="URL" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lXS-nR-USh">
+                                <rect key="frame" x="48" y="21.5" width="33" height="21"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="21" id="ZZ9-OX-KE8"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="nLW-cz-kvJ" customClass="ANImageButton">
+                                <rect key="frame" x="18" y="190" width="22" height="22"/>
+                                <constraints>
+                                    <constraint firstAttribute="width" constant="22" id="P43-iD-3l0"/>
+                                    <constraint firstAttribute="height" constant="22" id="n7Z-lB-FN5"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="18"/>
+                                <state key="normal" image="CertificateUnselected"/>
+                                <connections>
+                                    <action selector="localSelecteButtonClicked:" destination="ge6-AP-0um" eventType="touchUpInside" id="lh7-bx-8xR"/>
+                                </connections>
+                            </button>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Local Certificate" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hly-Eq-Kfh">
+                                <rect key="frame" x="48" y="191.5" width="128" height="21"/>
+                                <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="oTL-pD-XOH">
+                                <rect key="frame" x="15" y="50" width="345" height="44"/>
+                                <subviews>
+                                    <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="http:// or ftp://" textAlignment="natural" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="FJA-EM-1G3">
+                                        <rect key="frame" x="15" y="0.0" width="315" height="44"/>
+                                        <constraints>
+                                            <constraint firstAttribute="height" constant="44" id="mR2-lu-r0L"/>
+                                        </constraints>
+                                        <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                        <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                        <textInputTraits key="textInputTraits"/>
+                                    </textField>
+                                </subviews>
+                                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                <constraints>
+                                    <constraint firstAttribute="trailing" secondItem="FJA-EM-1G3" secondAttribute="trailing" constant="15" id="Ahr-gh-fzR"/>
+                                    <constraint firstItem="FJA-EM-1G3" firstAttribute="centerY" secondItem="oTL-pD-XOH" secondAttribute="centerY" id="ULG-hE-r4c"/>
+                                    <constraint firstItem="FJA-EM-1G3" firstAttribute="leading" secondItem="oTL-pD-XOH" secondAttribute="leading" constant="15" id="git-tY-lLS"/>
+                                    <constraint firstAttribute="height" constant="44" id="mWg-dC-Ik3"/>
+                                </constraints>
+                            </view>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="You can install certificates from a PKCS#12 file with pfx or p12 extension." textAlignment="natural" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="UoO-HA-SVc">
+                                <rect key="frame" x="15" y="109" width="345" height="33.5"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="cjW-BP-ZFL">
+                                <rect key="frame" x="15" y="330" width="345" height="50"/>
+                                <color key="backgroundColor" red="0.0" green="0.86274509803921573" blue="0.3529411764705882" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="50" id="lu0-p7-H2a"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                <state key="normal" title="Install">
+                                    <color key="titleColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
+                                </state>
+                                <connections>
+                                    <action selector="installButtonClicked:" destination="ge6-AP-0um" eventType="touchUpInside" id="PYu-57-QWz"/>
+                                    <action selector="loginButtonClicked:" destination="b5l-8Z-fX3" eventType="touchUpInside" id="UKB-Hy-PM1"/>
+                                    <action selector="registerButtonClicked:" destination="A29-A2-ywC" eventType="touchUpInside" id="ZPB-L1-LcO"/>
+                                </connections>
+                            </button>
+                            <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" scrollEnabled="NO" dataMode="prototypes" style="grouped" rowHeight="44" sectionHeaderHeight="-1" sectionFooterHeight="-1" translatesAutoresizingMaskIntoConstraints="NO" id="Z4E-xR-btY">
+                                <rect key="frame" x="15" y="225" width="345" height="50"/>
+                                <color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="50" id="IH7-BE-LEw"/>
+                                </constraints>
+                                <color key="separatorColor" red="0.98039215686274506" green="0.98039215686274506" blue="0.98039215686274506" alpha="1" colorSpace="calibratedRGB"/>
+                                <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                <connections>
+                                    <outlet property="dataSource" destination="ge6-AP-0um" id="3sG-Ui-Q9k"/>
+                                    <outlet property="delegate" destination="ge6-AP-0um" id="Jji-cS-5KC"/>
+                                </connections>
+                            </tableView>
+                        </subviews>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="calibratedRGB"/>
+                        <constraints>
+                            <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="hly-Eq-Kfh" secondAttribute="trailing" constant="20" symbolic="YES" id="6yE-eh-4JC"/>
+                            <constraint firstItem="Arr-MX-tZv" firstAttribute="leading" secondItem="4fd-Yp-3nJ" secondAttribute="leading" constant="18" id="8eg-Kp-h0c"/>
+                            <constraint firstAttribute="trailing" secondItem="UoO-HA-SVc" secondAttribute="trailing" constant="15" id="9iT-QF-3zu"/>
+                            <constraint firstItem="nLW-cz-kvJ" firstAttribute="leading" secondItem="4fd-Yp-3nJ" secondAttribute="leadingMargin" constant="2" id="AYP-VA-cke"/>
+                            <constraint firstItem="oTL-pD-XOH" firstAttribute="leading" secondItem="4fd-Yp-3nJ" secondAttribute="leading" constant="15" id="C7P-k7-MdP"/>
+                            <constraint firstItem="nLW-cz-kvJ" firstAttribute="top" secondItem="4fd-Yp-3nJ" secondAttribute="topMargin" constant="190" id="CD7-4k-64T"/>
+                            <constraint firstItem="UoO-HA-SVc" firstAttribute="top" secondItem="oTL-pD-XOH" secondAttribute="bottom" constant="15" id="ERj-3C-f9B"/>
+                            <constraint firstItem="Arr-MX-tZv" firstAttribute="top" secondItem="JbV-43-RVv" secondAttribute="bottom" constant="20" id="Hxi-NT-Lc8"/>
+                            <constraint firstAttribute="trailing" secondItem="Z4E-xR-btY" secondAttribute="trailing" constant="15" id="Kdq-Sj-ttX"/>
+                            <constraint firstAttribute="trailing" secondItem="oTL-pD-XOH" secondAttribute="trailing" constant="15" id="Le2-p8-Glc"/>
+                            <constraint firstItem="hly-Eq-Kfh" firstAttribute="top" secondItem="4fd-Yp-3nJ" secondAttribute="topMargin" constant="191.5" id="UJ3-tj-4po"/>
+                            <constraint firstItem="lXS-nR-USh" firstAttribute="top" secondItem="JbV-43-RVv" secondAttribute="bottom" constant="21.5" id="UwR-E9-mAj"/>
+                            <constraint firstAttribute="trailing" secondItem="cjW-BP-ZFL" secondAttribute="trailing" constant="15" id="bq5-oJ-Kvz"/>
+                            <constraint firstItem="cjW-BP-ZFL" firstAttribute="top" secondItem="JbV-43-RVv" secondAttribute="bottom" constant="330" id="dsn-bv-ysa"/>
+                            <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="lXS-nR-USh" secondAttribute="trailing" constant="20" symbolic="YES" id="ebu-M3-TZ0"/>
+                            <constraint firstItem="Z4E-xR-btY" firstAttribute="top" secondItem="JbV-43-RVv" secondAttribute="bottom" constant="225" id="fdS-un-lzW"/>
+                            <constraint firstItem="cjW-BP-ZFL" firstAttribute="leading" secondItem="4fd-Yp-3nJ" secondAttribute="leading" constant="15" id="nHQ-pb-dMI"/>
+                            <constraint firstItem="hly-Eq-Kfh" firstAttribute="leading" secondItem="nLW-cz-kvJ" secondAttribute="trailing" constant="8" id="pfM-Px-JLB"/>
+                            <constraint firstItem="oTL-pD-XOH" firstAttribute="top" secondItem="JbV-43-RVv" secondAttribute="bottom" constant="50" id="uHI-5j-Kee"/>
+                            <constraint firstItem="lXS-nR-USh" firstAttribute="leading" secondItem="Arr-MX-tZv" secondAttribute="trailing" constant="8" id="wib-7k-aNB"/>
+                            <constraint firstItem="UoO-HA-SVc" firstAttribute="leading" secondItem="4fd-Yp-3nJ" secondAttribute="leading" constant="15" id="xLS-ek-2XS"/>
+                            <constraint firstItem="Z4E-xR-btY" firstAttribute="leading" secondItem="4fd-Yp-3nJ" secondAttribute="leading" constant="15" id="zhc-Cn-kTH"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" title="Certificate" id="TL5-4y-mEM">
+                        <barButtonItem key="rightBarButtonItem" image="GatewayDelete" id="H0t-dw-hku">
+                            <connections>
+                                <action selector="closeButtonClicked:" destination="ge6-AP-0um" id="Mfr-s9-Nmd"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                    <connections>
+                        <outlet property="addressTextField" destination="FJA-EM-1G3" id="c8g-dT-AFG"/>
+                        <outlet property="installButton" destination="cjW-BP-ZFL" id="SMv-iT-qNc"/>
+                        <outlet property="localCertTableView" destination="Z4E-xR-btY" id="kCw-Oo-izR"/>
+                        <outlet property="localSelectButton" destination="nLW-cz-kvJ" id="jqZ-cO-wtB"/>
+                        <outlet property="urlSelectButton" destination="Arr-MX-tZv" id="7mf-cd-ah6"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="ZvR-4T-YnU" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="5440.8000000000002" y="689.5052473763119"/>
+        </scene>
+        <!--GatewayNavigation-->
+        <scene sceneID="lf3-g6-jVa">
+            <objects>
+                <navigationController storyboardIdentifier="GatewayNavigationID" title="GatewayNavigation" automaticallyAdjustsScrollViewInsets="NO" id="idK-RG-cFM" sceneMemberID="viewController">
+                    <toolbarItems/>
+                    <navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="4K2-hC-btu">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        <color key="barTintColor" red="0.0" green="0.86274509803921573" blue="0.3529411764705882" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <textAttributes key="titleTextAttributes">
+                            <fontDescription key="fontDescription" type="boldSystem" pointSize="18"/>
+                            <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        </textAttributes>
+                    </navigationBar>
+                    <nil name="viewControllers"/>
+                    <connections>
+                        <segue destination="BYZ-38-t0r" kind="relationship" relationship="rootViewController" id="C7D-AS-2gf"/>
+                    </connections>
+                </navigationController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="ebJ-c7-H6h" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="117.59999999999999" y="690.40479760119945"/>
+        </scene>
+        <!--GatewaySettingsNavigation-->
+        <scene sceneID="8Tb-e8-GT6">
+            <objects>
+                <navigationController title="GatewaySettingsNavigation" automaticallyAdjustsScrollViewInsets="NO" id="LP6-tU-vWi" sceneMemberID="viewController">
+                    <toolbarItems/>
+                    <navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="W1g-yv-aUZ">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        <color key="barTintColor" red="0.0" green="0.86274509803921573" blue="0.3529411764705882" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <textAttributes key="titleTextAttributes">
+                            <fontDescription key="fontDescription" type="boldSystem" pointSize="18"/>
+                            <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        </textAttributes>
+                    </navigationBar>
+                    <nil name="viewControllers"/>
+                    <connections>
+                        <segue destination="XsL-WP-fGg" kind="relationship" relationship="rootViewController" id="cmf-Ie-86q"/>
+                    </connections>
+                </navigationController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="qPU-ev-P7K" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="1924" y="690"/>
+        </scene>
+        <!--LoginViewController-->
+        <scene sceneID="b0p-2j-xl6">
+            <objects>
+                <viewController title="LoginViewController" id="b5l-8Z-fX3" customClass="LoginViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="1DN-bp-EJl"/>
+                        <viewControllerLayoutGuide type="bottom" id="oXm-vm-vtE"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="soR-It-UbC">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <tableView clipsSubviews="YES" contentMode="scaleToFill" bounces="NO" scrollEnabled="NO" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="60" sectionHeaderHeight="15" sectionFooterHeight="1" translatesAutoresizingMaskIntoConstraints="NO" id="yPl-Nz-dId">
+                                <rect key="frame" x="0.0" y="0.0" width="375" height="310"/>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="310" id="u0Q-Ci-6Qx"/>
+                                </constraints>
+                                <color key="separatorColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <prototypes>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="LoginMethodCell" id="EHi-YO-eyO">
+                                        <rect key="frame" x="0.0" y="28" width="375" height="60"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="EHi-YO-eyO" id="Ga2-CA-3Ow">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginMethodName" translatesAutoresizingMaskIntoConstraints="NO" id="9py-By-48Z">
+                                                    <rect key="frame" x="38" y="22" width="16" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="height" constant="16" id="RgD-7G-4uy"/>
+                                                        <constraint firstAttribute="width" constant="16" id="ZXh-15-zuv"/>
+                                                    </constraints>
+                                                </imageView>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7xH-e1-dzC">
+                                                    <rect key="frame" x="69" y="0.0" width="306" height="60"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <imageView userInteractionEnabled="NO" tag="2" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginDropArrow" translatesAutoresizingMaskIntoConstraints="NO" id="Mg8-8x-MA8">
+                                                    <rect key="frame" x="339" y="26" width="13" height="8"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="13" id="DYc-0F-P3R"/>
+                                                        <constraint firstAttribute="height" constant="8" id="Iwh-O3-OX8"/>
+                                                    </constraints>
+                                                </imageView>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="9py-By-48Z" firstAttribute="leading" secondItem="Ga2-CA-3Ow" secondAttribute="leadingMargin" constant="22" id="5o2-cA-9fQ"/>
+                                                <constraint firstItem="7xH-e1-dzC" firstAttribute="top" secondItem="Ga2-CA-3Ow" secondAttribute="top" id="6Z3-iq-mpz"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="Mg8-8x-MA8" secondAttribute="trailing" constant="7" id="RLx-XR-lzm"/>
+                                                <constraint firstAttribute="bottom" secondItem="7xH-e1-dzC" secondAttribute="bottom" id="YYP-gn-dWe"/>
+                                                <constraint firstAttribute="trailing" secondItem="7xH-e1-dzC" secondAttribute="trailing" id="eM0-ft-fP6"/>
+                                                <constraint firstItem="Mg8-8x-MA8" firstAttribute="centerY" secondItem="Ga2-CA-3Ow" secondAttribute="centerY" id="gMQ-Wl-nnF"/>
+                                                <constraint firstItem="9py-By-48Z" firstAttribute="centerY" secondItem="Ga2-CA-3Ow" secondAttribute="centerY" id="p7l-x4-Nb5"/>
+                                                <constraint firstItem="7xH-e1-dzC" firstAttribute="leading" secondItem="9py-By-48Z" secondAttribute="trailing" constant="15" id="y9L-o4-z5I"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="LoginUsernameCell" id="NDm-Ji-2te">
+                                        <rect key="frame" x="0.0" y="88" width="375" height="60"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="NDm-Ji-2te" id="hWB-Bo-89k">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginUsername" translatesAutoresizingMaskIntoConstraints="NO" id="HQb-cc-76v">
+                                                    <rect key="frame" x="38" y="22" width="16" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="16" id="u3X-g7-Fj3"/>
+                                                        <constraint firstAttribute="height" constant="16" id="zbS-TB-O6I"/>
+                                                    </constraints>
+                                                </imageView>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Username" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="Ng3-FM-4LL">
+                                                    <rect key="frame" x="69" y="0.0" width="298" height="60"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits" returnKeyType="next"/>
+                                                    <connections>
+                                                        <outlet property="delegate" destination="b5l-8Z-fX3" id="rym-gW-6DF"/>
+                                                    </connections>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="HQb-cc-76v" firstAttribute="centerY" secondItem="hWB-Bo-89k" secondAttribute="centerY" id="2Yo-rD-Ygw"/>
+                                                <constraint firstItem="Ng3-FM-4LL" firstAttribute="top" secondItem="hWB-Bo-89k" secondAttribute="top" id="8hc-H9-bw2"/>
+                                                <constraint firstItem="Ng3-FM-4LL" firstAttribute="leading" secondItem="HQb-cc-76v" secondAttribute="trailing" constant="15" id="a3X-2Y-u65"/>
+                                                <constraint firstItem="HQb-cc-76v" firstAttribute="leading" secondItem="hWB-Bo-89k" secondAttribute="leadingMargin" constant="22" id="knC-iq-6MK"/>
+                                                <constraint firstAttribute="bottom" secondItem="Ng3-FM-4LL" secondAttribute="bottom" id="ouy-1v-nVF"/>
+                                                <constraint firstAttribute="trailing" secondItem="Ng3-FM-4LL" secondAttribute="trailing" constant="8" id="uAL-Y2-W5k"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="LoginPasswordCell" id="eR7-cR-QhZ">
+                                        <rect key="frame" x="0.0" y="148" width="375" height="60"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="eR7-cR-QhZ" id="jQq-9k-lhQ">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginPassword" translatesAutoresizingMaskIntoConstraints="NO" id="UMX-OB-kx0">
+                                                    <rect key="frame" x="38" y="22" width="16" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="height" constant="16" id="an0-dd-Emf"/>
+                                                        <constraint firstAttribute="width" constant="16" id="dcl-RO-fI7"/>
+                                                    </constraints>
+                                                </imageView>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Password" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="BYe-pr-0gN">
+                                                    <rect key="frame" x="69" y="0.0" width="298" height="60"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits" secureTextEntry="YES"/>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="trailing" secondItem="BYe-pr-0gN" secondAttribute="trailing" constant="8" id="EMa-yK-twW"/>
+                                                <constraint firstAttribute="bottom" secondItem="BYe-pr-0gN" secondAttribute="bottom" id="JOT-xs-CfB"/>
+                                                <constraint firstItem="BYe-pr-0gN" firstAttribute="top" secondItem="jQq-9k-lhQ" secondAttribute="top" id="LZM-q9-IBK"/>
+                                                <constraint firstItem="UMX-OB-kx0" firstAttribute="centerY" secondItem="jQq-9k-lhQ" secondAttribute="centerY" id="Pb8-2W-qgs"/>
+                                                <constraint firstItem="UMX-OB-kx0" firstAttribute="leading" secondItem="jQq-9k-lhQ" secondAttribute="leadingMargin" constant="22" id="ZNN-4r-f9M"/>
+                                                <constraint firstItem="BYe-pr-0gN" firstAttribute="leading" secondItem="UMX-OB-kx0" secondAttribute="trailing" constant="15" id="zry-9V-amM"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="LoginPassword2Cell" id="8XD-jR-JGc">
+                                        <rect key="frame" x="0.0" y="208" width="375" height="60"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="8XD-jR-JGc" id="9St-AD-g1q">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginPassword" translatesAutoresizingMaskIntoConstraints="NO" id="GOs-Xf-93O">
+                                                    <rect key="frame" x="38" y="22" width="16" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="height" constant="16" id="YDE-Qz-jwN"/>
+                                                        <constraint firstAttribute="width" constant="16" id="Z6L-WW-rcp"/>
+                                                    </constraints>
+                                                </imageView>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Password" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="WBC-j3-bju">
+                                                    <rect key="frame" x="69" y="0.0" width="298" height="60"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits" secureTextEntry="YES"/>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="trailing" secondItem="WBC-j3-bju" secondAttribute="trailing" constant="8" id="0PB-rq-UNs"/>
+                                                <constraint firstAttribute="bottom" secondItem="WBC-j3-bju" secondAttribute="bottom" id="8rC-p4-cb4"/>
+                                                <constraint firstItem="WBC-j3-bju" firstAttribute="top" secondItem="9St-AD-g1q" secondAttribute="top" id="DCn-jf-i3k"/>
+                                                <constraint firstItem="WBC-j3-bju" firstAttribute="leading" secondItem="GOs-Xf-93O" secondAttribute="trailing" constant="15" id="NaE-3Z-I7U"/>
+                                                <constraint firstItem="GOs-Xf-93O" firstAttribute="centerY" secondItem="9St-AD-g1q" secondAttribute="centerY" id="m9I-dH-xBR"/>
+                                                <constraint firstItem="GOs-Xf-93O" firstAttribute="leading" secondItem="9St-AD-g1q" secondAttribute="leadingMargin" constant="22" id="tcR-SP-cWl"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="LoginPassword3Cell" id="tcv-4Q-uf2">
+                                        <rect key="frame" x="0.0" y="268" width="375" height="60"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="tcv-4Q-uf2" id="se0-Iw-Atg">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginPassword" translatesAutoresizingMaskIntoConstraints="NO" id="pxH-M1-LKn">
+                                                    <rect key="frame" x="38" y="22" width="16" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="16" id="9yc-d6-iKI"/>
+                                                        <constraint firstAttribute="height" constant="16" id="fyT-rh-AtW"/>
+                                                    </constraints>
+                                                </imageView>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Password" minimumFontSize="17" clearButtonMode="unlessEditing" translatesAutoresizingMaskIntoConstraints="NO" id="WbM-xG-5wO">
+                                                    <rect key="frame" x="69" y="0.0" width="298" height="60"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits" secureTextEntry="YES"/>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="pxH-M1-LKn" firstAttribute="centerY" secondItem="se0-Iw-Atg" secondAttribute="centerY" id="51y-Zm-PlY"/>
+                                                <constraint firstItem="WbM-xG-5wO" firstAttribute="top" secondItem="se0-Iw-Atg" secondAttribute="top" id="Bvb-uQ-uoy"/>
+                                                <constraint firstAttribute="bottom" secondItem="WbM-xG-5wO" secondAttribute="bottom" id="C66-K5-6fF"/>
+                                                <constraint firstAttribute="trailing" secondItem="WbM-xG-5wO" secondAttribute="trailing" constant="8" id="HSz-Dr-pYM"/>
+                                                <constraint firstItem="WbM-xG-5wO" firstAttribute="leading" secondItem="pxH-M1-LKn" secondAttribute="trailing" constant="15" id="lPi-HR-9xh"/>
+                                                <constraint firstItem="pxH-M1-LKn" firstAttribute="leading" secondItem="se0-Iw-Atg" secondAttribute="leadingMargin" constant="22" id="ly8-VL-glD"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                </prototypes>
+                                <sections/>
+                                <connections>
+                                    <outlet property="dataSource" destination="b5l-8Z-fX3" id="V6c-qY-byk"/>
+                                    <outlet property="delegate" destination="b5l-8Z-fX3" id="Dz9-cr-uHB"/>
+                                </connections>
+                            </tableView>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="juX-Xb-hIb">
+                                <rect key="frame" x="15" y="345" width="345" height="50"/>
+                                <color key="backgroundColor" red="0.0" green="0.86274509803921573" blue="0.3529411764705882" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="50" id="uvY-JN-4i9"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                <state key="normal" title="Login">
+                                    <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                </state>
+                                <connections>
+                                    <action selector="loginButtonClicked:" destination="b5l-8Z-fX3" eventType="touchUpInside" id="HMl-Da-MHs"/>
+                                </connections>
+                            </button>
+                        </subviews>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <gestureRecognizers/>
+                        <constraints>
+                            <constraint firstAttribute="trailing" secondItem="yPl-Nz-dId" secondAttribute="trailing" id="InS-1e-X9j"/>
+                            <constraint firstItem="juX-Xb-hIb" firstAttribute="top" secondItem="yPl-Nz-dId" secondAttribute="bottom" constant="35" id="Ljw-ED-3H0"/>
+                            <constraint firstItem="juX-Xb-hIb" firstAttribute="leading" secondItem="soR-It-UbC" secondAttribute="leading" constant="15" id="OeV-gm-PZS"/>
+                            <constraint firstItem="yPl-Nz-dId" firstAttribute="leading" secondItem="soR-It-UbC" secondAttribute="leading" id="ZnM-1s-hqH"/>
+                            <constraint firstItem="yPl-Nz-dId" firstAttribute="top" secondItem="1DN-bp-EJl" secondAttribute="bottom" id="izh-n9-cwJ"/>
+                            <constraint firstAttribute="trailing" secondItem="juX-Xb-hIb" secondAttribute="trailing" constant="15" id="sKU-HK-ebF"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" title="Login" id="Wmb-C6-ThL">
+                        <barButtonItem key="rightBarButtonItem" image="LoginExit" id="gHd-dU-Gol">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            <connections>
+                                <action selector="exitButtonClicked:" destination="b5l-8Z-fX3" id="KHf-3E-X4k"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                    <connections>
+                        <outlet property="loginButton" destination="juX-Xb-hIb" id="nFg-cS-YXi"/>
+                        <outlet property="tableView" destination="yPl-Nz-dId" id="OVL-Ge-HIU"/>
+                        <outlet property="tableViewHeightConstraint" destination="u0Q-Ci-6Qx" id="3Hr-AO-JhT"/>
+                        <segue destination="MGw-hc-Bqe" kind="show" identifier="LoginToChangePassword" id="Iyn-qq-u9T"/>
+                        <segue destination="A29-A2-ywC" kind="show" identifier="LoginToRegister" id="sO0-s5-1Pp"/>
+                        <segue destination="Qv9-5w-hBC" kind="show" identifier="LoginToChallenge" id="3ah-39-IJ1"/>
+                        <segue destination="axh-t8-XkJ" kind="show" identifier="LoginToSMS" id="Xr9-Sq-bCI"/>
+                        <segue destination="Own-rK-e3P" kind="show" identifier="LoginToSyferLock" id="f3w-K1-XbV"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="LYB-28-XzO" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="2796" y="1804.9475262368817"/>
+        </scene>
+        <!--Register-->
+        <scene sceneID="yMl-II-Gfg">
+            <objects>
+                <viewController id="A29-A2-ywC" customClass="RegisterViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="r4c-Ow-sH6"/>
+                        <viewControllerLayoutGuide type="bottom" id="ZRV-XI-4sK"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="HOP-1B-zgP">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <tableView clipsSubviews="YES" contentMode="scaleToFill" bounces="NO" scrollEnabled="NO" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="60" sectionHeaderHeight="15" sectionFooterHeight="1" translatesAutoresizingMaskIntoConstraints="NO" id="j8h-Cg-Eax">
+                                <rect key="frame" x="0.0" y="0.0" width="375" height="195"/>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="195" id="6nG-hW-ZyK"/>
+                                </constraints>
+                                <color key="separatorColor" red="0.8862745098" green="0.8862745098" blue="0.8862745098" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <prototypes>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="RegisterUsernameCell" id="BZv-R7-xmh">
+                                        <rect key="frame" x="0.0" y="28" width="375" height="60"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="BZv-R7-xmh" id="hgS-NV-k22">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginUsername" translatesAutoresizingMaskIntoConstraints="NO" id="Oqq-Od-aq5">
+                                                    <rect key="frame" x="38" y="22" width="16" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="height" constant="16" id="FhU-2U-ywL"/>
+                                                        <constraint firstAttribute="width" constant="16" id="qXk-M0-hsO"/>
+                                                    </constraints>
+                                                </imageView>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Username" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="FMa-ck-fFH">
+                                                    <rect key="frame" x="69" y="0.0" width="298" height="60"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits"/>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="bottom" secondItem="FMa-ck-fFH" secondAttribute="bottom" id="4W4-Ko-8YJ"/>
+                                                <constraint firstItem="Oqq-Od-aq5" firstAttribute="leading" secondItem="hgS-NV-k22" secondAttribute="leadingMargin" constant="22" id="JRI-vU-QrP"/>
+                                                <constraint firstItem="FMa-ck-fFH" firstAttribute="top" secondItem="hgS-NV-k22" secondAttribute="top" id="NCr-0R-g2t"/>
+                                                <constraint firstItem="Oqq-Od-aq5" firstAttribute="centerY" secondItem="hgS-NV-k22" secondAttribute="centerY" id="clN-JP-BeW"/>
+                                                <constraint firstItem="FMa-ck-fFH" firstAttribute="leading" secondItem="Oqq-Od-aq5" secondAttribute="trailing" constant="15" id="stn-Dv-8eT"/>
+                                                <constraint firstAttribute="trailing" secondItem="FMa-ck-fFH" secondAttribute="trailing" constant="8" id="yS8-gU-fQg"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="RegisterPasswordCell" id="PPm-fN-k3B">
+                                        <rect key="frame" x="0.0" y="88" width="375" height="60"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="PPm-fN-k3B" id="R80-Za-JQG">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginPassword" translatesAutoresizingMaskIntoConstraints="NO" id="xa5-Ev-e6r">
+                                                    <rect key="frame" x="38" y="22" width="16" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="16" id="AcV-yK-IUo"/>
+                                                        <constraint firstAttribute="height" constant="16" id="rwx-7D-V8W"/>
+                                                    </constraints>
+                                                </imageView>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Password" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="dzG-jd-47k">
+                                                    <rect key="frame" x="69" y="0.0" width="298" height="60"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits" secureTextEntry="YES"/>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="xa5-Ev-e6r" firstAttribute="leading" secondItem="R80-Za-JQG" secondAttribute="leadingMargin" constant="22" id="3ts-hQ-klY"/>
+                                                <constraint firstItem="dzG-jd-47k" firstAttribute="top" secondItem="R80-Za-JQG" secondAttribute="top" id="79N-dx-T4g"/>
+                                                <constraint firstItem="xa5-Ev-e6r" firstAttribute="centerY" secondItem="R80-Za-JQG" secondAttribute="centerY" id="apF-6G-PWi"/>
+                                                <constraint firstAttribute="trailing" secondItem="dzG-jd-47k" secondAttribute="trailing" constant="8" id="j9l-wX-yoc"/>
+                                                <constraint firstAttribute="bottom" secondItem="dzG-jd-47k" secondAttribute="bottom" id="xTZ-HY-3ly"/>
+                                                <constraint firstItem="dzG-jd-47k" firstAttribute="leading" secondItem="xa5-Ev-e6r" secondAttribute="trailing" constant="15" id="yrl-pf-dj4"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="RegisterDeviceNameCell" id="wHL-5P-nIf">
+                                        <rect key="frame" x="0.0" y="148" width="375" height="60"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="wHL-5P-nIf" id="r3W-bH-Cpu">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="n6p-E3-OCI">
+                                                    <rect key="frame" x="152.5" y="0.0" width="214.5" height="60"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits"/>
+                                                </textField>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="1000" text="Device Name:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gLM-TK-KzW">
+                                                    <rect key="frame" x="38" y="19.5" width="106" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="bottom" secondItem="n6p-E3-OCI" secondAttribute="bottom" id="4Fx-Sj-kGV"/>
+                                                <constraint firstAttribute="trailing" secondItem="n6p-E3-OCI" secondAttribute="trailing" constant="8" id="5IE-T8-2sZ"/>
+                                                <constraint firstItem="n6p-E3-OCI" firstAttribute="top" secondItem="r3W-bH-Cpu" secondAttribute="top" id="JBu-fH-Pta"/>
+                                                <constraint firstItem="gLM-TK-KzW" firstAttribute="leading" secondItem="r3W-bH-Cpu" secondAttribute="leadingMargin" constant="22" id="oQ5-KI-ywV"/>
+                                                <constraint firstItem="n6p-E3-OCI" firstAttribute="leading" secondItem="gLM-TK-KzW" secondAttribute="trailing" constant="8.5" id="wOT-ZX-56l"/>
+                                                <constraint firstItem="gLM-TK-KzW" firstAttribute="centerY" secondItem="r3W-bH-Cpu" secondAttribute="centerY" id="wnv-Ft-1Yr"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                </prototypes>
+                                <sections/>
+                                <connections>
+                                    <outlet property="dataSource" destination="A29-A2-ywC" id="xC8-Oy-LkW"/>
+                                    <outlet property="delegate" destination="A29-A2-ywC" id="zWB-Cr-Pda"/>
+                                </connections>
+                            </tableView>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Pbw-TK-XUH">
+                                <rect key="frame" x="15" y="235" width="345" height="50"/>
+                                <color key="backgroundColor" red="0.0" green="0.86274509803921573" blue="0.3529411764705882" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="50" id="DYJ-nA-Eg7"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                <state key="normal" title="Register">
+                                    <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                </state>
+                                <connections>
+                                    <action selector="loginButtonClicked:" destination="b5l-8Z-fX3" eventType="touchUpInside" id="q74-AZ-KcJ"/>
+                                    <action selector="registerButtonClicked:" destination="A29-A2-ywC" eventType="touchUpInside" id="thg-yU-YnC"/>
+                                </connections>
+                            </button>
+                        </subviews>
+                        <color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <constraints>
+                            <constraint firstItem="Pbw-TK-XUH" firstAttribute="top" secondItem="j8h-Cg-Eax" secondAttribute="bottom" constant="40" id="DN6-Pp-wYE"/>
+                            <constraint firstAttribute="trailing" secondItem="j8h-Cg-Eax" secondAttribute="trailing" id="Fig-tR-38v"/>
+                            <constraint firstItem="j8h-Cg-Eax" firstAttribute="top" secondItem="r4c-Ow-sH6" secondAttribute="bottom" id="I6E-gn-Gna"/>
+                            <constraint firstItem="Pbw-TK-XUH" firstAttribute="leading" secondItem="HOP-1B-zgP" secondAttribute="leading" constant="15" id="LN9-KY-ojG"/>
+                            <constraint firstAttribute="trailing" secondItem="Pbw-TK-XUH" secondAttribute="trailing" constant="15" id="rCa-HH-paQ"/>
+                            <constraint firstItem="j8h-Cg-Eax" firstAttribute="leading" secondItem="HOP-1B-zgP" secondAttribute="leading" id="vfP-L1-ROT"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" title="Register" id="aHJ-lm-gVt">
+                        <barButtonItem key="leftBarButtonItem" title="Cancel" id="yPq-1N-cfx">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            <connections>
+                                <action selector="cancelButtonClicked:" destination="A29-A2-ywC" id="0EG-yG-Da1"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                    <connections>
+                        <outlet property="registerButton" destination="Pbw-TK-XUH" id="442-X6-atp"/>
+                        <outlet property="tableView" destination="j8h-Cg-Eax" id="Nkx-uy-p8O"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="WKG-Ms-hFh" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="3664.8000000000002" y="1804.9475262368817"/>
+        </scene>
+        <!--Challenge-->
+        <scene sceneID="4sx-It-vfN">
+            <objects>
+                <viewController id="Qv9-5w-hBC" customClass="ChallengeViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="yZz-4a-ccD"/>
+                        <viewControllerLayoutGuide type="bottom" id="Eas-o5-h4e"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="1Zb-xl-XyS">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <tableView clipsSubviews="YES" contentMode="scaleToFill" bounces="NO" dataMode="prototypes" style="grouped" separatorStyle="default" allowsSelection="NO" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" translatesAutoresizingMaskIntoConstraints="NO" id="VTT-we-cnt">
+                                <rect key="frame" x="0.0" y="0.0" width="375" height="75"/>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="75" id="1zN-bi-q3G"/>
+                                </constraints>
+                                <color key="separatorColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="calibratedRGB"/>
+                                <prototypes>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="ChallengePasswordCell" id="tnh-FZ-LtH">
+                                        <rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="tnh-FZ-LtH" id="TvW-8M-FMf">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginPassword" translatesAutoresizingMaskIntoConstraints="NO" id="f96-7e-hfK">
+                                                    <rect key="frame" x="23" y="14" width="16" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="height" constant="16" id="hxB-DA-eED"/>
+                                                        <constraint firstAttribute="width" constant="16" id="omO-tp-o2Z"/>
+                                                    </constraints>
+                                                </imageView>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Password" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="QYy-f0-w8v">
+                                                    <rect key="frame" x="49" y="0.0" width="311" height="44"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits" secureTextEntry="YES"/>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="trailing" secondItem="QYy-f0-w8v" secondAttribute="trailing" constant="15" id="42j-2d-OW3"/>
+                                                <constraint firstAttribute="bottom" secondItem="QYy-f0-w8v" secondAttribute="bottom" id="4k8-Wi-a1F"/>
+                                                <constraint firstItem="QYy-f0-w8v" firstAttribute="leading" secondItem="f96-7e-hfK" secondAttribute="trailing" constant="10" id="E0v-Sk-eeS"/>
+                                                <constraint firstItem="f96-7e-hfK" firstAttribute="centerY" secondItem="TvW-8M-FMf" secondAttribute="centerY" id="Nlp-Z7-u0n"/>
+                                                <constraint firstItem="f96-7e-hfK" firstAttribute="leading" secondItem="TvW-8M-FMf" secondAttribute="leadingMargin" constant="7" id="e7F-tL-zeK"/>
+                                                <constraint firstItem="QYy-f0-w8v" firstAttribute="top" secondItem="TvW-8M-FMf" secondAttribute="top" id="qnv-gI-M6h"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                </prototypes>
+                                <connections>
+                                    <outlet property="dataSource" destination="Qv9-5w-hBC" id="fG0-JY-Hwd"/>
+                                    <outlet property="delegate" destination="Qv9-5w-hBC" id="fwC-wA-F2p"/>
+                                </connections>
+                            </tableView>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kzl-9l-9Ef">
+                                <rect key="frame" x="15" y="120" width="345" height="50"/>
+                                <color key="backgroundColor" red="0.0" green="0.86274509803921573" blue="0.3529411764705882" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="50" id="RPp-IU-QdT"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                <state key="normal" title="Login">
+                                    <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                </state>
+                                <connections>
+                                    <action selector="loginButtonClicked:" destination="Qv9-5w-hBC" eventType="touchUpInside" id="3Fw-Tq-qBb"/>
+                                    <action selector="loginButtonClicked:" destination="b5l-8Z-fX3" eventType="touchUpInside" id="sLr-X7-gTy"/>
+                                </connections>
+                            </button>
+                        </subviews>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="calibratedRGB"/>
+                        <constraints>
+                            <constraint firstItem="kzl-9l-9Ef" firstAttribute="leading" secondItem="1Zb-xl-XyS" secondAttribute="leading" constant="15" id="45B-nk-KYJ"/>
+                            <constraint firstAttribute="trailing" secondItem="kzl-9l-9Ef" secondAttribute="trailing" constant="15" id="edV-wK-cBf"/>
+                            <constraint firstItem="VTT-we-cnt" firstAttribute="leading" secondItem="1Zb-xl-XyS" secondAttribute="leading" id="f98-DC-F16"/>
+                            <constraint firstItem="VTT-we-cnt" firstAttribute="top" secondItem="yZz-4a-ccD" secondAttribute="bottom" id="hM8-8u-Ke5"/>
+                            <constraint firstItem="kzl-9l-9Ef" firstAttribute="top" secondItem="VTT-we-cnt" secondAttribute="bottom" constant="45" id="rxT-vs-Bic"/>
+                            <constraint firstAttribute="trailing" secondItem="VTT-we-cnt" secondAttribute="trailing" id="zL6-EK-fxL"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" title="Challenge" id="EhN-hu-nGU">
+                        <barButtonItem key="leftBarButtonItem" title="Cancel" id="WOr-DE-WNk">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                            <connections>
+                                <action selector="cancelButtonClicked:" destination="Qv9-5w-hBC" id="jcg-19-qT7"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                    <connections>
+                        <outlet property="loginButton" destination="kzl-9l-9Ef" id="f1D-ue-Rrh"/>
+                        <outlet property="tableView" destination="VTT-we-cnt" id="bWs-dg-BPN"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="WYE-DD-Yek" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="3664.8000000000002" y="2623.5382308845578"/>
+        </scene>
+        <!--SMS-->
+        <scene sceneID="pcD-2e-Qek">
+            <objects>
+                <viewController id="axh-t8-XkJ" userLabel="SMS" customClass="SMSViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="YbF-IW-N0J"/>
+                        <viewControllerLayoutGuide type="bottom" id="7UW-9S-1DG"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="zfg-q5-hIg">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <tableView clipsSubviews="YES" contentMode="scaleToFill" bounces="NO" dataMode="prototypes" style="grouped" separatorStyle="default" allowsSelection="NO" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" translatesAutoresizingMaskIntoConstraints="NO" id="tYf-Cx-xgr">
+                                <rect key="frame" x="0.0" y="0.0" width="375" height="75"/>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="75" id="byo-tF-H87"/>
+                                </constraints>
+                                <color key="separatorColor" red="0.8862745098" green="0.8862745098" blue="0.8862745098" alpha="1" colorSpace="calibratedRGB"/>
+                                <prototypes>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="ValidateCodeCellID" id="723-mL-Qnc">
+                                        <rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="723-mL-Qnc" id="zuF-UF-KZu">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginPassword" translatesAutoresizingMaskIntoConstraints="NO" id="bYS-z6-32w">
+                                                    <rect key="frame" x="23" y="14" width="16" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="16" id="AQ5-j3-Abm"/>
+                                                        <constraint firstAttribute="height" constant="16" id="ccH-Dk-G6x"/>
+                                                    </constraints>
+                                                </imageView>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Verification Code" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="Wkf-H4-MkU">
+                                                    <rect key="frame" x="49" y="0.0" width="223" height="45"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits"/>
+                                                </textField>
+                                                <button opaque="NO" tag="2" contentMode="scaleToFill" horizontalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="W4E-oF-QCg">
+                                                    <rect key="frame" x="270" y="7" width="90" height="30"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="90" id="VLm-6K-t9k"/>
+                                                    </constraints>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <state key="normal" title="Resend">
+                                                        <color key="titleColor" red="0.89411764709999997" green="0.43921568630000002" blue="0.1137254902" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    </state>
+                                                    <state key="highlighted" title="Resend">
+                                                        <color key="titleColor" red="0.89411764709999997" green="0.43921568630000002" blue="0.1137254902" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    </state>
+                                                </button>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="trailing" secondItem="W4E-oF-QCg" secondAttribute="trailing" constant="15" id="5dO-vl-AKa"/>
+                                                <constraint firstItem="Wkf-H4-MkU" firstAttribute="leading" secondItem="bYS-z6-32w" secondAttribute="trailing" constant="10" id="Knm-pn-mYg"/>
+                                                <constraint firstItem="W4E-oF-QCg" firstAttribute="centerY" secondItem="zuF-UF-KZu" secondAttribute="centerY" id="VoL-M7-vyO"/>
+                                                <constraint firstItem="bYS-z6-32w" firstAttribute="leading" secondItem="zuF-UF-KZu" secondAttribute="leadingMargin" constant="7" id="aF9-bE-5c1"/>
+                                                <constraint firstItem="bYS-z6-32w" firstAttribute="centerY" secondItem="zuF-UF-KZu" secondAttribute="centerY" id="aua-TM-OQb"/>
+                                                <constraint firstItem="Wkf-H4-MkU" firstAttribute="top" secondItem="zuF-UF-KZu" secondAttribute="top" id="kay-cg-6Mw"/>
+                                                <constraint firstAttribute="bottom" secondItem="Wkf-H4-MkU" secondAttribute="bottom" constant="-1" id="mAd-0a-5Kt"/>
+                                                <constraint firstItem="W4E-oF-QCg" firstAttribute="leading" secondItem="Wkf-H4-MkU" secondAttribute="trailing" constant="-2" id="nFf-9K-y4u"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                </prototypes>
+                                <connections>
+                                    <outlet property="dataSource" destination="axh-t8-XkJ" id="JPu-9h-IpA"/>
+                                    <outlet property="delegate" destination="axh-t8-XkJ" id="kf9-F3-jfa"/>
+                                </connections>
+                            </tableView>
+                            <button opaque="NO" tag="2" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="UOd-np-41k">
+                                <rect key="frame" x="15" y="120" width="345" height="50"/>
+                                <color key="backgroundColor" red="0.0" green="0.86274509803921573" blue="0.3529411764705882" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="50" id="icY-tA-0j1"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                <state key="normal" title="Login">
+                                    <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                </state>
+                                <connections>
+                                    <action selector="loginButtonClicked:" destination="b5l-8Z-fX3" eventType="touchUpInside" id="A85-zG-8B3"/>
+                                    <action selector="loginButtonClicked:" destination="axh-t8-XkJ" eventType="touchUpInside" id="Psh-At-hvb"/>
+                                    <action selector="loginButtonClicked:" destination="Qv9-5w-hBC" eventType="touchUpInside" id="bEB-CX-zy1"/>
+                                </connections>
+                            </button>
+                        </subviews>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="calibratedRGB"/>
+                        <constraints>
+                            <constraint firstItem="UOd-np-41k" firstAttribute="top" secondItem="tYf-Cx-xgr" secondAttribute="bottom" constant="45" id="714-tV-VIp"/>
+                            <constraint firstItem="UOd-np-41k" firstAttribute="leading" secondItem="zfg-q5-hIg" secondAttribute="leading" constant="15" id="Ets-1C-895"/>
+                            <constraint firstItem="tYf-Cx-xgr" firstAttribute="leading" secondItem="zfg-q5-hIg" secondAttribute="leading" id="Iio-3P-dXe"/>
+                            <constraint firstAttribute="trailing" secondItem="UOd-np-41k" secondAttribute="trailing" constant="15" id="WEe-mz-UKY"/>
+                            <constraint firstAttribute="trailing" secondItem="tYf-Cx-xgr" secondAttribute="trailing" id="cmX-kT-WHf"/>
+                            <constraint firstItem="tYf-Cx-xgr" firstAttribute="top" secondItem="YbF-IW-N0J" secondAttribute="bottom" id="fTj-Uu-qr1"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" title="OTP Authentication" id="2GC-VR-kJB">
+                        <barButtonItem key="leftBarButtonItem" title="Cancel" id="hGm-60-ZTY">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                            <connections>
+                                <action selector="cancelButtonClicked:" destination="axh-t8-XkJ" id="gdJ-SW-FFw"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                    <connections>
+                        <outlet property="loginButton" destination="UOd-np-41k" id="O6R-i0-Xig"/>
+                        <outlet property="tableView" destination="tYf-Cx-xgr" id="7YT-TS-6iB"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="CoK-La-pf4" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="4532" y="2623.5382308845578"/>
+        </scene>
+        <!--Remote Desktop-->
+        <scene sceneID="JJ1-oV-W3X">
+            <objects>
+                <viewController id="EyZ-YP-cnm" customClass="CustomDesktopViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="VWM-U1-5o9"/>
+                        <viewControllerLayoutGuide type="bottom" id="YXS-ze-ieJ"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="c8C-Mw-TJi">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <tableView clipsSubviews="YES" contentMode="scaleToFill" bounces="NO" scrollEnabled="NO" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="66" sectionHeaderHeight="15" sectionFooterHeight="1" translatesAutoresizingMaskIntoConstraints="NO" id="SdP-hh-QXC">
+                                <rect key="frame" x="0.0" y="0.0" width="375" height="213"/>
+                                <color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="213" id="1YP-8G-8ld"/>
+                                </constraints>
+                                <color key="separatorColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="calibratedRGB"/>
+                                <prototypes>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="HostnameCellID" id="etB-7Z-yn2">
+                                        <rect key="frame" x="0.0" y="55.5" width="375" height="66"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="etB-7Z-yn2" id="gMD-73-OSA">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="66"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Host/IP" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="uEq-nN-ns5">
+                                                    <rect key="frame" x="15" y="0.0" width="352" height="66"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits"/>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="uEq-nN-ns5" firstAttribute="leading" secondItem="gMD-73-OSA" secondAttribute="leading" constant="15" id="B5n-QH-6ks"/>
+                                                <constraint firstItem="uEq-nN-ns5" firstAttribute="top" secondItem="gMD-73-OSA" secondAttribute="top" id="g4H-pu-NeQ"/>
+                                                <constraint firstAttribute="trailing" secondItem="uEq-nN-ns5" secondAttribute="trailing" constant="8" id="m8M-Nd-goU"/>
+                                                <constraint firstAttribute="bottom" secondItem="uEq-nN-ns5" secondAttribute="bottom" id="wkY-LW-N8M"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="UsernameCellID" id="cvj-EV-isL">
+                                        <rect key="frame" x="0.0" y="121.5" width="375" height="66"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="cvj-EV-isL" id="bLG-Jv-A7P">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="66"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Username" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="GD0-qw-dtZ">
+                                                    <rect key="frame" x="15" y="0.0" width="352" height="66"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits"/>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="GD0-qw-dtZ" firstAttribute="leading" secondItem="bLG-Jv-A7P" secondAttribute="leading" constant="15" id="Z1u-Fo-sjt"/>
+                                                <constraint firstItem="GD0-qw-dtZ" firstAttribute="top" secondItem="bLG-Jv-A7P" secondAttribute="top" id="aHq-h6-HkE"/>
+                                                <constraint firstAttribute="bottom" secondItem="GD0-qw-dtZ" secondAttribute="bottom" id="bR5-fk-ZfA"/>
+                                                <constraint firstAttribute="trailing" secondItem="GD0-qw-dtZ" secondAttribute="trailing" constant="8" id="gDV-IP-KmW"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="DomainCellID" id="qnG-5C-1eQ">
+                                        <rect key="frame" x="0.0" y="187.5" width="375" height="66"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="qnG-5C-1eQ" id="mUl-yZ-dMC">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="66"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Domain" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="Q7j-qj-9b8">
+                                                    <rect key="frame" x="15" y="0.0" width="352" height="66"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits"/>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="Q7j-qj-9b8" firstAttribute="leading" secondItem="mUl-yZ-dMC" secondAttribute="leading" constant="15" id="2w0-g0-FC4"/>
+                                                <constraint firstAttribute="bottom" secondItem="Q7j-qj-9b8" secondAttribute="bottom" id="AXg-1v-Hfr"/>
+                                                <constraint firstItem="Q7j-qj-9b8" firstAttribute="top" secondItem="mUl-yZ-dMC" secondAttribute="top" id="OpS-hS-cYR"/>
+                                                <constraint firstAttribute="trailing" secondItem="Q7j-qj-9b8" secondAttribute="trailing" constant="8" id="dLC-b2-dtN"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </prototypes>
+                                <connections>
+                                    <outlet property="dataSource" destination="EyZ-YP-cnm" id="glA-Sa-g6B"/>
+                                    <outlet property="delegate" destination="EyZ-YP-cnm" id="uzs-PR-4Fq"/>
+                                </connections>
+                            </tableView>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="cOm-0d-WcQ">
+                                <rect key="frame" x="15" y="258" width="345" height="50"/>
+                                <color key="backgroundColor" red="0.0" green="0.86274509803921573" blue="0.3529411764705882" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="50" id="lA9-cA-1fW"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                <state key="normal" title="Connect">
+                                    <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                </state>
+                                <connections>
+                                    <action selector="connectButtonClicked:" destination="EyZ-YP-cnm" eventType="touchUpInside" id="kga-2U-pIz"/>
+                                    <action selector="loginButtonClicked:" destination="b5l-8Z-fX3" eventType="touchUpInside" id="2xf-Pf-bE4"/>
+                                </connections>
+                            </button>
+                        </subviews>
+                        <color key="backgroundColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="calibratedRGB"/>
+                        <constraints>
+                            <constraint firstAttribute="trailing" secondItem="cOm-0d-WcQ" secondAttribute="trailing" constant="15" id="1FF-Oy-GiT"/>
+                            <constraint firstItem="SdP-hh-QXC" firstAttribute="top" secondItem="VWM-U1-5o9" secondAttribute="bottom" id="2p8-dW-pSI"/>
+                            <constraint firstItem="cOm-0d-WcQ" firstAttribute="leading" secondItem="c8C-Mw-TJi" secondAttribute="leading" constant="15" id="fNM-Y8-wtw"/>
+                            <constraint firstItem="cOm-0d-WcQ" firstAttribute="top" secondItem="SdP-hh-QXC" secondAttribute="bottom" constant="45" id="g7m-A8-RTu"/>
+                            <constraint firstAttribute="trailing" secondItem="SdP-hh-QXC" secondAttribute="trailing" id="gNm-Jx-2iq"/>
+                            <constraint firstItem="SdP-hh-QXC" firstAttribute="leading" secondItem="c8C-Mw-TJi" secondAttribute="leading" id="vka-uQ-P8W"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" title="Remote Desktop" id="rIh-wP-43Y"/>
+                    <connections>
+                        <outlet property="connectButton" destination="cOm-0d-WcQ" id="ObK-fm-Ebi"/>
+                        <outlet property="tableView" destination="SdP-hh-QXC" id="eiW-cw-c6i"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="uUH-qY-4Qt" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="-1876" y="4589.9550224887562"/>
+        </scene>
+        <!--Sub Resource View Controller-->
+        <scene sceneID="aB2-YP-vxA">
+            <objects>
+                <tableViewController storyboardIdentifier="SubResourceViewControllerID" id="ixp-zo-wwn" customClass="SubResourceViewController" sceneMemberID="viewController">
+                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="i4P-Z6-S9g">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
+                        <color key="separatorColor" red="0.8862745098" green="0.8862745098" blue="0.8862745098" alpha="1" colorSpace="calibratedRGB"/>
+                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                        <connections>
+                            <outlet property="dataSource" destination="ixp-zo-wwn" id="hHh-w9-ItC"/>
+                            <outlet property="delegate" destination="ixp-zo-wwn" id="Dj0-Kz-Mk6"/>
+                        </connections>
+                    </tableView>
+                </tableViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="NUl-g4-55J" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="-1018" y="4590"/>
+        </scene>
+        <!--Access Mode Select View Controller-->
+        <scene sceneID="Ne8-3d-fdj">
+            <objects>
+                <tableViewController storyboardIdentifier="AcsModeViewControllerID" id="Lt7-EO-i16" customClass="AccessModeSelectViewController" sceneMemberID="viewController">
+                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="47q-3J-XW7">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
+                        <color key="separatorColor" red="0.88627450980392153" green="0.88627450980392153" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
+                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                        <connections>
+                            <outlet property="dataSource" destination="Lt7-EO-i16" id="DeZ-Ly-dbI"/>
+                            <outlet property="delegate" destination="Lt7-EO-i16" id="BxC-eJ-gED"/>
+                        </connections>
+                    </tableView>
+                    <navigationItem key="navigationItem" id="WsC-qd-FpB">
+                        <barButtonItem key="leftBarButtonItem" title="Cancel" id="OtV-xl-Ohs">
+                            <color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
+                            <connections>
+                                <action selector="cancelButtonClicked:" destination="Lt7-EO-i16" id="vjS-CA-vV7"/>
+                            </connections>
+                        </barButtonItem>
+                        <barButtonItem key="rightBarButtonItem" title="Confirm" id="yeD-Au-sFK">
+                            <color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
+                            <connections>
+                                <action selector="saveButtonClicked:" destination="Lt7-EO-i16" id="VN8-4x-rAN"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                </tableViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="Iow-K3-TGC" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="687" y="4590"/>
+        </scene>
+        <!--Navigation Controller-->
+        <scene sceneID="AGU-BE-BrM">
+            <objects>
+                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="RPI-UI-YjC" sceneMemberID="viewController">
+                    <navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="Jdo-AZ-1vk">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
+                        <color key="barTintColor" red="0.0" green="0.86274509803921573" blue="0.3529411764705882" alpha="1" colorSpace="calibratedRGB"/>
+                    </navigationBar>
+                    <connections>
+                        <segue destination="Lt7-EO-i16" kind="relationship" relationship="rootViewController" id="FEy-OB-dHW"/>
+                    </connections>
+                </navigationController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="U3E-52-6EV" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="-137" y="4590"/>
+        </scene>
+        <!--Gateway-->
+        <scene sceneID="Cah-u3-yRy">
+            <objects>
+                <viewController id="v1Y-JU-ghZ" customClass="ResourcesViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="jte-We-k7c"/>
+                        <viewControllerLayoutGuide type="bottom" id="spO-fb-3hh"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="cM6-BE-uc6">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qPJ-dc-5yP">
+                                <rect key="frame" x="0.0" y="0.0" width="375" height="50"/>
+                                <subviews>
+                                    <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="tih-jI-rGn">
+                                        <rect key="frame" x="311" y="9.5" width="51" height="31"/>
+                                        <connections>
+                                            <action selector="vpnEnableSwitched:" destination="v1Y-JU-ghZ" eventType="valueChanged" id="iL2-0D-4Fm"/>
+                                        </connections>
+                                    </switch>
+                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Secure Tunnel" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="PWl-K8-Dro">
+                                        <rect key="frame" x="15" y="14.5" width="112" height="21"/>
+                                        <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                        <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                        <nil key="highlightedColor"/>
+                                    </label>
+                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Connecting..." textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FFN-Tu-ZTR">
+                                        <rect key="frame" x="211" y="16" width="92" height="18"/>
+                                        <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                        <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                        <nil key="highlightedColor"/>
+                                    </label>
+                                    <activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="jEM-OB-Frs">
+                                        <rect key="frame" x="183" y="15" width="20" height="20"/>
+                                    </activityIndicatorView>
+                                    <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ResourceConnectSuccess" translatesAutoresizingMaskIntoConstraints="NO" id="4qi-ej-DYj">
+                                        <rect key="frame" x="189" y="18" width="14" height="14"/>
+                                        <constraints>
+                                            <constraint firstAttribute="width" constant="14" id="TtM-hi-btC"/>
+                                            <constraint firstAttribute="height" constant="14" id="dEQ-mr-7fK"/>
+                                        </constraints>
+                                    </imageView>
+                                </subviews>
+                                <color key="backgroundColor" red="0.98039215686274506" green="0.98039215686274506" blue="0.98039215686274506" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstItem="4qi-ej-DYj" firstAttribute="centerY" secondItem="qPJ-dc-5yP" secondAttribute="centerY" id="0yz-xn-UBa"/>
+                                    <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="PWl-K8-Dro" secondAttribute="trailing" constant="20" symbolic="YES" id="3O5-Wc-fl1"/>
+                                    <constraint firstItem="tih-jI-rGn" firstAttribute="centerY" secondItem="qPJ-dc-5yP" secondAttribute="centerY" id="6Km-eu-1dT"/>
+                                    <constraint firstAttribute="trailing" secondItem="tih-jI-rGn" secondAttribute="trailing" constant="15" id="CSc-q1-LGc"/>
+                                    <constraint firstItem="PWl-K8-Dro" firstAttribute="centerY" secondItem="qPJ-dc-5yP" secondAttribute="centerY" id="SfX-pu-Hck"/>
+                                    <constraint firstItem="PWl-K8-Dro" firstAttribute="leading" secondItem="qPJ-dc-5yP" secondAttribute="leading" constant="15" id="Y3C-14-l81"/>
+                                    <constraint firstItem="jEM-OB-Frs" firstAttribute="centerY" secondItem="qPJ-dc-5yP" secondAttribute="centerY" id="Yl4-Id-Myy"/>
+                                    <constraint firstItem="FFN-Tu-ZTR" firstAttribute="centerY" secondItem="qPJ-dc-5yP" secondAttribute="centerY" id="aX6-Om-muy"/>
+                                    <constraint firstItem="tih-jI-rGn" firstAttribute="leading" secondItem="FFN-Tu-ZTR" secondAttribute="trailing" constant="8" id="cBZ-Gs-M7Q"/>
+                                    <constraint firstAttribute="height" constant="50" id="pLS-7h-weF"/>
+                                    <constraint firstItem="FFN-Tu-ZTR" firstAttribute="leading" secondItem="4qi-ej-DYj" secondAttribute="trailing" constant="8" id="q5O-pe-eyM"/>
+                                    <constraint firstItem="FFN-Tu-ZTR" firstAttribute="leading" secondItem="jEM-OB-Frs" secondAttribute="trailing" constant="8" id="s5d-Wc-rut"/>
+                                </constraints>
+                            </view>
+                            <tableView hidden="YES" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" scrollEnabled="NO" dataMode="prototypes" style="grouped" rowHeight="44" sectionHeaderHeight="-1" sectionFooterHeight="-1" translatesAutoresizingMaskIntoConstraints="NO" id="fVv-Jr-fwe">
+                                <rect key="frame" x="0.0" y="45" width="375" height="50"/>
+                                <color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="50" id="1Qf-xq-abz"/>
+                                </constraints>
+                                <color key="separatorColor" red="0.98039215686274506" green="0.98039215686274506" blue="0.98039215686274506" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                <connections>
+                                    <outlet property="dataSource" destination="v1Y-JU-ghZ" id="gUP-Ln-clk"/>
+                                    <outlet property="delegate" destination="v1Y-JU-ghZ" id="a5Q-8i-KX0"/>
+                                </connections>
+                            </tableView>
+                            <view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BGN-X3-l8M">
+                                <rect key="frame" x="0.0" y="50" width="375" height="50"/>
+                                <subviews>
+                                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ppE-On-UgE">
+                                        <rect key="frame" x="15" y="0.0" width="345" height="1"/>
+                                        <color key="backgroundColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="calibratedRGB"/>
+                                        <constraints>
+                                            <constraint firstAttribute="height" constant="1" id="tue-lM-ylZ"/>
+                                        </constraints>
+                                    </view>
+                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hhP-By-cX0">
+                                        <rect key="frame" x="170" y="16.5" width="35.5" height="17"/>
+                                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                        <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                        <nil key="highlightedColor"/>
+                                    </label>
+                                </subviews>
+                                <color key="backgroundColor" red="0.98039215686274506" green="0.98039215686274506" blue="0.98039215686274506" alpha="1" colorSpace="calibratedRGB"/>
+                                <constraints>
+                                    <constraint firstItem="ppE-On-UgE" firstAttribute="top" secondItem="BGN-X3-l8M" secondAttribute="top" id="3aJ-1O-Ev3"/>
+                                    <constraint firstItem="hhP-By-cX0" firstAttribute="centerX" secondItem="BGN-X3-l8M" secondAttribute="centerX" id="Cyt-SX-yT4"/>
+                                    <constraint firstItem="ppE-On-UgE" firstAttribute="leading" secondItem="BGN-X3-l8M" secondAttribute="leading" constant="15" id="OcB-wq-M3J"/>
+                                    <constraint firstItem="hhP-By-cX0" firstAttribute="centerY" secondItem="BGN-X3-l8M" secondAttribute="centerY" id="dLG-Qb-PCQ"/>
+                                    <constraint firstAttribute="height" constant="50" id="fqC-er-5ET"/>
+                                    <constraint firstItem="ppE-On-UgE" firstAttribute="centerX" secondItem="BGN-X3-l8M" secondAttribute="centerX" id="pMx-ZS-QwR"/>
+                                </constraints>
+                            </view>
+                            <view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fSs-by-PN4">
+                                <rect key="frame" x="0.0" y="50" width="375" height="524"/>
+                                <subviews>
+                                    <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ResourceEmpty" translatesAutoresizingMaskIntoConstraints="NO" id="qeA-Ck-j1u">
+                                        <rect key="frame" x="117.5" y="95" width="140" height="128"/>
+                                        <constraints>
+                                            <constraint firstAttribute="height" constant="128" id="1Es-6G-ZAk"/>
+                                            <constraint firstAttribute="width" constant="140" id="o1x-P9-4kq"/>
+                                        </constraints>
+                                    </imageView>
+                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="No resource has been found" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iYp-n0-3JW">
+                                        <rect key="frame" x="96" y="253" width="183" height="17"/>
+                                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                        <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
+                                        <nil key="highlightedColor"/>
+                                    </label>
+                                </subviews>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                                <constraints>
+                                    <constraint firstItem="qeA-Ck-j1u" firstAttribute="centerX" secondItem="fSs-by-PN4" secondAttribute="centerX" id="5Qu-mO-edY"/>
+                                    <constraint firstItem="qeA-Ck-j1u" firstAttribute="top" secondItem="fSs-by-PN4" secondAttribute="top" constant="95" id="8du-wI-6ZF"/>
+                                    <constraint firstItem="iYp-n0-3JW" firstAttribute="centerX" secondItem="fSs-by-PN4" secondAttribute="centerX" id="m6b-WQ-Xi2"/>
+                                    <constraint firstItem="iYp-n0-3JW" firstAttribute="top" secondItem="qeA-Ck-j1u" secondAttribute="bottom" constant="30" id="oQs-az-YdD"/>
+                                </constraints>
+                            </view>
+                            <tableView hidden="YES" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" rowHeight="44" sectionHeaderHeight="1" sectionFooterHeight="1" translatesAutoresizingMaskIntoConstraints="NO" id="lt6-TN-CBy">
+                                <rect key="frame" x="0.0" y="45" width="375" height="529"/>
+                                <color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
+                                <color key="separatorColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="calibratedRGB"/>
+                                <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                <connections>
+                                    <outlet property="dataSource" destination="v1Y-JU-ghZ" id="Ebg-Ao-7f2"/>
+                                    <outlet property="delegate" destination="v1Y-JU-ghZ" id="duQ-PP-bvU"/>
+                                </connections>
+                            </tableView>
+                        </subviews>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <constraints>
+                            <constraint firstAttribute="trailing" secondItem="BGN-X3-l8M" secondAttribute="trailing" id="3va-Jk-A3v"/>
+                            <constraint firstItem="fVv-Jr-fwe" firstAttribute="leading" secondItem="cM6-BE-uc6" secondAttribute="leading" id="Fkd-jg-bPF"/>
+                            <constraint firstItem="BGN-X3-l8M" firstAttribute="leading" secondItem="cM6-BE-uc6" secondAttribute="leading" id="Ih2-h0-Z7L"/>
+                            <constraint firstItem="qPJ-dc-5yP" firstAttribute="leading" secondItem="cM6-BE-uc6" secondAttribute="leading" id="MYp-5R-gFR"/>
+                            <constraint firstItem="spO-fb-3hh" firstAttribute="top" secondItem="fSs-by-PN4" secondAttribute="bottom" id="R8r-Eu-HS6"/>
+                            <constraint firstItem="lt6-TN-CBy" firstAttribute="top" secondItem="jte-We-k7c" secondAttribute="bottom" constant="45" id="WhV-ye-ZlA"/>
+                            <constraint firstItem="fVv-Jr-fwe" firstAttribute="top" secondItem="jte-We-k7c" secondAttribute="bottom" constant="45" id="X6z-Fq-W8V"/>
+                            <constraint firstAttribute="trailing" secondItem="fVv-Jr-fwe" secondAttribute="trailing" id="cAN-9H-6vt"/>
+                            <constraint firstItem="spO-fb-3hh" firstAttribute="top" secondItem="lt6-TN-CBy" secondAttribute="bottom" id="cy4-DW-YTo"/>
+                            <constraint firstItem="lt6-TN-CBy" firstAttribute="leading" secondItem="cM6-BE-uc6" secondAttribute="leading" id="hpI-WN-qt6"/>
+                            <constraint firstItem="BGN-X3-l8M" firstAttribute="top" secondItem="jte-We-k7c" secondAttribute="bottom" constant="50" id="jIJ-bT-9O4"/>
+                            <constraint firstAttribute="trailing" secondItem="lt6-TN-CBy" secondAttribute="trailing" id="jmU-lg-4oZ"/>
+                            <constraint firstAttribute="trailing" secondItem="fSs-by-PN4" secondAttribute="trailing" id="k94-Cs-dt9"/>
+                            <constraint firstAttribute="trailing" secondItem="qPJ-dc-5yP" secondAttribute="trailing" id="nJX-OJ-sHb"/>
+                            <constraint firstItem="fSs-by-PN4" firstAttribute="leading" secondItem="cM6-BE-uc6" secondAttribute="leading" id="sil-Nc-xyd"/>
+                            <constraint firstItem="qPJ-dc-5yP" firstAttribute="top" secondItem="jte-We-k7c" secondAttribute="bottom" id="urT-OZ-LXv"/>
+                            <constraint firstItem="fSs-by-PN4" firstAttribute="top" secondItem="jte-We-k7c" secondAttribute="bottom" constant="50" id="ylU-8G-nvb"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" title="Gateway" id="SuR-By-ib7">
+                        <barButtonItem key="rightBarButtonItem" image="ResourceExit" id="S7O-fw-4OT">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            <connections>
+                                <action selector="exitButtonClicked:" destination="v1Y-JU-ghZ" id="kYY-gS-Rro"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                    <connections>
+                        <outlet property="acsModeTableView" destination="fVv-Jr-fwe" id="SLN-wF-fIP"/>
+                        <outlet property="activityIndicator" destination="jEM-OB-Frs" id="vCw-zX-m9O"/>
+                        <outlet property="emptyResourceImageView" destination="qeA-Ck-j1u" id="xg7-1L-gbR"/>
+                        <outlet property="emptyResourceLabel" destination="iYp-n0-3JW" id="Bsu-FX-Qxx"/>
+                        <outlet property="emptyResourceView" destination="fSs-by-PN4" id="YfI-9s-PmN"/>
+                        <outlet property="emptyViewTopConstraint" destination="ylU-8G-nvb" id="KNz-Sw-UmL"/>
+                        <outlet property="messageLabel" destination="hhP-By-cX0" id="JdZ-pk-JNL"/>
+                        <outlet property="messageView" destination="BGN-X3-l8M" id="KbK-FX-eKE"/>
+                        <outlet property="messageViewTopConstraint" destination="jIJ-bT-9O4" id="7Mq-be-v6q"/>
+                        <outlet property="resourceTableView" destination="lt6-TN-CBy" id="co6-VW-c8N"/>
+                        <outlet property="resourceViewTopConstraint" destination="WhV-ye-ZlA" id="70s-di-07h"/>
+                        <outlet property="statusImageView" destination="4qi-ej-DYj" id="OPr-Nl-YzP"/>
+                        <outlet property="statusLabel" destination="FFN-Tu-ZTR" id="ntl-gw-bwo"/>
+                        <outlet property="vpnEnableSwitch" destination="tih-jI-rGn" id="idl-cR-f8x"/>
+                        <segue destination="ixp-zo-wwn" kind="show" identifier="ResourceToSubResource" id="PDU-he-Ld0"/>
+                        <segue destination="EyZ-YP-cnm" kind="show" identifier="ResourceToCustomDesktop" id="ztu-Kd-80v"/>
+                        <segue destination="RPI-UI-YjC" kind="presentation" identifier="ResourceToAccessModeSelect" modalPresentationStyle="fullScreen" id="5T7-PF-nT2"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="FEY-bC-a3K" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="-1018.4" y="3813.6431784107949"/>
+        </scene>
+        <!--ANTabBarController-->
+        <scene sceneID="fKa-RZ-Ufs">
+            <objects>
+                <tabBarController title="ANTabBarController" id="LZd-Ei-vmr" customClass="ANTabBarController" sceneMemberID="viewController">
+                    <tabBar key="tabBar" contentMode="scaleToFill" id="ALn-CL-2Tp">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="49"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                    </tabBar>
+                    <connections>
+                        <segue destination="zh2-KR-niN" kind="relationship" relationship="viewControllers" id="KzF-KZ-2kZ"/>
+                        <segue destination="NBi-af-Ul6" kind="relationship" relationship="viewControllers" id="S0o-0Y-HuX"/>
+                        <segue destination="ji1-Yh-QLz" kind="relationship" relationship="viewControllers" id="Q0y-GY-mgF"/>
+                    </connections>
+                </tabBarController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="DVr-0R-XF3" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="118" y="2168"/>
+        </scene>
+        <!--LoginNavigation-->
+        <scene sceneID="Xnm-pw-ikw">
+            <objects>
+                <navigationController title="LoginNavigation" automaticallyAdjustsScrollViewInsets="NO" id="nnp-7I-qjc" sceneMemberID="viewController">
+                    <toolbarItems/>
+                    <navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="97A-SE-cgY">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <color key="barTintColor" red="0.0" green="0.86274509803921573" blue="0.3529411764705882" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <textAttributes key="titleTextAttributes">
+                            <fontDescription key="fontDescription" type="boldSystem" pointSize="18"/>
+                            <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        </textAttributes>
+                    </navigationBar>
+                    <nil name="viewControllers"/>
+                    <connections>
+                        <segue destination="b5l-8Z-fX3" kind="relationship" relationship="rootViewController" id="i7q-E7-SYr"/>
+                    </connections>
+                </navigationController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="wjZ-Tq-ACH" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="1924" y="1807"/>
+        </scene>
+        <!--Gateway-->
+        <scene sceneID="zRt-jZ-TLQ">
+            <objects>
+                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="zh2-KR-niN" sceneMemberID="viewController">
+                    <tabBarItem key="tabBarItem" title="Gateway" image="ResourceGatewayUnselected" selectedImage="ResourceGatewaySelected" id="M5q-8a-7xR"/>
+                    <toolbarItems/>
+                    <navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="YkX-q2-1AP">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        <color key="barTintColor" red="0.0" green="0.86274509803921573" blue="0.3529411764705882" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <textAttributes key="titleTextAttributes">
+                            <fontDescription key="fontDescription" type="boldSystem" pointSize="18"/>
+                            <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        </textAttributes>
+                    </navigationBar>
+                    <nil name="viewControllers"/>
+                    <connections>
+                        <segue destination="v1Y-JU-ghZ" kind="relationship" relationship="rootViewController" id="Yzh-jw-MTk"/>
+                    </connections>
+                </navigationController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="oWu-Pm-D4a" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="-1018.4" y="3026.5367316341831"/>
+        </scene>
+        <!--Status-->
+        <scene sceneID="1Yn-DC-CWm">
+            <objects>
+                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="NBi-af-Ul6" sceneMemberID="viewController">
+                    <tabBarItem key="tabBarItem" title="Status" image="ResourceStatusUnselected" selectedImage="ResourceStatusSelected" id="0rx-RB-iIc"/>
+                    <toolbarItems/>
+                    <navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="pIg-vb-CbM">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <color key="barTintColor" red="0.0" green="0.86274509803921573" blue="0.3529411764705882" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <textAttributes key="titleTextAttributes">
+                            <fontDescription key="fontDescription" type="boldSystem" pointSize="18"/>
+                            <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        </textAttributes>
+                    </navigationBar>
+                    <nil name="viewControllers"/>
+                    <connections>
+                        <segue destination="r5T-k1-WRt" kind="relationship" relationship="rootViewController" id="QPO-dA-4ed"/>
+                    </connections>
+                </navigationController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="GQg-Rn-hev" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="117.59999999999999" y="3026.5367316341831"/>
+        </scene>
+        <!--Status-->
+        <scene sceneID="LFl-be-CdD">
+            <objects>
+                <tableViewController id="r5T-k1-WRt" customClass="StatusViewController" sceneMemberID="viewController">
+                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" bounces="NO" dataMode="static" style="grouped" separatorStyle="default" allowsSelection="NO" rowHeight="44" sectionHeaderHeight="40" sectionFooterHeight="1" id="Qvp-QE-kvM">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <color key="separatorColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="calibratedRGB"/>
+                        <sections>
+                            <tableViewSection headerTitle="CONNECTION INFO" id="YG5-K0-czK">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="RaH-oW-4eo">
+                                        <rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="RaH-oW-4eo" id="lQa-DO-3OA">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="State" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hbN-yy-oxI">
+                                                    <rect key="frame" x="23" y="11.5" width="41.5" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pOD-Lz-clG">
+                                                    <rect key="frame" x="352" y="22" width="0.0" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="hbN-yy-oxI" secondAttribute="trailingMargin" id="5Gg-YQ-Rlt"/>
+                                                <constraint firstItem="hbN-yy-oxI" firstAttribute="leading" secondItem="lQa-DO-3OA" secondAttribute="leadingMargin" constant="7" id="Jpu-tP-gw8"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="pOD-Lz-clG" secondAttribute="trailing" constant="7" id="KSW-dh-9ev"/>
+                                                <constraint firstItem="pOD-Lz-clG" firstAttribute="centerY" secondItem="lQa-DO-3OA" secondAttribute="centerY" id="eEd-bU-hmg"/>
+                                                <constraint firstItem="pOD-Lz-clG" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="lQa-DO-3OA" secondAttribute="leadingMargin" id="nsH-55-R5N"/>
+                                                <constraint firstItem="hbN-yy-oxI" firstAttribute="centerY" secondItem="lQa-DO-3OA" secondAttribute="centerY" id="u7h-S6-Vyj"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="mTz-aC-JEX">
+                                        <rect key="frame" x="0.0" y="99.5" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="mTz-aC-JEX" id="Vng-j3-UH5">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Server" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mlq-pq-j6g">
+                                                    <rect key="frame" x="23" y="11.5" width="51.5" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="feC-60-gST">
+                                                    <rect key="frame" x="352" y="22" width="0.0" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="mlq-pq-j6g" firstAttribute="leading" secondItem="Vng-j3-UH5" secondAttribute="leadingMargin" constant="7" id="PfG-de-SmE"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="feC-60-gST" secondAttribute="trailing" constant="7" id="cQI-Sf-9lQ"/>
+                                                <constraint firstItem="feC-60-gST" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Vng-j3-UH5" secondAttribute="leadingMargin" id="naJ-tN-4dx"/>
+                                                <constraint firstItem="feC-60-gST" firstAttribute="centerY" secondItem="Vng-j3-UH5" secondAttribute="centerY" id="rr3-kv-n4x"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="mlq-pq-j6g" secondAttribute="trailingMargin" id="shQ-Su-Q4j"/>
+                                                <constraint firstItem="mlq-pq-j6g" firstAttribute="centerY" secondItem="Vng-j3-UH5" secondAttribute="centerY" id="zL3-20-u5f"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="Egg-NT-aro">
+                                        <rect key="frame" x="0.0" y="143.5" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Egg-NT-aro" id="kkh-XZ-yBK">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="IP Address" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="IOa-mi-PjO">
+                                                    <rect key="frame" x="23" y="11.5" width="84" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Qof-NW-hNB">
+                                                    <rect key="frame" x="352" y="22" width="0.0" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="IOa-mi-PjO" firstAttribute="leading" secondItem="kkh-XZ-yBK" secondAttribute="leadingMargin" constant="7" id="0wh-AT-G8p"/>
+                                                <constraint firstItem="Qof-NW-hNB" firstAttribute="centerY" secondItem="kkh-XZ-yBK" secondAttribute="centerY" id="Q6M-Ol-qae"/>
+                                                <constraint firstItem="Qof-NW-hNB" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="kkh-XZ-yBK" secondAttribute="leadingMargin" id="QZ0-PA-ewi"/>
+                                                <constraint firstItem="IOa-mi-PjO" firstAttribute="centerY" secondItem="kkh-XZ-yBK" secondAttribute="centerY" id="hJv-Gj-lpT"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="Qof-NW-hNB" secondAttribute="trailing" constant="7" id="lMe-nl-TDV"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="IOa-mi-PjO" secondAttribute="trailingMargin" id="tPy-f4-LAq"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="39e-aA-bUj">
+                                        <rect key="frame" x="0.0" y="187.5" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="39e-aA-bUj" id="G1w-a4-dGa">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Time Connected" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mLt-BF-kGM">
+                                                    <rect key="frame" x="23" y="11.5" width="129" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OUx-0G-8Uc">
+                                                    <rect key="frame" x="352" y="22" width="0.0" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="trailingMargin" secondItem="OUx-0G-8Uc" secondAttribute="trailing" constant="7" id="7K6-Pc-pcS"/>
+                                                <constraint firstItem="mLt-BF-kGM" firstAttribute="leading" secondItem="G1w-a4-dGa" secondAttribute="leadingMargin" constant="7" id="B96-n2-HEe"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="mLt-BF-kGM" secondAttribute="trailingMargin" id="Eto-rR-7st"/>
+                                                <constraint firstItem="mLt-BF-kGM" firstAttribute="centerY" secondItem="G1w-a4-dGa" secondAttribute="centerY" id="LV8-V1-M53"/>
+                                                <constraint firstItem="OUx-0G-8Uc" firstAttribute="centerY" secondItem="G1w-a4-dGa" secondAttribute="centerY" id="OKK-xc-yRZ"/>
+                                                <constraint firstItem="OUx-0G-8Uc" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="G1w-a4-dGa" secondAttribute="leadingMargin" id="sM6-oA-kWt"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="TOd-p6-GdM">
+                                        <rect key="frame" x="0.0" y="231.5" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="TOd-p6-GdM" id="UwS-Ts-KIN">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="MTU" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lao-gf-Bxh">
+                                                    <rect key="frame" x="23" y="11.5" width="38" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="f8E-ob-VIF">
+                                                    <rect key="frame" x="352" y="22" width="0.0" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="f8E-ob-VIF" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="UwS-Ts-KIN" secondAttribute="leadingMargin" id="412-vT-64k"/>
+                                                <constraint firstItem="lao-gf-Bxh" firstAttribute="leading" secondItem="UwS-Ts-KIN" secondAttribute="leadingMargin" constant="7" id="Ddw-Le-yZo"/>
+                                                <constraint firstItem="f8E-ob-VIF" firstAttribute="centerY" secondItem="UwS-Ts-KIN" secondAttribute="centerY" id="Ggr-mN-uQY"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="f8E-ob-VIF" secondAttribute="trailing" constant="7" id="MjU-x4-VXC"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="lao-gf-Bxh" secondAttribute="trailingMargin" id="Pwa-mT-4Ue"/>
+                                                <constraint firstItem="lao-gf-Bxh" firstAttribute="centerY" secondItem="UwS-Ts-KIN" secondAttribute="centerY" id="aQl-An-gCP"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="hcB-x9-YAW">
+                                        <rect key="frame" x="0.0" y="275.5" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="hcB-x9-YAW" id="04e-Md-7Gv">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Mode" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sVN-85-RxM">
+                                                    <rect key="frame" x="23" y="11.5" width="44.5" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9vS-xT-Gre">
+                                                    <rect key="frame" x="352" y="22" width="0.0" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="9vS-xT-Gre" firstAttribute="centerY" secondItem="04e-Md-7Gv" secondAttribute="centerY" id="LPo-8X-vkX"/>
+                                                <constraint firstItem="9vS-xT-Gre" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="04e-Md-7Gv" secondAttribute="leadingMargin" id="Ojy-K2-qTn"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="9vS-xT-Gre" secondAttribute="trailing" constant="7" id="RMn-7x-L1c"/>
+                                                <constraint firstItem="sVN-85-RxM" firstAttribute="leading" secondItem="04e-Md-7Gv" secondAttribute="leadingMargin" constant="7" id="mfT-Sg-EJU"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="sVN-85-RxM" secondAttribute="trailingMargin" id="npn-ib-HTD"/>
+                                                <constraint firstItem="sVN-85-RxM" firstAttribute="centerY" secondItem="04e-Md-7Gv" secondAttribute="centerY" id="pZk-Se-LzR"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                            <tableViewSection headerTitle="DNS" id="8xO-lB-ku6">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" misplaced="YES" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="qch-Ve-xe7">
+                                        <rect key="frame" x="0.0" y="358.5" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="qch-Ve-xe7" id="zFH-V6-01F">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" misplaced="YES" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="5DJ-Bq-YZo">
+                                        <rect key="frame" x="0.0" y="358.50000011920929" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="5DJ-Bq-YZo" id="oX0-r4-gPf">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" misplaced="YES" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="QhV-lm-ceg">
+                                        <rect key="frame" x="0.0" y="358.50000023841858" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="QhV-lm-ceg" id="y2q-OD-BmZ">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" misplaced="YES" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="uum-8j-kZY">
+                                        <rect key="frame" x="0.0" y="358.50000035762787" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="uum-8j-kZY" id="gVA-zf-h0n">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" misplaced="YES" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="89z-E0-5d8">
+                                        <rect key="frame" x="0.0" y="358.50000047683716" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="89z-E0-5d8" id="TTJ-iL-yIh">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" misplaced="YES" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="dIM-zf-loR">
+                                        <rect key="frame" x="0.0" y="358.50000059604645" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="dIM-zf-loR" id="jyw-Mi-dPO">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" misplaced="YES" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="zn7-pU-xVV">
+                                        <rect key="frame" x="0.0" y="358.50000071525574" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="zn7-pU-xVV" id="k7l-UU-3MB">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="yrH-pG-S25">
+                                        <rect key="frame" x="0.0" y="358.50000083446503" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="yrH-pG-S25" id="JJN-dY-S6A">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="o30-vo-oYa">
+                                        <rect key="frame" x="0.0" y="358.50000095367432" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="o30-vo-oYa" id="hYh-3E-9Jq">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="OHe-MV-nB0">
+                                        <rect key="frame" x="0.0" y="358.50000107288361" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="OHe-MV-nB0" id="OsG-4x-URI">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="3E9-Hj-fyh">
+                                        <rect key="frame" x="0.0" y="358.5000011920929" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="3E9-Hj-fyh" id="uvl-qn-wsl">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="jhR-2r-Pqv">
+                                        <rect key="frame" x="0.0" y="358.50000131130219" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="jhR-2r-Pqv" id="Ww8-ky-8u0">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="nbI-cf-H3E">
+                                        <rect key="frame" x="0.0" y="358.50000143051147" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="nbI-cf-H3E" id="8im-TO-xSS">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="Efh-d8-21D">
+                                        <rect key="frame" x="0.0" y="358.50000154972076" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Efh-d8-21D" id="3a2-nE-WeG">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="hbR-qJ-Etk">
+                                        <rect key="frame" x="0.0" y="358.50000166893005" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="hbR-qJ-Etk" id="CLu-VT-f0e">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="T1n-P4-wfV">
+                                        <rect key="frame" x="0.0" y="358.50000178813934" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="T1n-P4-wfV" id="YzM-Gf-aiQ">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="y30-0k-ufQ">
+                                        <rect key="frame" x="0.0" y="358.50000190734863" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="y30-0k-ufQ" id="6xK-bV-wwg">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                            <tableViewSection headerTitle="STATISTICS" id="Xl0-cU-DDR">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="tCL-SZ-Y4Z">
+                                        <rect key="frame" x="0.0" y="397.50000202655792" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="tCL-SZ-Y4Z" id="H1x-rp-QzS">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Data Sent" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Wlj-g6-WuJ">
+                                                    <rect key="frame" x="23" y="11.5" width="77" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XEA-WC-w7P">
+                                                    <rect key="frame" x="352" y="22" width="0.0" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="XEA-WC-w7P" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="H1x-rp-QzS" secondAttribute="leadingMargin" id="5BD-7Q-gM3"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="XEA-WC-w7P" secondAttribute="trailing" constant="7" id="5qa-Zz-nPq"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="Wlj-g6-WuJ" secondAttribute="trailingMargin" id="BM3-IW-Vdh"/>
+                                                <constraint firstItem="XEA-WC-w7P" firstAttribute="centerY" secondItem="H1x-rp-QzS" secondAttribute="centerY" id="HCm-oq-2PH"/>
+                                                <constraint firstItem="Wlj-g6-WuJ" firstAttribute="centerY" secondItem="H1x-rp-QzS" secondAttribute="centerY" id="S4X-Ze-565"/>
+                                                <constraint firstItem="Wlj-g6-WuJ" firstAttribute="leading" secondItem="H1x-rp-QzS" secondAttribute="leadingMargin" constant="7" id="SMW-H8-fJW"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="kyt-Sv-rs5">
+                                        <rect key="frame" x="0.0" y="441.50000202655792" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="kyt-Sv-rs5" id="d96-V6-mlc">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Data Received" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="oet-ex-ZoA">
+                                                    <rect key="frame" x="23" y="11.5" width="112" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3fD-rX-Z83">
+                                                    <rect key="frame" x="352" y="22" width="0.0" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="3fD-rX-Z83" firstAttribute="centerY" secondItem="d96-V6-mlc" secondAttribute="centerY" id="1Xw-NF-7hp"/>
+                                                <constraint firstItem="oet-ex-ZoA" firstAttribute="centerY" secondItem="d96-V6-mlc" secondAttribute="centerY" id="887-Ni-xbA"/>
+                                                <constraint firstItem="3fD-rX-Z83" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="d96-V6-mlc" secondAttribute="leadingMargin" id="SIf-G1-j1J"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="oet-ex-ZoA" secondAttribute="trailingMargin" id="Wzf-GW-D5h"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="3fD-rX-Z83" secondAttribute="trailing" constant="7" id="f1E-Mx-W2R"/>
+                                                <constraint firstItem="oet-ex-ZoA" firstAttribute="leading" secondItem="d96-V6-mlc" secondAttribute="leadingMargin" constant="7" id="qg3-lx-yi8"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                        </sections>
+                        <connections>
+                            <outlet property="dataSource" destination="r5T-k1-WRt" id="pdF-sb-uXw"/>
+                            <outlet property="delegate" destination="r5T-k1-WRt" id="UuC-Ac-APz"/>
+                        </connections>
+                    </tableView>
+                    <navigationItem key="navigationItem" title="Status" id="Ewy-ma-UbL"/>
+                    <connections>
+                        <outlet property="dataReceivedLabel" destination="3fD-rX-Z83" id="NR3-O1-f5U"/>
+                        <outlet property="dataSentLabel" destination="XEA-WC-w7P" id="x9M-eN-H1Y"/>
+                        <outlet property="ipAddressLabel" destination="Qof-NW-hNB" id="f3w-bW-NBW"/>
+                        <outlet property="modeLabel" destination="9vS-xT-Gre" id="xtl-Kh-8pl"/>
+                        <outlet property="mtuLabel" destination="f8E-ob-VIF" id="9xS-9h-SgB"/>
+                        <outlet property="serverLabel" destination="feC-60-gST" id="8e1-gc-HfI"/>
+                        <outlet property="stateLabel" destination="pOD-Lz-clG" id="els-Ay-HiT"/>
+                        <outlet property="timeLabel" destination="OUx-0G-8Uc" id="EDl-pf-t3c"/>
+                    </connections>
+                </tableViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="QvO-OP-14y" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="117.59999999999999" y="3813.6431784107949"/>
+        </scene>
+        <!--Settings-->
+        <scene sceneID="ebE-B2-7Pa">
+            <objects>
+                <tableViewController id="kNN-aP-IXV" customClass="SettingsViewController" sceneMemberID="viewController">
+                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" bounces="NO" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="1" sectionFooterHeight="1" id="GmA-Kc-OCx">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
+                        <color key="separatorColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <sections>
+                            <tableViewSection id="PlT-e5-bDi">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="lJo-Ae-HjF">
+                                        <rect key="frame" x="0.0" y="1" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="lJo-Ae-HjF" id="hGY-F4-NCT">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Username" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="KtQ-Qv-Lo0">
+                                                    <rect key="frame" x="23" y="11.5" width="80.5" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7NZ-oF-ooj">
+                                                    <rect key="frame" x="352" y="22" width="0.0" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="KtQ-Qv-Lo0" firstAttribute="leading" secondItem="hGY-F4-NCT" secondAttribute="leadingMargin" constant="7" id="ETS-Z6-hhh"/>
+                                                <constraint firstItem="7NZ-oF-ooj" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="hGY-F4-NCT" secondAttribute="leadingMargin" id="NdW-QW-uxn"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="7NZ-oF-ooj" secondAttribute="trailing" constant="7" id="jcD-cd-bGX"/>
+                                                <constraint firstItem="KtQ-Qv-Lo0" firstAttribute="centerY" secondItem="hGY-F4-NCT" secondAttribute="centerY" id="vST-qP-JjP"/>
+                                                <constraint firstItem="7NZ-oF-ooj" firstAttribute="centerY" secondItem="hGY-F4-NCT" secondAttribute="centerY" id="xf4-sm-pV1"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="KtQ-Qv-Lo0" secondAttribute="trailingMargin" id="ybu-jS-OC6"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="haL-xJ-ru1">
+                                        <rect key="frame" x="0.0" y="45" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="haL-xJ-ru1" id="uMc-1g-bZf">
+                                            <rect key="frame" x="0.0" y="0.0" width="348" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Password" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DXU-9a-S4o">
+                                                    <rect key="frame" x="23" y="11.5" width="76" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="DXU-9a-S4o" firstAttribute="leading" secondItem="uMc-1g-bZf" secondAttribute="leadingMargin" constant="7" id="HVb-Zv-sqm"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="DXU-9a-S4o" secondAttribute="trailingMargin" id="Q7M-M4-0ke"/>
+                                                <constraint firstItem="DXU-9a-S4o" firstAttribute="centerY" secondItem="uMc-1g-bZf" secondAttribute="centerY" id="nk0-oV-x9A"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                            <tableViewSection id="XyK-bc-y4a">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="20k-ei-0TV">
+                                        <rect key="frame" x="0.0" y="91" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="20k-ei-0TV" id="JRp-wI-728">
+                                            <rect key="frame" x="0.0" y="0.0" width="348" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Remote Desktop" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qNz-AI-x3B">
+                                                    <rect key="frame" x="23" y="12.5" width="130" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="qNz-AI-x3B" firstAttribute="leading" secondItem="JRp-wI-728" secondAttribute="leadingMargin" constant="7" id="Nyh-A9-jDZ"/>
+                                                <constraint firstItem="qNz-AI-x3B" firstAttribute="centerY" secondItem="JRp-wI-728" secondAttribute="centerY" constant="1" id="cQc-qb-Vj3"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="qNz-AI-x3B" secondAttribute="trailingMargin" id="lkN-n8-3bY"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                            <tableViewSection id="ep1-rJ-hIx">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="2pt-EB-Pge">
+                                        <rect key="frame" x="0.0" y="137" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="2pt-EB-Pge" id="m36-Jj-BAX">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Device ID" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tR4-hQ-XRC">
+                                                    <rect key="frame" x="23" y="11.5" width="110" height="21"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="110" id="4hM-Zp-h6t"/>
+                                                    </constraints>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="In1-of-yQS" customClass="ANCopyLabel">
+                                                    <rect key="frame" x="120" y="22" width="232" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="In1-of-yQS" firstAttribute="leading" secondItem="m36-Jj-BAX" secondAttribute="leading" constant="120" id="ADj-dU-rYV"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="In1-of-yQS" secondAttribute="trailing" constant="7" id="NWN-Zx-InT"/>
+                                                <constraint firstItem="tR4-hQ-XRC" firstAttribute="centerY" secondItem="m36-Jj-BAX" secondAttribute="centerY" id="Q2l-5a-6V7"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="In1-of-yQS" secondAttribute="trailing" constant="7" id="gVk-SV-uDh"/>
+                                                <constraint firstItem="tR4-hQ-XRC" firstAttribute="leading" secondItem="m36-Jj-BAX" secondAttribute="leadingMargin" constant="7" id="jOp-m4-za4"/>
+                                                <constraint firstItem="In1-of-yQS" firstAttribute="centerY" secondItem="m36-Jj-BAX" secondAttribute="centerY" id="mqI-PB-scY"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                            <tableViewSection id="Rpm-xC-Uzg">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="pIk-wc-0sv">
+                                        <rect key="frame" x="0.0" y="183" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="pIk-wc-0sv" id="SkF-EH-B3E">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="FaceID" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3M7-p1-f2w" userLabel="FaceID">
+                                                    <rect key="frame" x="23" y="11.5" width="110" height="21"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="110" id="h3p-25-zON"/>
+                                                    </constraints>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pXx-Wm-I5u" customClass="ANCopyLabel">
+                                                    <rect key="frame" x="120" y="22" width="232" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="RDB-GI-KFD">
+                                                    <rect key="frame" x="312" y="7" width="49" height="31"/>
+                                                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                                </switch>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="pXx-Wm-I5u" firstAttribute="leading" secondItem="SkF-EH-B3E" secondAttribute="leading" constant="120" id="7dR-Id-fif"/>
+                                                <constraint firstItem="3M7-p1-f2w" firstAttribute="leading" secondItem="SkF-EH-B3E" secondAttribute="leadingMargin" constant="7" id="QeK-ne-C2e"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="pXx-Wm-I5u" secondAttribute="trailing" constant="7" id="Xp7-5B-OJr"/>
+                                                <constraint firstItem="pXx-Wm-I5u" firstAttribute="centerY" secondItem="SkF-EH-B3E" secondAttribute="centerY" id="brV-vQ-yn1"/>
+                                                <constraint firstItem="3M7-p1-f2w" firstAttribute="centerY" secondItem="SkF-EH-B3E" secondAttribute="centerY" id="rKo-po-lbz"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="pXx-Wm-I5u" secondAttribute="trailing" constant="7" id="uBo-YD-fo3"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                            <tableViewSection id="Ji5-0k-Yc8">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="KyX-5T-x3H">
+                                        <rect key="frame" x="0.0" y="229" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KyX-5T-x3H" id="epP-Xr-tCZ">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Gesture login" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="AIf-cu-NLD" userLabel="Gesture login">
+                                                    <rect key="frame" x="23" y="11.5" width="180" height="21"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="180" id="prX-mL-QP5"/>
+                                                    </constraints>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iJs-xF-qM6" customClass="ANCopyLabel">
+                                                    <rect key="frame" x="120" y="22" width="232" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6vQ-1v-zsT">
+                                                    <rect key="frame" x="312" y="7" width="49" height="31"/>
+                                                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                                </switch>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="AIf-cu-NLD" firstAttribute="centerY" secondItem="epP-Xr-tCZ" secondAttribute="centerY" id="5Eo-ft-WNn"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="iJs-xF-qM6" secondAttribute="trailing" constant="7" id="NOE-hg-IqK"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="iJs-xF-qM6" secondAttribute="trailing" constant="7" id="QRM-36-581"/>
+                                                <constraint firstItem="AIf-cu-NLD" firstAttribute="leading" secondItem="epP-Xr-tCZ" secondAttribute="leadingMargin" constant="7" id="Yfc-CM-iZG"/>
+                                                <constraint firstItem="iJs-xF-qM6" firstAttribute="centerY" secondItem="epP-Xr-tCZ" secondAttribute="centerY" id="g70-0r-AEi"/>
+                                                <constraint firstItem="iJs-xF-qM6" firstAttribute="leading" secondItem="epP-Xr-tCZ" secondAttribute="leading" constant="120" id="mMo-pG-4a4"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                            <tableViewSection id="CBg-Nn-YPB">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="2la-JM-I6m">
+                                        <rect key="frame" x="0.0" y="183" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="2la-JM-I6m" id="fne-MG-6Rv">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Logout" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5Qf-YN-ltX">
+                                                    <rect key="frame" x="160" y="12" width="55" height="20"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="5Qf-YN-ltX" firstAttribute="centerX" secondItem="fne-MG-6Rv" secondAttribute="centerX" id="DOf-lL-tO3"/>
+                                                <constraint firstItem="5Qf-YN-ltX" firstAttribute="centerY" secondItem="fne-MG-6Rv" secondAttribute="centerY" id="IdE-Jj-Dlj"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                        </sections>
+                        <connections>
+                            <outlet property="dataSource" destination="kNN-aP-IXV" id="Kwh-42-7a1"/>
+                            <outlet property="delegate" destination="kNN-aP-IXV" id="BuM-Cl-TBO"/>
+                        </connections>
+                    </tableView>
+                    <navigationItem key="navigationItem" title="Settings" id="44I-4p-BZJ"/>
+                    <connections>
+                        <outlet property="deviceIDCell" destination="2pt-EB-Pge" id="v2i-Tf-yNa"/>
+                        <outlet property="deviceIDLabel" destination="In1-of-yQS" id="8aB-L6-Vtf"/>
+                        <outlet property="faceIDLable" destination="3M7-p1-f2w" id="aEP-SO-0df"/>
+                        <outlet property="faceIDSwitch" destination="RDB-GI-KFD" id="coa-c3-Pn9"/>
+                        <outlet property="gestureSwitch" destination="6vQ-1v-zsT" id="RJF-CM-XcM"/>
+                        <outlet property="passwordCell" destination="haL-xJ-ru1" id="vnk-nd-19F"/>
+                        <outlet property="usernameLabel" destination="7NZ-oF-ooj" id="U36-XH-nRB"/>
+                        <segue destination="MGw-hc-Bqe" kind="show" identifier="SettingsToChangePassword" id="bsi-4V-JG6"/>
+                        <segue destination="ths-LD-SZi" kind="show" identifier="SettingsToRemoteDesktop" id="WIg-WZ-5a5"/>
+                    </connections>
+                </tableViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="lB7-uT-NTe" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="1288.8" y="3813.6431784107949"/>
+        </scene>
+        <!--Remote Desktop-->
+        <scene sceneID="WoW-l4-2Fe">
+            <objects>
+                <tableViewController title="Remote Desktop" id="ths-LD-SZi" customClass="RemoteDesktopSettingsViewController" sceneMemberID="viewController">
+                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="PRC-v9-4lh">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="calibratedRGB"/>
+                        <sections>
+                            <tableViewSection id="RBy-MA-3Yx">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="ZsV-dQ-obU">
+                                        <rect key="frame" x="0.0" y="18" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ZsV-dQ-obU" id="bI2-DB-UhM">
+                                            <rect key="frame" x="0.0" y="0.0" width="348" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Audio Mode" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zJ0-qT-F6l">
+                                                    <rect key="frame" x="23" y="11.5" width="94" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Dyb-56-nYR">
+                                                    <rect key="frame" x="340" y="22" width="0.0" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="Dyb-56-nYR" firstAttribute="centerY" secondItem="bI2-DB-UhM" secondAttribute="centerY" id="0e6-7r-iZ5"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="zJ0-qT-F6l" secondAttribute="trailingMargin" id="5CT-2g-o27"/>
+                                                <constraint firstItem="Dyb-56-nYR" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="bI2-DB-UhM" secondAttribute="leadingMargin" id="BdG-GT-AEq"/>
+                                                <constraint firstItem="zJ0-qT-F6l" firstAttribute="centerY" secondItem="bI2-DB-UhM" secondAttribute="centerY" id="Mvf-Cp-jdt"/>
+                                                <constraint firstItem="Dyb-56-nYR" firstAttribute="trailing" secondItem="bI2-DB-UhM" secondAttribute="trailingMargin" id="buS-JU-Dwh"/>
+                                                <constraint firstItem="zJ0-qT-F6l" firstAttribute="leading" secondItem="bI2-DB-UhM" secondAttribute="leadingMargin" constant="7" id="wGa-nZ-mHP"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                            <tableViewSection headerTitle="" id="py7-w9-d3r">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="9Jw-UU-Ccz">
+                                        <rect key="frame" x="0.0" y="102" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="9Jw-UU-Ccz" id="pDo-CD-27p">
+                                            <rect key="frame" x="0.0" y="0.0" width="348" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Vendor" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BXu-8Q-X33">
+                                                    <rect key="frame" x="23" y="11.5" width="57" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="RXY-dP-obT">
+                                                    <rect key="frame" x="340" y="22" width="0.0" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="RXY-dP-obT" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="pDo-CD-27p" secondAttribute="leadingMargin" id="0qf-D9-Ez0"/>
+                                                <constraint firstItem="RXY-dP-obT" firstAttribute="centerY" secondItem="pDo-CD-27p" secondAttribute="centerY" id="F5J-yN-a1V"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="BXu-8Q-X33" secondAttribute="trailingMargin" id="UIf-gw-mqu"/>
+                                                <constraint firstItem="BXu-8Q-X33" firstAttribute="leading" secondItem="pDo-CD-27p" secondAttribute="leadingMargin" constant="7" id="iJx-Ar-GFa"/>
+                                                <constraint firstItem="RXY-dP-obT" firstAttribute="trailing" secondItem="pDo-CD-27p" secondAttribute="trailingMargin" id="rDP-xC-V9C"/>
+                                                <constraint firstItem="BXu-8Q-X33" firstAttribute="centerY" secondItem="pDo-CD-27p" secondAttribute="centerY" id="seA-b6-5oS"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                        </sections>
+                        <connections>
+                            <outlet property="dataSource" destination="ths-LD-SZi" id="YaT-n1-bEW"/>
+                            <outlet property="delegate" destination="ths-LD-SZi" id="2CJ-77-5Gg"/>
+                        </connections>
+                    </tableView>
+                    <connections>
+                        <outlet property="audioModeLabel" destination="Dyb-56-nYR" id="0Wd-8Q-Hqk"/>
+                        <outlet property="audioModelCell" destination="ZsV-dQ-obU" id="dwc-UM-z31"/>
+                        <outlet property="vendorCell" destination="9Jw-UU-Ccz" id="wAE-TC-uF1"/>
+                        <outlet property="vendorLabel" destination="RXY-dP-obT" id="M6Q-x5-PmZ"/>
+                    </connections>
+                </tableViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="RjJ-tL-UHT" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="2014" y="4590"/>
+        </scene>
+        <!--Change Password-->
+        <scene sceneID="KmO-tX-lcl">
+            <objects>
+                <tableViewController storyboardIdentifier="ChangePasswordViewControllerID" useStoryboardIdentifierAsRestorationIdentifier="YES" id="MGw-hc-Bqe" customClass="ChangePasswordViewController" sceneMemberID="viewController">
+                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" bounces="NO" dataMode="static" style="grouped" separatorStyle="default" allowsSelection="NO" rowHeight="66" sectionHeaderHeight="18" sectionFooterHeight="18" id="lON-LZ-doF">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="calibratedRGB"/>
+                        <color key="separatorColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="calibratedRGB"/>
+                        <sections>
+                            <tableViewSection id="QsC-jf-jh7">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="Dku-Kq-Q0S">
+                                        <rect key="frame" x="0.0" y="18" width="375" height="66"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Dku-Kq-Q0S" id="4WU-4e-kel">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="66"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="New Password" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="MyJ-Bk-1xO">
+                                                    <rect key="frame" x="47" y="0.0" width="320" height="65.5"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits" returnKeyType="next" secureTextEntry="YES"/>
+                                                    <connections>
+                                                        <outlet property="delegate" destination="MGw-hc-Bqe" id="Swq-iG-Prp"/>
+                                                    </connections>
+                                                </textField>
+                                                <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginPassword" translatesAutoresizingMaskIntoConstraints="NO" id="xPQ-N7-5il">
+                                                    <rect key="frame" x="23" y="25" width="16" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="height" constant="16" id="GTq-5e-ThX"/>
+                                                        <constraint firstAttribute="width" constant="16" id="jNZ-4a-Buc"/>
+                                                    </constraints>
+                                                </imageView>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="MyJ-Bk-1xO" firstAttribute="leading" secondItem="xPQ-N7-5il" secondAttribute="trailing" constant="8" id="0EI-AQ-k2a"/>
+                                                <constraint firstItem="MyJ-Bk-1xO" firstAttribute="top" secondItem="4WU-4e-kel" secondAttribute="top" id="4y8-D9-897"/>
+                                                <constraint firstItem="xPQ-N7-5il" firstAttribute="centerY" secondItem="4WU-4e-kel" secondAttribute="centerY" id="GC0-hn-TYo"/>
+                                                <constraint firstAttribute="bottom" secondItem="MyJ-Bk-1xO" secondAttribute="bottom" constant="0.5" id="KUU-I0-rTS"/>
+                                                <constraint firstItem="xPQ-N7-5il" firstAttribute="leading" secondItem="4WU-4e-kel" secondAttribute="leadingMargin" constant="7" id="Wa4-fF-h11"/>
+                                                <constraint firstAttribute="trailing" secondItem="MyJ-Bk-1xO" secondAttribute="trailing" constant="8" id="mX3-yB-PR5"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="RCt-Au-72G">
+                                        <rect key="frame" x="0.0" y="84" width="375" height="66"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="RCt-Au-72G" id="vx9-6q-Zvk">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="66"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Confirm New Password" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="LAE-e1-UaQ">
+                                                    <rect key="frame" x="47" y="0.0" width="320" height="65.5"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits" returnKeyType="done" secureTextEntry="YES"/>
+                                                    <connections>
+                                                        <outlet property="delegate" destination="MGw-hc-Bqe" id="vzZ-X2-tFR"/>
+                                                    </connections>
+                                                </textField>
+                                                <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginPassword" translatesAutoresizingMaskIntoConstraints="NO" id="FXV-tO-RYZ">
+                                                    <rect key="frame" x="23" y="25" width="16" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="16" id="N2Q-LG-2BZ"/>
+                                                        <constraint firstAttribute="height" constant="16" id="ZBV-Vv-Cua"/>
+                                                    </constraints>
+                                                </imageView>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="FXV-tO-RYZ" firstAttribute="leading" secondItem="vx9-6q-Zvk" secondAttribute="leadingMargin" constant="7" id="6V1-8t-2rG"/>
+                                                <constraint firstItem="LAE-e1-UaQ" firstAttribute="leading" secondItem="FXV-tO-RYZ" secondAttribute="trailing" constant="8" id="Ee0-Xj-FfF"/>
+                                                <constraint firstAttribute="bottom" secondItem="LAE-e1-UaQ" secondAttribute="bottom" constant="0.5" id="YM7-mg-j6Z"/>
+                                                <constraint firstAttribute="trailing" secondItem="LAE-e1-UaQ" secondAttribute="trailing" constant="8" id="aHS-pw-Diq"/>
+                                                <constraint firstItem="LAE-e1-UaQ" firstAttribute="top" secondItem="vx9-6q-Zvk" secondAttribute="top" id="ejq-mq-bHg"/>
+                                                <constraint firstItem="FXV-tO-RYZ" firstAttribute="centerY" secondItem="vx9-6q-Zvk" secondAttribute="centerY" id="shX-wW-jkR"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                        </sections>
+                        <connections>
+                            <outlet property="dataSource" destination="MGw-hc-Bqe" id="y1c-fZ-VoF"/>
+                            <outlet property="delegate" destination="MGw-hc-Bqe" id="bgQ-Ze-Csn"/>
+                        </connections>
+                    </tableView>
+                    <navigationItem key="navigationItem" title="Change Password" id="5ap-sa-C8K">
+                        <barButtonItem key="leftBarButtonItem" title="Cancel" id="uzA-KT-Dzt">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            <connections>
+                                <action selector="cancelLogin:" destination="MGw-hc-Bqe" id="qsV-nO-xZx"/>
+                            </connections>
+                        </barButtonItem>
+                        <barButtonItem key="rightBarButtonItem" title="Change" id="yYu-r2-zyv">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            <connections>
+                                <action selector="changeButtonClicked:" destination="MGw-hc-Bqe" id="ZL5-UD-Tab"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                    <connections>
+                        <outlet property="confirmPasswordTextField" destination="LAE-e1-UaQ" id="ye8-5T-j6D"/>
+                        <outlet property="passwordTextField" destination="MyJ-Bk-1xO" id="QPq-BS-WJe"/>
+                    </connections>
+                </tableViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="wYf-Pe-R1d" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="2204" y="3813.6431784107949"/>
+        </scene>
+        <!--Settings-->
+        <scene sceneID="Dg1-T5-lYa">
+            <objects>
+                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="ji1-Yh-QLz" sceneMemberID="viewController">
+                    <tabBarItem key="tabBarItem" title="Settings" image="ResourceSettingsUnselected" selectedImage="ResourceSettingsSelected" id="wPf-sp-tCf"/>
+                    <toolbarItems/>
+                    <navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="11d-Ho-0vl">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                        <color key="barTintColor" red="0.0" green="0.86274509803921573" blue="0.3529411764705882" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <textAttributes key="titleTextAttributes">
+                            <fontDescription key="fontDescription" type="boldSystem" pointSize="18"/>
+                            <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        </textAttributes>
+                    </navigationBar>
+                    <nil name="viewControllers"/>
+                    <connections>
+                        <segue destination="kNN-aP-IXV" kind="relationship" relationship="rootViewController" id="Iq3-dP-ekZ"/>
+                    </connections>
+                </navigationController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="7hS-TJ-kiS" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="1289" y="3027"/>
+        </scene>
+        <!--WebAuth-->
+        <scene sceneID="woL-bQ-uNE">
+            <objects>
+                <viewController storyboardIdentifier="WebAuthViewControllerID" id="wTa-nS-3rH" customClass="WebAuthViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="REt-Jk-8fG"/>
+                        <viewControllerLayoutGuide type="bottom" id="Lc3-Mo-Chl"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="tHL-gU-Ifv">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <webView contentMode="scaleToFill" scalesPageToFit="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5pc-jk-dd9">
+                                <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                                <color key="backgroundColor" red="0.36078431370000003" green="0.38823529410000002" blue="0.4039215686" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <connections>
+                                    <outlet property="delegate" destination="wTa-nS-3rH" id="b6k-ub-N7T"/>
+                                </connections>
+                            </webView>
+                            <activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="1rf-mF-zdP">
+                                <rect key="frame" x="177.5" y="301.5" width="20" height="20"/>
+                            </activityIndicatorView>
+                        </subviews>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                        <constraints>
+                            <constraint firstItem="5pc-jk-dd9" firstAttribute="top" secondItem="REt-Jk-8fG" secondAttribute="bottom" id="8Rx-eO-ZPw"/>
+                            <constraint firstItem="1rf-mF-zdP" firstAttribute="centerX" secondItem="tHL-gU-Ifv" secondAttribute="centerX" id="N1H-bf-8ch"/>
+                            <constraint firstItem="5pc-jk-dd9" firstAttribute="top" secondItem="REt-Jk-8fG" secondAttribute="bottom" id="aYi-xr-5yI"/>
+                            <constraint firstItem="Lc3-Mo-Chl" firstAttribute="top" secondItem="5pc-jk-dd9" secondAttribute="bottom" id="bKz-4y-EOF"/>
+                            <constraint firstAttribute="trailing" secondItem="5pc-jk-dd9" secondAttribute="trailing" id="bjx-61-DoN"/>
+                            <constraint firstItem="1rf-mF-zdP" firstAttribute="centerY" secondItem="tHL-gU-Ifv" secondAttribute="centerY" id="iKO-dz-jHH"/>
+                            <constraint firstItem="5pc-jk-dd9" firstAttribute="leading" secondItem="tHL-gU-Ifv" secondAttribute="leading" id="rbM-ZI-BLl"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" title="WebAuth" id="Ndw-U2-Kyh">
+                        <barButtonItem key="leftBarButtonItem" title="Close" id="Aa6-VI-DlU">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            <connections>
+                                <action selector="cancelButtonClicked:" destination="wTa-nS-3rH" id="yBz-xC-iY0"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                    <connections>
+                        <outlet property="activityIndicator" destination="1rf-mF-zdP" id="x7w-WK-66f"/>
+                        <outlet property="webView" destination="5pc-jk-dd9" id="HmM-EV-oNH"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="CgL-Ao-Ib1" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="5440.8000000000002" y="1806.7466266866568"/>
+        </scene>
+        <!--Web View Controller-->
+        <scene sceneID="fvV-Ct-MEk">
+            <objects>
+                <viewController storyboardIdentifier="webViewController" id="Pj0-zq-9zu" customClass="ANWebViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="tCf-tr-Dak"/>
+                        <viewControllerLayoutGuide type="bottom" id="vDl-no-dbd"/>
+                    </layoutGuides>
+                    <view key="view" multipleTouchEnabled="YES" contentMode="scaleToFill" id="7Bc-Q5-I0g">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                        <subviews>
+                            <webView contentMode="scaleToFill" scalesPageToFit="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kwA-oW-glo">
+                                <rect key="frame" x="0.0" y="44" width="375" height="579"/>
+                            </webView>
+                            <toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" translucent="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qTD-pI-Mvx">
+                                <rect key="frame" x="0.0" y="623" width="375" height="44"/>
+                                <items>
+                                    <barButtonItem width="11" style="plain" systemItem="fixedSpace" id="dN1-9x-6Cp"/>
+                                    <barButtonItem image="browserBack.png" style="plain" id="4Ly-aa-L2c">
+                                        <inset key="imageInsets" minX="0.0" minY="2.5" maxX="-1" maxY="-2"/>
+                                        <connections>
+                                            <action selector="goBack:" destination="Pj0-zq-9zu" id="b8I-cV-Tdw"/>
+                                        </connections>
+                                    </barButtonItem>
+                                    <barButtonItem style="plain" systemItem="flexibleSpace" id="CWi-b2-9Im"/>
+                                    <barButtonItem image="browserForward.png" style="plain" id="hhs-TN-Vsn">
+                                        <inset key="imageInsets" minX="0.0" minY="2.5" maxX="-1" maxY="-2"/>
+                                        <connections>
+                                            <action selector="goForward:" destination="Pj0-zq-9zu" id="jFk-JM-9hJ"/>
+                                        </connections>
+                                    </barButtonItem>
+                                    <barButtonItem style="plain" systemItem="flexibleSpace" id="hT9-jC-VfJ"/>
+                                    <barButtonItem image="NavTab.png" style="plain" id="FbZ-aN-cuc">
+                                        <inset key="imageInsets" minX="0.0" minY="3" maxX="0.0" maxY="-3"/>
+                                        <connections>
+                                            <action selector="openExposeController:" destination="Pj0-zq-9zu" id="zaG-Dn-2sd"/>
+                                        </connections>
+                                    </barButtonItem>
+                                    <barButtonItem width="9" style="plain" systemItem="fixedSpace" id="OaZ-BO-Gge"/>
+                                </items>
+                            </toolbar>
+                            <navigationBar contentMode="scaleToFill" translucent="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bYV-bn-kYy">
+                                <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                <color key="backgroundColor" red="0.0" green="0.86274509803921573" blue="0.3529411764705882" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <color key="tintColor" red="0.0" green="0.86274509803921573" blue="0.3529411764705882" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <color key="barTintColor" red="0.0" green="0.86274509803921573" blue="0.3529411764705882" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <textAttributes key="titleTextAttributes">
+                                    <fontDescription key="fontDescription" type="boldSystem" pointSize="18"/>
+                                    <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                </textAttributes>
+                                <items>
+                                    <navigationItem id="uEA-in-mD0"/>
+                                </items>
+                            </navigationBar>
+                        </subviews>
+                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <constraints>
+                            <constraint firstItem="bYV-bn-kYy" firstAttribute="bottom" secondItem="kwA-oW-glo" secondAttribute="top" id="7cn-gd-edD"/>
+                            <constraint firstItem="bYV-bn-kYy" firstAttribute="leading" secondItem="qTD-pI-Mvx" secondAttribute="leading" id="7v1-xI-Eif"/>
+                            <constraint firstItem="bYV-bn-kYy" firstAttribute="trailing" secondItem="qTD-pI-Mvx" secondAttribute="trailing" id="Rlr-9h-V6B"/>
+                            <constraint firstItem="bYV-bn-kYy" firstAttribute="top" secondItem="tCf-tr-Dak" secondAttribute="bottom" symbolic="YES" id="XLr-zv-1qm"/>
+                            <constraint firstItem="bYV-bn-kYy" firstAttribute="leading" secondItem="7Bc-Q5-I0g" secondAttribute="leading" id="aS6-Lc-PrJ"/>
+                            <constraint firstItem="bYV-bn-kYy" firstAttribute="leading" secondItem="kwA-oW-glo" secondAttribute="leading" id="aab-Ud-HO3"/>
+                            <constraint firstAttribute="trailing" secondItem="bYV-bn-kYy" secondAttribute="trailing" id="cdc-Rb-EMY"/>
+                            <constraint firstAttribute="bottom" secondItem="qTD-pI-Mvx" secondAttribute="bottom" id="clj-1y-cwr"/>
+                            <constraint firstItem="bYV-bn-kYy" firstAttribute="trailing" secondItem="kwA-oW-glo" secondAttribute="trailing" id="oOg-QS-8Dh"/>
+                            <constraint firstItem="qTD-pI-Mvx" firstAttribute="bottom" secondItem="kwA-oW-glo" secondAttribute="bottom" constant="44" id="oXd-g5-AeC"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" id="rht-pr-CKf"/>
+                    <connections>
+                        <outlet property="btnBack" destination="4Ly-aa-L2c" id="h1e-Wt-ffj"/>
+                        <outlet property="btnForward" destination="hhs-TN-Vsn" id="q6E-hA-tKv"/>
+                        <outlet property="btnOpenExpose" destination="FbZ-aN-cuc" id="Hqx-pm-HgQ"/>
+                        <outlet property="toolbar" destination="qTD-pI-Mvx" id="VfK-ED-aT3"/>
+                        <outlet property="webview" destination="kwA-oW-glo" id="8qk-Sq-vJG"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="Sfq-sT-cmb" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="-1876" y="3814"/>
+        </scene>
+        <!--Navigation Controller-->
+        <scene sceneID="5Hy-oP-LZV">
+            <objects>
+                <navigationController automaticallyAdjustsScrollViewInsets="NO" modalPresentationStyle="fullScreen" id="l9d-Rt-vCd" sceneMemberID="viewController">
+                    <toolbarItems/>
+                    <navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="nKi-CN-vD5">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        <color key="barTintColor" red="0.0" green="0.86274509803921573" blue="0.3529411764705882" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    </navigationBar>
+                    <nil name="viewControllers"/>
+                    <connections>
+                        <segue destination="ge6-AP-0um" kind="relationship" relationship="rootViewController" id="5Ga-N9-rMf"/>
+                    </connections>
+                </navigationController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="uO0-H0-LFh" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="4501.6000000000004" y="689.5052473763119"/>
+        </scene>
+        <!--Syfer Lock Login View Controller-->
+        <scene sceneID="A4g-We-toO">
+            <objects>
+                <viewController storyboardIdentifier="toSyferLockLogin" useStoryboardIdentifierAsRestorationIdentifier="YES" id="Own-rK-e3P" customClass="SyferLockLoginViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="Q4L-nK-dUR"/>
+                        <viewControllerLayoutGuide type="bottom" id="e8z-q7-em7"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="8E7-Lq-6o9">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ewU-UW-M2d">
+                                <rect key="frame" x="12" y="585" width="351" height="30"/>
+                                <color key="backgroundColor" red="0.0" green="0.86274509803921573" blue="0.3529411764705882" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <state key="normal" title="Login">
+                                    <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                </state>
+                                <connections>
+                                    <action selector="loginButtonTapped:" destination="Own-rK-e3P" eventType="touchUpInside" id="El5-VL-bqj"/>
+                                </connections>
+                            </button>
+                            <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" bounces="NO" scrollEnabled="NO" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="jwZ-uK-xoQ">
+                                <rect key="frame" x="16" y="8" width="343" height="527"/>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                                <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="qdB-nW-vwe">
+                                    <size key="itemSize" width="50" height="50"/>
+                                    <size key="headerReferenceSize" width="0.0" height="0.0"/>
+                                    <size key="footerReferenceSize" width="0.0" height="0.0"/>
+                                    <inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                </collectionViewFlowLayout>
+                                <cells/>
+                            </collectionView>
+                            <activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="Dhk-bB-ppf">
+                                <rect key="frame" x="177.5" y="590" width="20" height="20"/>
+                            </activityIndicatorView>
+                            <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="7cr-Yb-azO">
+                                <rect key="frame" x="136" y="543" width="227" height="34"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                <textInputTraits key="textInputTraits" keyboardType="numbersAndPunctuation" returnKeyType="done" secureTextEntry="YES"/>
+                            </textField>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Enter GridPIN" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mvS-kK-HYj">
+                                <rect key="frame" x="12" y="547" width="104" height="20.5"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                        </subviews>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <gestureRecognizers/>
+                        <constraints>
+                            <constraint firstItem="jwZ-uK-xoQ" firstAttribute="top" secondItem="Q4L-nK-dUR" secondAttribute="bottom" constant="8" id="5Bc-4N-rx6"/>
+                            <constraint firstItem="ewU-UW-M2d" firstAttribute="leading" secondItem="mvS-kK-HYj" secondAttribute="leading" id="5nw-dG-41u"/>
+                            <constraint firstItem="jwZ-uK-xoQ" firstAttribute="trailing" secondItem="8E7-Lq-6o9" secondAttribute="trailingMargin" id="6CZ-38-N6w"/>
+                            <constraint firstItem="ewU-UW-M2d" firstAttribute="trailing" secondItem="7cr-Yb-azO" secondAttribute="trailing" id="CAD-PO-ThV"/>
+                            <constraint firstItem="Dhk-bB-ppf" firstAttribute="centerX" secondItem="8E7-Lq-6o9" secondAttribute="centerX" id="E0q-zc-x4S"/>
+                            <constraint firstItem="Dhk-bB-ppf" firstAttribute="top" secondItem="7cr-Yb-azO" secondAttribute="bottom" constant="13" id="IKG-OE-w51"/>
+                            <constraint firstItem="e8z-q7-em7" firstAttribute="top" secondItem="ewU-UW-M2d" secondAttribute="bottom" constant="8" id="KXZ-NO-F1o"/>
+                            <constraint firstAttribute="trailingMargin" secondItem="ewU-UW-M2d" secondAttribute="trailing" constant="-4" id="SFf-vX-avp"/>
+                            <constraint firstItem="7cr-Yb-azO" firstAttribute="top" secondItem="jwZ-uK-xoQ" secondAttribute="bottom" constant="8" id="WLP-00-Mgp"/>
+                            <constraint firstItem="e8z-q7-em7" firstAttribute="top" secondItem="ewU-UW-M2d" secondAttribute="bottom" constant="8" id="WON-Hd-91m"/>
+                            <constraint firstItem="jwZ-uK-xoQ" firstAttribute="leading" secondItem="8E7-Lq-6o9" secondAttribute="leadingMargin" id="ZrN-Vz-Wg0"/>
+                            <constraint firstItem="mvS-kK-HYj" firstAttribute="top" secondItem="jwZ-uK-xoQ" secondAttribute="bottom" constant="12" id="giF-RB-M81"/>
+                            <constraint firstItem="ewU-UW-M2d" firstAttribute="leading" secondItem="8E7-Lq-6o9" secondAttribute="leadingMargin" constant="-4" id="j56-UP-Cgp"/>
+                            <constraint firstItem="ewU-UW-M2d" firstAttribute="top" secondItem="7cr-Yb-azO" secondAttribute="bottom" constant="8" id="kN1-8l-Tid"/>
+                            <constraint firstItem="7cr-Yb-azO" firstAttribute="leading" secondItem="mvS-kK-HYj" secondAttribute="trailing" constant="20" id="ltH-Dc-mh7"/>
+                            <constraint firstItem="7cr-Yb-azO" firstAttribute="top" secondItem="jwZ-uK-xoQ" secondAttribute="bottom" constant="8" id="rpr-MW-C4Z"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" id="H3u-cn-ZJs">
+                        <barButtonItem key="leftBarButtonItem" title="Cancel" id="axq-BG-27D">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                            <connections>
+                                <action selector="cancelButtonTapped:" destination="Own-rK-e3P" id="rLZ-IC-h0Z"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                    <connections>
+                        <outlet property="cancelBarButton" destination="axq-BG-27D" id="Bne-zL-7Wr"/>
+                        <outlet property="collectionView" destination="jwZ-uK-xoQ" id="m8a-dT-1Hw"/>
+                        <outlet property="gridPINLabel" destination="mvS-kK-HYj" id="f1e-c6-Seq"/>
+                        <outlet property="loginActivity" destination="Dhk-bB-ppf" id="4SP-qF-c3b"/>
+                        <outlet property="loginButton" destination="ewU-UW-M2d" id="eYg-Es-cZd"/>
+                        <outlet property="passwordTextField" destination="7cr-Yb-azO" id="bxL-cN-RA3"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="6mD-He-deo" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="5441" y="2624"/>
+        </scene>
+        <!--Navigation Controller-->
+        <scene sceneID="Z58-lh-SrP">
+            <objects>
+                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="AQs-MT-X4V" sceneMemberID="viewController">
+                    <toolbarItems/>
+                    <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" translucent="NO" id="nkF-48-VZm">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <color key="barTintColor" red="0.0" green="0.86274509803921573" blue="0.3529411764705882" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <textAttributes key="titleTextAttributes">
+                            <fontDescription key="fontDescription" type="boldSystem" pointSize="18"/>
+                            <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        </textAttributes>
+                    </navigationBar>
+                    <nil name="viewControllers"/>
+                    <connections>
+                        <segue destination="wTa-nS-3rH" kind="relationship" relationship="rootViewController" id="sz0-NX-E94"/>
+                    </connections>
+                </navigationController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="dvW-Gd-WfJ" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="4513" y="1807"/>
+        </scene>
+    </scenes>
+    <inferredMetricsTieBreakers>
+        <segue reference="bpD-LK-kUE"/>
+        <segue reference="Iyn-qq-u9T"/>
+    </inferredMetricsTieBreakers>
+    <resources>
+        <image name="CertificateDelete" width="14" height="14"/>
+        <image name="CertificateUnselected" width="22" height="22"/>
+        <image name="GatewayAppIcon" width="76" height="76"/>
+        <image name="GatewayDelete" width="17" height="17"/>
+        <image name="GatewayItemAdd" width="20" height="20"/>
+        <image name="GatewayItemMore" width="20" height="17"/>
+        <image name="LoginDropArrow" width="15.5" height="9"/>
+        <image name="LoginExit" width="17" height="17"/>
+        <image name="LoginMethodName" width="16" height="14.5"/>
+        <image name="LoginPassword" width="13.5" height="15"/>
+        <image name="LoginSelected" width="16" height="15"/>
+        <image name="LoginUsername" width="15" height="15"/>
+        <image name="NavTab.png" width="20" height="19"/>
+        <image name="ResourceConnectSuccess" width="16" height="16"/>
+        <image name="ResourceEmpty" width="128" height="102.5"/>
+        <image name="ResourceExit" width="20" height="21"/>
+        <image name="ResourceGatewaySelected" width="22" height="20"/>
+        <image name="ResourceGatewayUnselected" width="22" height="20"/>
+        <image name="ResourceSettingsSelected" width="22" height="22"/>
+        <image name="ResourceSettingsUnselected" width="22" height="22"/>
+        <image name="ResourceStatusSelected" width="22" height="22"/>
+        <image name="ResourceStatusUnselected" width="22" height="22"/>
+        <image name="browserBack.png" width="16" height="20"/>
+        <image name="browserForward.png" width="16" height="20"/>
+        <systemColor name="groupTableViewBackgroundColor">
+            <color red="0.94901960784313721" green="0.94901960784313721" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+        </systemColor>
+        <systemColor name="tableCellGroupedBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
+    </resources>
+</document>
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Base.lproj/Main.storyboard.zrt
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Base.lproj/Main.storyboard.zrt	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Base.lproj/Main.storyboard.zrt	(working copy)
@@ -0,0 +1,3604 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="idK-RG-cFM">
+    <device id="retina4_7" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--About-->
+        <scene sceneID="7GW-1c-C65">
+            <objects>
+                <viewController id="mDt-jA-kKK" customClass="AboutViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="yyK-sb-qiP"/>
+                        <viewControllerLayoutGuide type="bottom" id="f3i-hb-d4V"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="oK0-bX-MM2">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="GatewayAppIcon" translatesAutoresizingMaskIntoConstraints="NO" id="UYO-df-3Os">
+                                <rect key="frame" x="149.5" y="30" width="76" height="76"/>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="76" id="DTU-jS-aHj"/>
+                                    <constraint firstAttribute="width" constant="76" id="iYc-cD-iOI"/>
+                                </constraints>
+                            </imageView>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="MotionPro Plus" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="yV0-g6-UFN">
+                                <rect key="frame" x="130" y="116" width="115" height="21"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <tableView clipsSubviews="YES" contentMode="scaleToFill" bounces="NO" scrollEnabled="NO" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="66" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="jPq-XV-RSO">
+                                <rect key="frame" x="0.0" y="167" width="375" height="192"/>
+                                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="192" id="UZO-4R-Fbh"/>
+                                </constraints>
+                                <prototypes>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="VersionCellID" id="knd-UO-Qgh">
+                                        <rect key="frame" x="0.0" y="28" width="375" height="66"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="knd-UO-Qgh" id="eNV-yN-0ho">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="66"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Version" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TvU-VQ-ZFz">
+                                                    <rect key="frame" x="23" y="9" width="57" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2.0" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GxL-yD-Lwm">
+                                                    <rect key="frame" x="23" y="40" width="21" height="17"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <button opaque="NO" tag="2" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Fvq-rT-MUU">
+                                                    <rect key="frame" x="230" y="18" width="129" height="30"/>
+                                                    <state key="normal" title="Check for Updates">
+                                                        <color key="titleColor" red="0.89411764705882346" green="0.4392156862745098" blue="0.11372549019607843" alpha="1" colorSpace="calibratedRGB"/>
+                                                    </state>
+                                                </button>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="GxL-yD-Lwm" secondAttribute="trailingMargin" id="Cae-dG-aed"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="TvU-VQ-ZFz" secondAttribute="trailingMargin" id="NiB-R5-rN7"/>
+                                                <constraint firstItem="TvU-VQ-ZFz" firstAttribute="top" secondItem="eNV-yN-0ho" secondAttribute="topMargin" constant="-2" id="UNb-dT-B9f"/>
+                                                <constraint firstItem="GxL-yD-Lwm" firstAttribute="top" secondItem="TvU-VQ-ZFz" secondAttribute="bottom" constant="10" id="fjh-H6-KQL"/>
+                                                <constraint firstItem="Fvq-rT-MUU" firstAttribute="centerY" secondItem="eNV-yN-0ho" secondAttribute="centerY" id="hiu-yG-n3U"/>
+                                                <constraint firstItem="Fvq-rT-MUU" firstAttribute="trailing" secondItem="eNV-yN-0ho" secondAttribute="trailingMargin" id="iz2-WF-66m"/>
+                                                <constraint firstItem="GxL-yD-Lwm" firstAttribute="leading" secondItem="eNV-yN-0ho" secondAttribute="leadingMargin" constant="7" id="lCK-q6-Z6o"/>
+                                                <constraint firstItem="TvU-VQ-ZFz" firstAttribute="leading" secondItem="eNV-yN-0ho" secondAttribute="leadingMargin" constant="7" id="tMZ-46-NSR"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="CopyrightCellID" id="Gps-sY-MiT">
+                                        <rect key="frame" x="0.0" y="94" width="375" height="66"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Gps-sY-MiT" id="Xlc-az-jE4">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="66"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Copyright" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XgP-Wz-cuu">
+                                                    <rect key="frame" x="23" y="9" width="75" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="©2014-2017 Array Networks, Inc. All rights reserved." textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TeR-BG-hdj">
+                                                    <rect key="frame" x="23" y="38" width="341.5" height="17"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="XgP-Wz-cuu" firstAttribute="leading" secondItem="Xlc-az-jE4" secondAttribute="leadingMargin" constant="7" id="9ot-jp-oFq"/>
+                                                <constraint firstItem="TeR-BG-hdj" firstAttribute="leading" secondItem="Xlc-az-jE4" secondAttribute="leadingMargin" constant="7" id="LMY-ul-z2L"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="XgP-Wz-cuu" secondAttribute="trailingMargin" id="MlM-MA-0l7"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="TeR-BG-hdj" secondAttribute="trailingMargin" id="TE1-g6-gaJ"/>
+                                                <constraint firstItem="TeR-BG-hdj" firstAttribute="top" secondItem="XgP-Wz-cuu" secondAttribute="bottom" constant="8" id="qDp-nt-e90"/>
+                                                <constraint firstItem="XgP-Wz-cuu" firstAttribute="top" secondItem="Xlc-az-jE4" secondAttribute="topMargin" constant="-2" id="tIf-t4-A1h"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="DeviceIDCellID" id="Iuh-31-jb1">
+                                        <rect key="frame" x="0.0" y="160" width="375" height="66"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Iuh-31-jb1" id="Y4d-8k-xeJ">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="66"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="DeviceID" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jJq-QL-oqs">
+                                                    <rect key="frame" x="23" y="9" width="68" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="NTp-GP-Z5I">
+                                                    <rect key="frame" x="23" y="34" width="337" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="12"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="jJq-QL-oqs" firstAttribute="top" secondItem="Y4d-8k-xeJ" secondAttribute="topMargin" constant="-2" id="KQR-hC-IcE"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="jJq-QL-oqs" secondAttribute="trailingMargin" id="M68-5s-V79"/>
+                                                <constraint firstItem="jJq-QL-oqs" firstAttribute="leading" secondItem="Y4d-8k-xeJ" secondAttribute="leadingMargin" constant="7" id="Pb7-yN-Cn9"/>
+                                                <constraint firstItem="NTp-GP-Z5I" firstAttribute="top" secondItem="jJq-QL-oqs" secondAttribute="bottom" constant="4" id="Zvt-nU-uF7"/>
+                                                <constraint firstItem="NTp-GP-Z5I" firstAttribute="leading" secondItem="Y4d-8k-xeJ" secondAttribute="leadingMargin" constant="7" id="hNp-KB-ueS"/>
+                                                <constraint firstAttribute="trailing" secondItem="NTp-GP-Z5I" secondAttribute="trailing" constant="15" id="kdp-Vp-lSY"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </prototypes>
+                                <sections/>
+                                <connections>
+                                    <outlet property="dataSource" destination="mDt-jA-kKK" id="VBW-ZX-ZbJ"/>
+                                    <outlet property="delegate" destination="mDt-jA-kKK" id="rHz-CR-7rG"/>
+                                </connections>
+                            </tableView>
+                        </subviews>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <constraints>
+                            <constraint firstItem="UYO-df-3Os" firstAttribute="top" secondItem="yyK-sb-qiP" secondAttribute="bottom" constant="30" id="AjB-ng-LjJ"/>
+                            <constraint firstItem="jPq-XV-RSO" firstAttribute="top" secondItem="yV0-g6-UFN" secondAttribute="bottom" constant="30" id="KkI-dB-0fk"/>
+                            <constraint firstItem="UYO-df-3Os" firstAttribute="centerX" secondItem="oK0-bX-MM2" secondAttribute="centerX" id="LVv-vQ-aju"/>
+                            <constraint firstAttribute="trailing" secondItem="jPq-XV-RSO" secondAttribute="trailing" id="S3g-6a-rE4"/>
+                            <constraint firstItem="yV0-g6-UFN" firstAttribute="centerX" secondItem="oK0-bX-MM2" secondAttribute="centerX" id="ezD-ra-hWD"/>
+                            <constraint firstItem="yV0-g6-UFN" firstAttribute="top" secondItem="UYO-df-3Os" secondAttribute="bottom" constant="10" id="kSb-wW-OTS"/>
+                            <constraint firstItem="jPq-XV-RSO" firstAttribute="leading" secondItem="oK0-bX-MM2" secondAttribute="leading" id="zLj-0q-0qb"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" title="About" id="IH6-7b-axS"/>
+                    <connections>
+                        <outlet property="imageView" destination="UYO-df-3Os" id="uHz-Ki-dMY"/>
+                        <outlet property="tableView" destination="jPq-XV-RSO" id="nus-Oe-AHd"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="StR-Mv-Pcp" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="117.59999999999999" y="-116.49175412293854"/>
+        </scene>
+        <!--Log-->
+        <scene sceneID="XoK-4M-eYE">
+            <objects>
+                <tableViewController id="fhm-J3-Mni" customClass="LogSettingsViewController" sceneMemberID="viewController">
+                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="hps-j4-jFV">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
+                        <color key="separatorColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="calibratedRGB"/>
+                        <sections>
+                            <tableViewSection id="CBw-Nm-plJ">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="IjV-wP-MYk">
+                                        <rect key="frame" x="0.0" y="18" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="IjV-wP-MYk" id="zJl-Z7-1Jr">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Enable Log" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Vye-sA-djA">
+                                                    <rect key="frame" x="23" y="11.5" width="86" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Fd8-FI-uVp">
+                                                    <rect key="frame" x="310" y="6.5" width="51" height="31"/>
+                                                    <connections>
+                                                        <action selector="enableLogSwitched:" destination="fhm-J3-Mni" eventType="valueChanged" id="wX4-eK-ZPS"/>
+                                                    </connections>
+                                                </switch>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="Vye-sA-djA" firstAttribute="leading" secondItem="zJl-Z7-1Jr" secondAttribute="leadingMargin" constant="7" id="LzQ-Vh-bQ0"/>
+                                                <constraint firstAttribute="trailing" secondItem="Fd8-FI-uVp" secondAttribute="trailing" constant="16" id="b1z-OG-FEk"/>
+                                                <constraint firstItem="Vye-sA-djA" firstAttribute="centerY" secondItem="zJl-Z7-1Jr" secondAttribute="centerY" id="dvL-uE-CZz"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="Vye-sA-djA" secondAttribute="trailingMargin" id="wCn-cB-VvR"/>
+                                                <constraint firstItem="Fd8-FI-uVp" firstAttribute="centerY" secondItem="zJl-Z7-1Jr" secondAttribute="centerY" id="yqA-dO-DMH"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="jFq-eh-rOS">
+                                        <rect key="frame" x="0.0" y="62" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="jFq-eh-rOS" id="9II-d0-lJc">
+                                            <rect key="frame" x="0.0" y="0.0" width="348" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Log Level" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="NKn-hb-JOP">
+                                                    <rect key="frame" x="23" y="11.5" width="74" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="NKn-hb-JOP" firstAttribute="leading" secondItem="9II-d0-lJc" secondAttribute="leadingMargin" constant="7" id="Btz-zo-MEF"/>
+                                                <constraint firstItem="NKn-hb-JOP" firstAttribute="centerY" secondItem="9II-d0-lJc" secondAttribute="centerY" id="Pd9-Yi-oba"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="NKn-hb-JOP" secondAttribute="trailingMargin" id="yP2-8s-zPc"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <connections>
+                                            <segue destination="d9b-zV-ilK" kind="show" identifier="GatewayLogSettingsToLogLevel" id="NJX-0i-NN5"/>
+                                        </connections>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="eW7-Se-Bzn">
+                                        <rect key="frame" x="0.0" y="106" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="eW7-Se-Bzn" id="2pV-FB-JHZ">
+                                            <rect key="frame" x="0.0" y="0.0" width="348" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Send Log" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="o4t-io-Lws">
+                                                    <rect key="frame" x="23" y="11.5" width="74" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="o4t-io-Lws" firstAttribute="leading" secondItem="2pV-FB-JHZ" secondAttribute="leadingMargin" constant="7" id="KrR-jm-6d0"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="o4t-io-Lws" secondAttribute="trailingMargin" id="ZDE-bQ-D4G"/>
+                                                <constraint firstItem="o4t-io-Lws" firstAttribute="centerY" secondItem="2pV-FB-JHZ" secondAttribute="centerY" id="yBS-su-Taq"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                        </sections>
+                        <connections>
+                            <outlet property="dataSource" destination="fhm-J3-Mni" id="2lw-Bm-v3m"/>
+                            <outlet property="delegate" destination="fhm-J3-Mni" id="Bcr-zL-QSH"/>
+                        </connections>
+                    </tableView>
+                    <navigationItem key="navigationItem" title="Log" id="TMW-3I-ErZ"/>
+                    <connections>
+                        <outlet property="enableLogSwitch" destination="Fd8-FI-uVp" id="lJJ-Rh-wPI"/>
+                        <outlet property="logLevelCell" destination="jFq-eh-rOS" id="p80-l5-8tz"/>
+                        <outlet property="sendLogCell" destination="eW7-Se-Bzn" id="Zez-jP-LF4"/>
+                    </connections>
+                </tableViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="gxP-7L-2XX" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="1013.6" y="-116.49175412293854"/>
+        </scene>
+        <!--Log Level-->
+        <scene sceneID="efT-r9-Bdc">
+            <objects>
+                <tableViewController id="d9b-zV-ilK" customClass="LogLevelViewController" sceneMemberID="viewController">
+                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="Y1k-b5-WQA">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
+                        <sections>
+                            <tableViewSection id="jht-Md-VQb">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="m45-ml-D4t">
+                                        <rect key="frame" x="0.0" y="18" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="m45-ml-D4t" id="xqE-3G-tfz">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Debug" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="s6d-5f-7hz">
+                                                    <rect key="frame" x="23" y="11.5" width="52" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginSelected" translatesAutoresizingMaskIntoConstraints="NO" id="1ay-Hu-rXk">
+                                                    <rect key="frame" x="338" y="15" width="14" height="14"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="14" id="A7H-xA-2wI"/>
+                                                        <constraint firstAttribute="height" constant="14" id="Bbc-IM-Ez8"/>
+                                                    </constraints>
+                                                </imageView>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="s6d-5f-7hz" firstAttribute="centerY" secondItem="xqE-3G-tfz" secondAttribute="centerY" id="fbq-tJ-xlc"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="1ay-Hu-rXk" secondAttribute="trailing" constant="7" id="oK6-Vo-FIa"/>
+                                                <constraint firstItem="1ay-Hu-rXk" firstAttribute="centerY" secondItem="xqE-3G-tfz" secondAttribute="centerY" id="rPz-ak-7li"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="s6d-5f-7hz" secondAttribute="trailingMargin" id="u2b-Wc-xtk"/>
+                                                <constraint firstItem="s6d-5f-7hz" firstAttribute="leading" secondItem="xqE-3G-tfz" secondAttribute="leadingMargin" constant="7" id="v2a-MB-kSG"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="gGs-sB-9Op">
+                                        <rect key="frame" x="0.0" y="62" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="gGs-sB-9Op" id="L1E-7S-vyc">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Info" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YSf-2U-wvg">
+                                                    <rect key="frame" x="23" y="11.5" width="30" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginSelected" translatesAutoresizingMaskIntoConstraints="NO" id="BjP-i8-8tR">
+                                                    <rect key="frame" x="338" y="15" width="14" height="14"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="14" id="8oq-wd-fFl"/>
+                                                        <constraint firstAttribute="height" constant="14" id="UGy-Xh-hsS"/>
+                                                    </constraints>
+                                                </imageView>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="YSf-2U-wvg" secondAttribute="trailingMargin" id="2Eb-ub-m82"/>
+                                                <constraint firstItem="YSf-2U-wvg" firstAttribute="leading" secondItem="L1E-7S-vyc" secondAttribute="leadingMargin" constant="7" id="GgW-pK-kdk"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="BjP-i8-8tR" secondAttribute="trailing" constant="7" id="lLE-3y-wyG"/>
+                                                <constraint firstItem="BjP-i8-8tR" firstAttribute="centerY" secondItem="L1E-7S-vyc" secondAttribute="centerY" id="xBU-Ti-KGP"/>
+                                                <constraint firstItem="YSf-2U-wvg" firstAttribute="centerY" secondItem="L1E-7S-vyc" secondAttribute="centerY" id="yes-ws-bKG"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="AD4-YV-Ynz">
+                                        <rect key="frame" x="0.0" y="106" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="AD4-YV-Ynz" id="4qm-5A-q3C">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="fA9-kc-A2w">
+                                                    <rect key="frame" x="23" y="12" width="65" height="20.5"/>
+                                                    <subviews>
+                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Warning" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VZj-7h-puW">
+                                                            <rect key="frame" x="0.0" y="0.0" width="65" height="20.5"/>
+                                                            <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                            <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                            <nil key="highlightedColor"/>
+                                                        </label>
+                                                    </subviews>
+                                                </stackView>
+                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginSelected" translatesAutoresizingMaskIntoConstraints="NO" id="yJI-XU-Ken">
+                                                    <rect key="frame" x="338" y="15" width="14" height="14"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="height" constant="14" id="9aG-wb-OcZ"/>
+                                                        <constraint firstAttribute="width" constant="14" id="Lc4-CQ-dXe"/>
+                                                    </constraints>
+                                                </imageView>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="fA9-kc-A2w" firstAttribute="centerY" secondItem="4qm-5A-q3C" secondAttribute="centerY" id="AoO-PV-5M6"/>
+                                                <constraint firstItem="yJI-XU-Ken" firstAttribute="centerY" secondItem="4qm-5A-q3C" secondAttribute="centerY" id="XAn-2E-psQ"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="yJI-XU-Ken" secondAttribute="trailing" constant="7" id="c7N-I4-A1m"/>
+                                                <constraint firstItem="fA9-kc-A2w" firstAttribute="leading" secondItem="4qm-5A-q3C" secondAttribute="leadingMargin" constant="7" id="uoe-R5-Bhs"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="xUK-pv-SXi">
+                                        <rect key="frame" x="0.0" y="150" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="xUK-pv-SXi" id="l0W-t2-qFd">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Error" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bLR-Il-PfP">
+                                                    <rect key="frame" x="23" y="11.5" width="39" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginSelected" translatesAutoresizingMaskIntoConstraints="NO" id="VwM-Cg-1Ga">
+                                                    <rect key="frame" x="338" y="15" width="14" height="14"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="14" id="3b0-rD-mo0"/>
+                                                        <constraint firstAttribute="height" constant="14" id="vbF-wX-HPy"/>
+                                                    </constraints>
+                                                </imageView>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="VwM-Cg-1Ga" firstAttribute="centerY" secondItem="l0W-t2-qFd" secondAttribute="centerY" id="AAm-QQ-ytV"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="bLR-Il-PfP" secondAttribute="trailingMargin" id="HQ6-Zu-YbY"/>
+                                                <constraint firstItem="bLR-Il-PfP" firstAttribute="leading" secondItem="l0W-t2-qFd" secondAttribute="leadingMargin" constant="7" id="fww-Qz-HS2"/>
+                                                <constraint firstItem="bLR-Il-PfP" firstAttribute="centerY" secondItem="l0W-t2-qFd" secondAttribute="centerY" id="hYU-ZC-JDl"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="VwM-Cg-1Ga" secondAttribute="trailing" constant="7" id="lm5-4L-6a7"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                        </sections>
+                        <connections>
+                            <outlet property="dataSource" destination="d9b-zV-ilK" id="VCO-5I-etF"/>
+                            <outlet property="delegate" destination="d9b-zV-ilK" id="PHA-hb-Tya"/>
+                        </connections>
+                    </tableView>
+                    <navigationItem key="navigationItem" title="Log Level" id="X0g-6U-zwd"/>
+                    <connections>
+                        <outlet property="debugImageView" destination="1ay-Hu-rXk" id="IIp-mF-oaz"/>
+                        <outlet property="errorImageView" destination="VwM-Cg-1Ga" id="5m6-iU-9fa"/>
+                        <outlet property="infoImageView" destination="BjP-i8-8tR" id="1Xf-ra-8Lu"/>
+                        <outlet property="warnImageView" destination="yJI-XU-Ken" id="0vI-FQ-Hmg"/>
+                    </connections>
+                </tableViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="wGe-HE-oct" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="1924" y="-116.49175412293854"/>
+        </scene>
+        <!--Gateway-->
+        <scene sceneID="tne-QT-ifu">
+            <objects>
+                <viewController id="BYZ-38-t0r" customClass="GatewayViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
+                        <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <pageControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" numberOfPages="3" translatesAutoresizingMaskIntoConstraints="NO" id="mwE-yG-bSp">
+                                <rect key="frame" x="126.5" y="546.5" width="122.5" height="27.5"/>
+                            </pageControl>
+                            <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="fg1-cd-yLy">
+                                <rect key="frame" x="0.0" y="45" width="375" height="493.5"/>
+                                <color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="pW1-0w-lFs">
+                                    <size key="itemSize" width="50" height="50"/>
+                                    <size key="headerReferenceSize" width="0.0" height="0.0"/>
+                                    <size key="footerReferenceSize" width="0.0" height="0.0"/>
+                                    <inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                </collectionViewFlowLayout>
+                                <cells/>
+                                <connections>
+                                    <outlet property="dataSource" destination="BYZ-38-t0r" id="ECu-vD-skG"/>
+                                    <outlet property="delegate" destination="BYZ-38-t0r" id="ksO-KQ-AU1"/>
+                                </connections>
+                            </collectionView>
+                        </subviews>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <constraints>
+                            <constraint firstItem="mwE-yG-bSp" firstAttribute="top" secondItem="fg1-cd-yLy" secondAttribute="bottom" constant="8" id="C9M-rf-249"/>
+                            <constraint firstItem="fg1-cd-yLy" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="NGt-u6-dC6"/>
+                            <constraint firstItem="mwE-yG-bSp" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="NYa-Em-5f3"/>
+                            <constraint firstAttribute="trailing" secondItem="fg1-cd-yLy" secondAttribute="trailing" id="nTs-JZ-bmk"/>
+                            <constraint firstItem="wfy-db-euE" firstAttribute="top" secondItem="mwE-yG-bSp" secondAttribute="bottom" constant="49" id="qei-ed-2w6"/>
+                            <constraint firstItem="fg1-cd-yLy" firstAttribute="top" secondItem="y3c-jy-aDJ" secondAttribute="bottom" constant="45" id="z3E-39-gb1"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" title="Gateway" id="ZG6-h2-0de">
+                        <rightBarButtonItems>
+                            <barButtonItem image="GatewayItemMore" id="KRr-gB-RmH">
+                                <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            </barButtonItem>
+                            <barButtonItem image="GatewayItemAdd" id="zmx-jG-321">
+                                <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            </barButtonItem>
+                        </rightBarButtonItems>
+                    </navigationItem>
+                    <connections>
+                        <outlet property="addGatewayButton" destination="zmx-jG-321" id="ziN-t7-mcd"/>
+                        <outlet property="collectionView" destination="fg1-cd-yLy" id="CbQ-e1-fFl"/>
+                        <outlet property="moreButton" destination="KRr-gB-RmH" id="sqc-hK-arP"/>
+                        <outlet property="pageControl" destination="mwE-yG-bSp" id="LIY-gJ-Zqj"/>
+                        <segue destination="LP6-tU-vWi" kind="presentation" identifier="GatewayToSettings" modalPresentationStyle="fullScreen" id="LDy-gx-0Ka"/>
+                        <segue destination="nnp-7I-qjc" kind="presentation" identifier="GatewayToLogin" modalPresentationStyle="fullScreen" id="mxa-fV-Mab"/>
+                        <segue destination="LZd-Ei-vmr" kind="presentation" identifier="GatewayToResource" modalPresentationStyle="fullScreen" id="2v7-vL-Q1V"/>
+                        <segue destination="fhm-J3-Mni" kind="show" identifier="GatewayToLogSettings" id="Ul7-yp-Smk"/>
+                        <segue destination="mDt-jA-kKK" kind="show" identifier="GatewayToAbout" id="Cre-3M-bGE"/>
+                        <segue destination="AQs-MT-X4V" kind="presentation" identifier="GatewayToWebAuth" modalPresentationStyle="fullScreen" id="ES7-sm-Mde"/>
+                        <segue destination="Qv9-5w-hBC" kind="show" identifier="LoginToChallenge" id="xSQ-ko-f4a"/>
+                        <segue destination="MGw-hc-Bqe" kind="show" identifier="LoginToChangePassword" id="iir-Mp-9Rd"/>
+                        <segue destination="axh-t8-XkJ" kind="show" identifier="LoginToSMS" id="bRA-r2-9bC"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="1013.6" y="689.5052473763119"/>
+        </scene>
+        <!--GatewaySettingsViewController-->
+        <scene sceneID="gfw-gV-BAU">
+            <objects>
+                <tableViewController title="GatewaySettingsViewController" id="XsL-WP-fGg" customClass="GatewaySettingsViewController" sceneMemberID="viewController">
+                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" bounces="NO" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="15" sectionFooterHeight="1" id="y11-ii-gOR">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="calibratedRGB"/>
+                        <color key="separatorColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="calibratedRGB"/>
+                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                        <sections>
+                            <tableViewSection id="NvI-RD-qCm">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="Nle-U0-aG9">
+                                        <rect key="frame" x="0.0" y="15" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Nle-U0-aG9" id="WIf-cx-jpE">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="right" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="DM1-M4-GJ6">
+                                                    <rect key="frame" x="65.5" y="0.0" width="294.5" height="44"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <textInputTraits key="textInputTraits" returnKeyType="next"/>
+                                                    <connections>
+                                                        <outlet property="delegate" destination="XsL-WP-fGg" id="bn0-5u-yVR"/>
+                                                    </connections>
+                                                </textField>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="1000" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="imK-Z9-nrn">
+                                                    <rect key="frame" x="23" y="11.5" width="34.5" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="DM1-M4-GJ6" firstAttribute="leading" secondItem="imK-Z9-nrn" secondAttribute="trailing" constant="8" id="Bhl-f3-XvW"/>
+                                                <constraint firstItem="imK-Z9-nrn" firstAttribute="leading" secondItem="WIf-cx-jpE" secondAttribute="leadingMargin" constant="7" id="H5k-gc-MCR"/>
+                                                <constraint firstAttribute="trailing" secondItem="DM1-M4-GJ6" secondAttribute="trailing" constant="15" id="IdM-tA-2CB"/>
+                                                <constraint firstItem="imK-Z9-nrn" firstAttribute="centerY" secondItem="WIf-cx-jpE" secondAttribute="centerY" id="MuH-JA-dF8"/>
+                                                <constraint firstAttribute="bottom" secondItem="DM1-M4-GJ6" secondAttribute="bottom" id="T3y-Wu-8zB"/>
+                                                <constraint firstItem="DM1-M4-GJ6" firstAttribute="top" secondItem="WIf-cx-jpE" secondAttribute="top" id="sUP-CB-PyF"/>
+                                                <constraint firstItem="DM1-M4-GJ6" firstAttribute="centerY" secondItem="WIf-cx-jpE" secondAttribute="centerY" id="uKl-kr-pLe"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="Ac8-m4-rin">
+                                        <rect key="frame" x="0.0" y="59" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Ac8-m4-rin" id="oo1-HA-eIT">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Gateway" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="CDP-Hx-Q1x">
+                                                    <rect key="frame" x="23" y="11.5" width="68" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="right" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="ih1-uB-gvq">
+                                                    <rect key="frame" x="99" y="0.0" width="261" height="44"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <textInputTraits key="textInputTraits" returnKeyType="next"/>
+                                                    <connections>
+                                                        <outlet property="delegate" destination="XsL-WP-fGg" id="r2m-qS-BQQ"/>
+                                                    </connections>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="ih1-uB-gvq" firstAttribute="leading" secondItem="CDP-Hx-Q1x" secondAttribute="trailing" constant="8" id="012-r5-g4H"/>
+                                                <constraint firstItem="ih1-uB-gvq" firstAttribute="top" secondItem="oo1-HA-eIT" secondAttribute="top" id="6ym-fX-AyR"/>
+                                                <constraint firstAttribute="bottom" secondItem="ih1-uB-gvq" secondAttribute="bottom" id="DOg-V3-r1x"/>
+                                                <constraint firstAttribute="trailing" secondItem="ih1-uB-gvq" secondAttribute="trailing" constant="15" id="FS1-n5-aTx"/>
+                                                <constraint firstItem="CDP-Hx-Q1x" firstAttribute="leading" secondItem="oo1-HA-eIT" secondAttribute="leadingMargin" constant="7" id="Suh-0S-0EX"/>
+                                                <constraint firstItem="CDP-Hx-Q1x" firstAttribute="centerY" secondItem="oo1-HA-eIT" secondAttribute="centerY" id="VAJ-a4-n0U"/>
+                                                <constraint firstItem="ih1-uB-gvq" firstAttribute="centerY" secondItem="oo1-HA-eIT" secondAttribute="centerY" id="b4X-IQ-gzy"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="dBG-TA-7PV">
+                                        <rect key="frame" x="0.0" y="103" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="dBG-TA-7PV" id="zJI-zU-MPb">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Username" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eAY-Im-Jhi">
+                                                    <rect key="frame" x="23" y="11.5" width="80.5" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="right" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="Wo1-jU-MJP">
+                                                    <rect key="frame" x="111.5" y="0.0" width="248.5" height="44"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <textInputTraits key="textInputTraits" returnKeyType="next"/>
+                                                    <connections>
+                                                        <outlet property="delegate" destination="XsL-WP-fGg" id="L1X-e3-65a"/>
+                                                    </connections>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="Wo1-jU-MJP" firstAttribute="leading" secondItem="eAY-Im-Jhi" secondAttribute="trailing" constant="8" id="5WR-5P-X2G"/>
+                                                <constraint firstAttribute="trailing" secondItem="Wo1-jU-MJP" secondAttribute="trailing" constant="15" id="KE8-Eu-gYA"/>
+                                                <constraint firstAttribute="bottom" secondItem="Wo1-jU-MJP" secondAttribute="bottom" id="Lw4-C5-7wb"/>
+                                                <constraint firstItem="eAY-Im-Jhi" firstAttribute="centerY" secondItem="zJI-zU-MPb" secondAttribute="centerY" id="Uq5-WN-rHs"/>
+                                                <constraint firstItem="eAY-Im-Jhi" firstAttribute="leading" secondItem="zJI-zU-MPb" secondAttribute="leadingMargin" constant="7" id="XR0-Ek-ypL"/>
+                                                <constraint firstItem="Wo1-jU-MJP" firstAttribute="top" secondItem="zJI-zU-MPb" secondAttribute="top" id="afB-ZI-1Ae"/>
+                                                <constraint firstItem="Wo1-jU-MJP" firstAttribute="centerY" secondItem="zJI-zU-MPb" secondAttribute="centerY" id="wvB-lx-LYs"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="ujt-ww-Fhf">
+                                        <rect key="frame" x="0.0" y="147" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ujt-ww-Fhf" id="GaZ-1l-iKS">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Port" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OvA-2F-uTb">
+                                                    <rect key="frame" x="23" y="11.5" width="33.5" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="443" textAlignment="right" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="Pmm-6N-Veq">
+                                                    <rect key="frame" x="64.5" y="0.0" width="295.5" height="44"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <textInputTraits key="textInputTraits" returnKeyType="next"/>
+                                                    <connections>
+                                                        <outlet property="delegate" destination="XsL-WP-fGg" id="1jx-5V-egx"/>
+                                                    </connections>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="Pmm-6N-Veq" firstAttribute="top" secondItem="GaZ-1l-iKS" secondAttribute="top" id="14C-sr-uLo"/>
+                                                <constraint firstItem="Pmm-6N-Veq" firstAttribute="centerY" secondItem="GaZ-1l-iKS" secondAttribute="centerY" id="4oO-r7-4Is"/>
+                                                <constraint firstAttribute="trailing" secondItem="Pmm-6N-Veq" secondAttribute="trailing" constant="15" id="JjM-Pl-KQa"/>
+                                                <constraint firstItem="OvA-2F-uTb" firstAttribute="leading" secondItem="GaZ-1l-iKS" secondAttribute="leadingMargin" constant="7" id="aqZ-qW-bI4"/>
+                                                <constraint firstAttribute="bottom" secondItem="Pmm-6N-Veq" secondAttribute="bottom" id="ge2-wq-eXb"/>
+                                                <constraint firstItem="Pmm-6N-Veq" firstAttribute="leading" secondItem="OvA-2F-uTb" secondAttribute="trailing" constant="8" id="jc8-MP-e0S"/>
+                                                <constraint firstItem="OvA-2F-uTb" firstAttribute="centerY" secondItem="GaZ-1l-iKS" secondAttribute="centerY" id="wNL-bv-a5C"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="uVr-lX-t6T">
+                                        <rect key="frame" x="0.0" y="191" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="uVr-lX-t6T" id="bDL-ff-tsO">
+                                            <rect key="frame" x="0.0" y="0.0" width="348" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Certificate" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Icn-qp-fkF">
+                                                    <rect key="frame" x="23" y="11.5" width="83" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fdn-RX-tgS">
+                                                    <rect key="frame" x="220" y="22" width="120" height="0.0"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="120" id="Kr0-Tf-SdA"/>
+                                                    </constraints>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="fdn-RX-tgS" firstAttribute="trailing" secondItem="bDL-ff-tsO" secondAttribute="trailingMargin" id="4Cg-5r-HiZ"/>
+                                                <constraint firstItem="fdn-RX-tgS" firstAttribute="centerY" secondItem="bDL-ff-tsO" secondAttribute="centerY" id="A34-mf-syj"/>
+                                                <constraint firstItem="Icn-qp-fkF" firstAttribute="centerY" secondItem="bDL-ff-tsO" secondAttribute="centerY" id="RUD-BX-7j0"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="Icn-qp-fkF" secondAttribute="trailingMargin" id="cpa-yV-EWg"/>
+                                                <constraint firstItem="Icn-qp-fkF" firstAttribute="leading" secondItem="bDL-ff-tsO" secondAttribute="leadingMargin" constant="7" id="d8S-Ke-Nu2"/>
+                                                <constraint firstItem="fdn-RX-tgS" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="bDL-ff-tsO" secondAttribute="leadingMargin" id="eEY-gY-qrt"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                            <tableViewSection id="1Jk-Fx-ZsE">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="owE-rV-dI2">
+                                        <rect key="frame" x="0.0" y="251" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="owE-rV-dI2" id="nWr-Y8-p8j">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Enable Secure Tunnel" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="96T-X7-oAM">
+                                                    <rect key="frame" x="23" y="11.5" width="169" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Xds-Qx-gOv">
+                                                    <rect key="frame" x="311" y="6.5" width="51" height="31"/>
+                                                </switch>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="96T-X7-oAM" secondAttribute="trailingMargin" id="0cA-cd-IJP"/>
+                                                <constraint firstItem="96T-X7-oAM" firstAttribute="centerY" secondItem="nWr-Y8-p8j" secondAttribute="centerY" id="KHV-Wa-Eqr"/>
+                                                <constraint firstItem="Xds-Qx-gOv" firstAttribute="centerY" secondItem="nWr-Y8-p8j" secondAttribute="centerY" id="ORV-HF-OlT"/>
+                                                <constraint firstItem="96T-X7-oAM" firstAttribute="leading" secondItem="nWr-Y8-p8j" secondAttribute="leadingMargin" constant="7" id="uXl-cq-lkw"/>
+                                                <constraint firstAttribute="trailing" secondItem="Xds-Qx-gOv" secondAttribute="trailing" constant="15" id="v6u-Pu-gNl"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="Nse-L7-SKx">
+                                        <rect key="frame" x="0.0" y="295" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Nse-L7-SKx" id="0g0-ig-6AT">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Save Password" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sbQ-bg-DE3">
+                                                    <rect key="frame" x="23" y="11.5" width="118" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="DQb-pJ-7b1">
+                                                    <rect key="frame" x="311" y="6.5" width="51" height="31"/>
+                                                    <connections>
+                                                        <action selector="savePasswordSwitched:" destination="XsL-WP-fGg" eventType="valueChanged" id="u04-3J-6nI"/>
+                                                    </connections>
+                                                </switch>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="DQb-pJ-7b1" firstAttribute="centerY" secondItem="0g0-ig-6AT" secondAttribute="centerY" id="13L-vF-FMq"/>
+                                                <constraint firstAttribute="trailing" secondItem="DQb-pJ-7b1" secondAttribute="trailing" constant="15" id="3KS-Oj-dJB"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="sbQ-bg-DE3" secondAttribute="trailingMargin" id="NIa-5V-2pI"/>
+                                                <constraint firstItem="sbQ-bg-DE3" firstAttribute="leading" secondItem="0g0-ig-6AT" secondAttribute="leadingMargin" constant="7" id="QLK-L2-70a"/>
+                                                <constraint firstItem="sbQ-bg-DE3" firstAttribute="centerY" secondItem="0g0-ig-6AT" secondAttribute="centerY" id="a9I-Qe-JGO"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="JaO-ND-HoQ">
+                                        <rect key="frame" x="0.0" y="339" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="JaO-ND-HoQ" id="4SZ-I7-kRU">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Show Login Dialog" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8qU-Mv-Wgb">
+                                                    <rect key="frame" x="23" y="11.5" width="144" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="VMt-Fa-LDJ">
+                                                    <rect key="frame" x="311" y="6.5" width="51" height="31"/>
+                                                </switch>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="VMt-Fa-LDJ" firstAttribute="centerY" secondItem="4SZ-I7-kRU" secondAttribute="centerY" id="9t0-0B-gIg"/>
+                                                <constraint firstAttribute="trailing" secondItem="VMt-Fa-LDJ" secondAttribute="trailing" constant="15" id="DZa-3U-DkU"/>
+                                                <constraint firstItem="8qU-Mv-Wgb" firstAttribute="centerY" secondItem="4SZ-I7-kRU" secondAttribute="centerY" id="Gjf-SR-jNh"/>
+                                                <constraint firstItem="8qU-Mv-Wgb" firstAttribute="leading" secondItem="4SZ-I7-kRU" secondAttribute="leadingMargin" constant="7" id="WLD-9J-He2"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="8qU-Mv-Wgb" secondAttribute="trailingMargin" id="oPU-R5-Jvl"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="5Hy-9R-m62">
+                                        <rect key="frame" x="0.0" y="383" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="5Hy-9R-m62" id="70z-38-z3w">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Enable Web SSO" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gJ3-Oy-fYa">
+                                                    <rect key="frame" x="23" y="11.5" width="131" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="hFW-eO-lIL">
+                                                    <rect key="frame" x="311" y="6.5" width="51" height="31"/>
+                                                </switch>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="trailing" secondItem="hFW-eO-lIL" secondAttribute="trailing" constant="15" id="NiJ-9i-jxI"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="gJ3-Oy-fYa" secondAttribute="trailingMargin" id="OXX-zl-Scr"/>
+                                                <constraint firstItem="hFW-eO-lIL" firstAttribute="centerY" secondItem="70z-38-z3w" secondAttribute="centerY" id="XCd-9N-wR2"/>
+                                                <constraint firstItem="gJ3-Oy-fYa" firstAttribute="centerY" secondItem="70z-38-z3w" secondAttribute="centerY" id="hN1-OW-lKC"/>
+                                                <constraint firstItem="gJ3-Oy-fYa" firstAttribute="leading" secondItem="70z-38-z3w" secondAttribute="leadingMargin" constant="7" id="xaw-MA-3Mu"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="5QK-8c-cDU">
+                                        <rect key="frame" x="0.0" y="427" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="5QK-8c-cDU" id="mO4-r1-ygQ">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Enable WebAuth" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wea-au-VtG">
+                                                    <rect key="frame" x="23" y="11.5" width="129" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="yaV-d9-dhg">
+                                                    <rect key="frame" x="311" y="6.5" width="51" height="31"/>
+                                                </switch>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="wea-au-VtG" firstAttribute="leading" secondItem="mO4-r1-ygQ" secondAttribute="leadingMargin" constant="7" id="01Z-tc-PWU"/>
+                                                <constraint firstAttribute="trailing" secondItem="yaV-d9-dhg" secondAttribute="trailing" constant="15" id="4jr-md-A8n"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="wea-au-VtG" secondAttribute="trailingMargin" id="JtY-SE-v7k"/>
+                                                <constraint firstItem="wea-au-VtG" firstAttribute="centerY" secondItem="mO4-r1-ygQ" secondAttribute="centerY" id="YQn-f4-kPg"/>
+                                                <constraint firstItem="yaV-d9-dhg" firstAttribute="centerY" secondItem="mO4-r1-ygQ" secondAttribute="centerY" id="kY5-wJ-S1C"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                            <tableViewSection id="5jR-Lb-3fv">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="FuL-oC-auO">
+                                        <rect key="frame" x="0.0" y="487" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="FuL-oC-auO" id="Pui-Mn-Fr1">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="SyferLock Authentication" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wym-Rd-iq1">
+                                                    <rect key="frame" x="23" y="11.5" width="197" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="mS8-5h-yHM">
+                                                    <rect key="frame" x="311" y="6.5" width="51" height="31"/>
+                                                </switch>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="wym-Rd-iq1" firstAttribute="centerY" secondItem="Pui-Mn-Fr1" secondAttribute="centerY" id="XyL-ky-7KZ"/>
+                                                <constraint firstAttribute="trailing" secondItem="mS8-5h-yHM" secondAttribute="trailing" constant="15" id="bGK-Ut-j4F"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="wym-Rd-iq1" secondAttribute="trailingMargin" id="kTg-Z0-e6s"/>
+                                                <constraint firstItem="mS8-5h-yHM" firstAttribute="centerY" secondItem="Pui-Mn-Fr1" secondAttribute="centerY" id="w6A-1J-6mI"/>
+                                                <constraint firstItem="wym-Rd-iq1" firstAttribute="leading" secondItem="Pui-Mn-Fr1" secondAttribute="leadingMargin" constant="7" id="zld-tq-J6T"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                        </sections>
+                        <connections>
+                            <outlet property="dataSource" destination="XsL-WP-fGg" id="1d5-zs-e3T"/>
+                            <outlet property="delegate" destination="XsL-WP-fGg" id="19a-tO-de5"/>
+                        </connections>
+                    </tableView>
+                    <navigationItem key="navigationItem" title="Gateway" id="WG0-kd-ZSL">
+                        <barButtonItem key="leftBarButtonItem" title="Cancel" id="5dD-Oo-s8d">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            <connections>
+                                <action selector="cancelButtonClicked:" destination="XsL-WP-fGg" id="akT-WQ-jcr"/>
+                            </connections>
+                        </barButtonItem>
+                        <barButtonItem key="rightBarButtonItem" title="Save" id="Hle-HP-ZfN">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            <connections>
+                                <action selector="saveButtonClicked:" destination="XsL-WP-fGg" id="mtr-Sb-mXe"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                    <connections>
+                        <outlet property="certNameLabel" destination="fdn-RX-tgS" id="UNf-TJ-gy6"/>
+                        <outlet property="enableSecureTunnelSwitch" destination="Xds-Qx-gOv" id="4DY-vR-HFf"/>
+                        <outlet property="enableWebAuthSwitch" destination="yaV-d9-dhg" id="WZq-8I-z6g"/>
+                        <outlet property="enableWebSSOSwitch" destination="hFW-eO-lIL" id="kes-CB-Lj4"/>
+                        <outlet property="gatewayTextField" destination="ih1-uB-gvq" id="x4l-hH-wRb"/>
+                        <outlet property="portTextField" destination="Pmm-6N-Veq" id="Q0k-Tm-8Ed"/>
+                        <outlet property="savePasswordSwitch" destination="DQb-pJ-7b1" id="KKP-9M-JKV"/>
+                        <outlet property="showLoginDialogSwitch" destination="VMt-Fa-LDJ" id="263-78-bGd"/>
+                        <outlet property="syferlockAuthSwitch" destination="mS8-5h-yHM" id="Ibk-hj-uAP"/>
+                        <outlet property="titleTextField" destination="DM1-M4-GJ6" id="Hf4-UI-jSQ"/>
+                        <outlet property="usernameTextField" destination="Wo1-jU-MJP" id="i3q-xf-vek"/>
+                        <segue destination="kQL-Cp-vCp" kind="show" identifier="GatewaySettingsToCertificates" id="dwI-hk-mt6"/>
+                        <segue destination="l9d-Rt-vCd" kind="show" identifier="GatewaySettingsToInstallCertificate" id="bpD-LK-kUE"/>
+                    </connections>
+                </tableViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="fa1-2L-7U9" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="2792.8000000000002" y="689.5052473763119"/>
+        </scene>
+        <!--Certificates-->
+        <scene sceneID="2oM-db-nzH">
+            <objects>
+                <tableViewController storyboardIdentifier="CertificateViewControllerID" modalPresentationStyle="fullScreen" id="kQL-Cp-vCp" customClass="CertificatesViewController" sceneMemberID="viewController">
+                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" allowsSelection="NO" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="GoU-Ly-mPU">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="calibratedRGB"/>
+                        <color key="separatorColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="calibratedRGB"/>
+                        <inset key="separatorInset" minX="40" minY="0.0" maxX="0.0" maxY="0.0"/>
+                        <prototypes>
+                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="CertificateNameID" id="TE0-lz-m2p" customClass="CertificateNameCell">
+                                <rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
+                                <autoresizingMask key="autoresizingMask"/>
+                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="TE0-lz-m2p" id="IMh-6R-E7p">
+                                    <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                    <autoresizingMask key="autoresizingMask"/>
+                                    <subviews>
+                                        <button opaque="NO" tag="2" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kQf-vV-n7A" customClass="ANImageButton">
+                                            <rect key="frame" x="338" y="15" width="14" height="14"/>
+                                            <constraints>
+                                                <constraint firstAttribute="width" constant="14" id="AkZ-sR-ssc"/>
+                                                <constraint firstAttribute="height" constant="14" id="Bkh-sL-TqA"/>
+                                            </constraints>
+                                            <state key="normal" title="Button" image="CertificateDelete">
+                                                <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                            </state>
+                                            <connections>
+                                                <action selector="deleteButtonClicked:" destination="TE0-lz-m2p" eventType="touchUpInside" id="kUS-hv-d26"/>
+                                            </connections>
+                                        </button>
+                                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="r21-cF-CVj" customClass="ANImageButton">
+                                            <rect key="frame" x="18" y="11" width="22" height="22"/>
+                                            <constraints>
+                                                <constraint firstAttribute="height" constant="22" id="Gar-w6-io5"/>
+                                                <constraint firstAttribute="width" constant="22" id="nSn-HD-Oz7"/>
+                                            </constraints>
+                                            <state key="normal" image="CertificateUnselected"/>
+                                            <connections>
+                                                <action selector="selecteButtonClicked:" destination="TE0-lz-m2p" eventType="touchUpInside" id="Nd1-Jr-gOC"/>
+                                            </connections>
+                                        </button>
+                                        <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wrc-lZ-DBp">
+                                            <rect key="frame" x="48" y="12.5" width="46" height="21"/>
+                                            <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                            <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                            <nil key="highlightedColor"/>
+                                        </label>
+                                    </subviews>
+                                    <constraints>
+                                        <constraint firstItem="wrc-lZ-DBp" firstAttribute="centerY" secondItem="IMh-6R-E7p" secondAttribute="centerY" constant="1" id="7ly-MO-ceF"/>
+                                        <constraint firstItem="kQf-vV-n7A" firstAttribute="centerY" secondItem="IMh-6R-E7p" secondAttribute="centerY" id="BxA-23-FCN"/>
+                                        <constraint firstItem="kQf-vV-n7A" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="IMh-6R-E7p" secondAttribute="leadingMargin" id="DQ2-oe-HMG"/>
+                                        <constraint firstAttribute="trailingMargin" secondItem="kQf-vV-n7A" secondAttribute="trailing" constant="7" id="Kg3-RE-kZN"/>
+                                        <constraint firstItem="r21-cF-CVj" firstAttribute="leading" secondItem="IMh-6R-E7p" secondAttribute="leadingMargin" constant="2" id="OeM-1d-D1N"/>
+                                        <constraint firstItem="wrc-lZ-DBp" firstAttribute="leading" secondItem="r21-cF-CVj" secondAttribute="trailing" constant="8" id="RAr-41-Xq4"/>
+                                        <constraint firstItem="r21-cF-CVj" firstAttribute="centerY" secondItem="IMh-6R-E7p" secondAttribute="centerY" id="XnB-pO-qnB"/>
+                                        <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="wrc-lZ-DBp" secondAttribute="trailing" constant="20" symbolic="YES" id="bcu-nS-qmL"/>
+                                    </constraints>
+                                </tableViewCellContentView>
+                                <color key="backgroundColor" systemColor="tableCellGroupedBackgroundColor"/>
+                                <connections>
+                                    <outlet property="deleteButton" destination="kQf-vV-n7A" id="c2o-wD-HFI"/>
+                                    <outlet property="nameLabel" destination="wrc-lZ-DBp" id="buX-EG-VDB"/>
+                                    <outlet property="selectButton" destination="r21-cF-CVj" id="vVC-AA-5M7"/>
+                                </connections>
+                            </tableViewCell>
+                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="CertificateSubjectID" id="CJX-bt-rbE">
+                                <rect key="frame" x="0.0" y="99.5" width="375" height="44"/>
+                                <autoresizingMask key="autoresizingMask"/>
+                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="CJX-bt-rbE" id="3nQ-Ed-66T">
+                                    <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                    <autoresizingMask key="autoresizingMask"/>
+                                    <subviews>
+                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Subject" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SI4-0H-aeD">
+                                            <rect key="frame" x="48" y="11.5" width="58" height="21"/>
+                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                            <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                            <nil key="highlightedColor"/>
+                                        </label>
+                                        <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="&lt;subject&gt;" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fdz-NZ-lcr">
+                                            <rect key="frame" x="275" y="11.5" width="77" height="21"/>
+                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                            <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                            <nil key="highlightedColor"/>
+                                        </label>
+                                    </subviews>
+                                    <constraints>
+                                        <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="SI4-0H-aeD" secondAttribute="trailingMargin" id="UCP-Zz-nnZ"/>
+                                        <constraint firstAttribute="trailingMargin" secondItem="fdz-NZ-lcr" secondAttribute="trailing" constant="7" id="YGX-VK-xbn"/>
+                                        <constraint firstItem="fdz-NZ-lcr" firstAttribute="centerY" secondItem="3nQ-Ed-66T" secondAttribute="centerY" id="e02-f3-rbd"/>
+                                        <constraint firstItem="SI4-0H-aeD" firstAttribute="centerY" secondItem="3nQ-Ed-66T" secondAttribute="centerY" id="jM5-Zh-nD4"/>
+                                        <constraint firstItem="SI4-0H-aeD" firstAttribute="leading" secondItem="3nQ-Ed-66T" secondAttribute="leadingMargin" constant="32" id="q9h-7y-F83"/>
+                                        <constraint firstItem="fdz-NZ-lcr" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="3nQ-Ed-66T" secondAttribute="leadingMargin" id="vKQ-dh-yrM"/>
+                                    </constraints>
+                                </tableViewCellContentView>
+                                <color key="backgroundColor" systemColor="tableCellGroupedBackgroundColor"/>
+                            </tableViewCell>
+                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="CertificateIssuerID" id="Lcc-N2-VRt">
+                                <rect key="frame" x="0.0" y="143.5" width="375" height="44"/>
+                                <autoresizingMask key="autoresizingMask"/>
+                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Lcc-N2-VRt" id="Zs6-9V-VLy">
+                                    <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                    <autoresizingMask key="autoresizingMask"/>
+                                    <subviews>
+                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Issued by" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zn0-OY-lhN">
+                                            <rect key="frame" x="48" y="11.5" width="73" height="21"/>
+                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                            <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                            <nil key="highlightedColor"/>
+                                        </label>
+                                        <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="&lt;issuer&gt;" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lg2-Oh-23a">
+                                            <rect key="frame" x="286" y="11.5" width="66" height="21"/>
+                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                            <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                            <nil key="highlightedColor"/>
+                                        </label>
+                                    </subviews>
+                                    <constraints>
+                                        <constraint firstItem="lg2-Oh-23a" firstAttribute="centerY" secondItem="Zs6-9V-VLy" secondAttribute="centerY" id="3Ix-yh-M5h"/>
+                                        <constraint firstAttribute="trailingMargin" secondItem="lg2-Oh-23a" secondAttribute="trailing" constant="7" id="5zo-hp-HWT"/>
+                                        <constraint firstItem="zn0-OY-lhN" firstAttribute="leading" secondItem="Zs6-9V-VLy" secondAttribute="leadingMargin" constant="32" id="WBF-Jd-ete"/>
+                                        <constraint firstItem="lg2-Oh-23a" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Zs6-9V-VLy" secondAttribute="leadingMargin" id="hYH-6i-W3c"/>
+                                        <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="zn0-OY-lhN" secondAttribute="trailingMargin" id="iIG-fc-eBE"/>
+                                        <constraint firstItem="zn0-OY-lhN" firstAttribute="centerY" secondItem="Zs6-9V-VLy" secondAttribute="centerY" id="uYv-Nt-zw7"/>
+                                    </constraints>
+                                </tableViewCellContentView>
+                                <color key="backgroundColor" systemColor="tableCellGroupedBackgroundColor"/>
+                            </tableViewCell>
+                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="CertificateExpireID" id="Yyt-Ju-TMm">
+                                <rect key="frame" x="0.0" y="187.5" width="375" height="44"/>
+                                <autoresizingMask key="autoresizingMask"/>
+                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Yyt-Ju-TMm" id="E09-vo-lio">
+                                    <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                    <autoresizingMask key="autoresizingMask"/>
+                                    <subviews>
+                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Expires" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pxh-Lt-m9c">
+                                            <rect key="frame" x="48" y="11.5" width="56" height="21"/>
+                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                            <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                            <nil key="highlightedColor"/>
+                                        </label>
+                                        <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="&lt;time&gt;" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uj8-n9-k7D">
+                                            <rect key="frame" x="298" y="11.5" width="54" height="21"/>
+                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                            <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                            <nil key="highlightedColor"/>
+                                        </label>
+                                    </subviews>
+                                    <constraints>
+                                        <constraint firstItem="pxh-Lt-m9c" firstAttribute="leading" secondItem="E09-vo-lio" secondAttribute="leadingMargin" constant="32" id="4aK-C0-70z"/>
+                                        <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="pxh-Lt-m9c" secondAttribute="trailingMargin" id="6CP-qv-w1d"/>
+                                        <constraint firstItem="uj8-n9-k7D" firstAttribute="centerY" secondItem="E09-vo-lio" secondAttribute="centerY" id="MGc-L1-YW8"/>
+                                        <constraint firstItem="uj8-n9-k7D" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="E09-vo-lio" secondAttribute="leadingMargin" id="NFl-ag-x9I"/>
+                                        <constraint firstAttribute="trailingMargin" secondItem="uj8-n9-k7D" secondAttribute="trailing" constant="7" id="evq-jR-RkP"/>
+                                        <constraint firstItem="pxh-Lt-m9c" firstAttribute="centerY" secondItem="E09-vo-lio" secondAttribute="centerY" id="sO5-Dw-eik"/>
+                                    </constraints>
+                                </tableViewCellContentView>
+                                <color key="backgroundColor" systemColor="tableCellGroupedBackgroundColor"/>
+                            </tableViewCell>
+                        </prototypes>
+                        <connections>
+                            <outlet property="dataSource" destination="kQL-Cp-vCp" id="9QL-T1-JeR"/>
+                            <outlet property="delegate" destination="kQL-Cp-vCp" id="tU8-KO-Iem"/>
+                        </connections>
+                    </tableView>
+                    <navigationItem key="navigationItem" title="Certificates" id="3s4-cm-cci">
+                        <barButtonItem key="rightBarButtonItem" systemItem="add" id="zGS-SE-sa8">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            <connections>
+                                <segue destination="l9d-Rt-vCd" kind="presentation" modalPresentationStyle="fullScreen" id="4WH-pD-NYb"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                </tableViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="jRg-da-dNl" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="3665" y="690"/>
+        </scene>
+        <!--Certificate-->
+        <scene sceneID="6Tc-Pi-DBe">
+            <objects>
+                <viewController modalPresentationStyle="fullScreen" id="ge6-AP-0um" customClass="CertificateInstallViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="JbV-43-RVv"/>
+                        <viewControllerLayoutGuide type="bottom" id="vta-U8-txv"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="4fd-Yp-3nJ">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Arr-MX-tZv" customClass="ANImageButton">
+                                <rect key="frame" x="18" y="20" width="22" height="22"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="22" id="hjR-f0-dbl"/>
+                                    <constraint firstAttribute="width" constant="22" id="wI7-Wa-Cce"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="18"/>
+                                <state key="normal" image="CertificateUnselected"/>
+                                <connections>
+                                    <action selector="urlSelecteButtonClicked:" destination="ge6-AP-0um" eventType="touchUpInside" id="Qlh-bl-xhg"/>
+                                </connections>
+                            </button>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="URL" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lXS-nR-USh">
+                                <rect key="frame" x="48" y="21.5" width="33" height="21"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="21" id="ZZ9-OX-KE8"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="nLW-cz-kvJ" customClass="ANImageButton">
+                                <rect key="frame" x="18" y="190" width="22" height="22"/>
+                                <constraints>
+                                    <constraint firstAttribute="width" constant="22" id="P43-iD-3l0"/>
+                                    <constraint firstAttribute="height" constant="22" id="n7Z-lB-FN5"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="18"/>
+                                <state key="normal" image="CertificateUnselected"/>
+                                <connections>
+                                    <action selector="localSelecteButtonClicked:" destination="ge6-AP-0um" eventType="touchUpInside" id="lh7-bx-8xR"/>
+                                </connections>
+                            </button>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Local Certificate" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hly-Eq-Kfh">
+                                <rect key="frame" x="48" y="191.5" width="128" height="21"/>
+                                <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="oTL-pD-XOH">
+                                <rect key="frame" x="15" y="50" width="345" height="44"/>
+                                <subviews>
+                                    <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="http:// or ftp://" textAlignment="natural" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="FJA-EM-1G3">
+                                        <rect key="frame" x="15" y="0.0" width="315" height="44"/>
+                                        <constraints>
+                                            <constraint firstAttribute="height" constant="44" id="mR2-lu-r0L"/>
+                                        </constraints>
+                                        <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                        <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                        <textInputTraits key="textInputTraits"/>
+                                    </textField>
+                                </subviews>
+                                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                <constraints>
+                                    <constraint firstAttribute="trailing" secondItem="FJA-EM-1G3" secondAttribute="trailing" constant="15" id="Ahr-gh-fzR"/>
+                                    <constraint firstItem="FJA-EM-1G3" firstAttribute="centerY" secondItem="oTL-pD-XOH" secondAttribute="centerY" id="ULG-hE-r4c"/>
+                                    <constraint firstItem="FJA-EM-1G3" firstAttribute="leading" secondItem="oTL-pD-XOH" secondAttribute="leading" constant="15" id="git-tY-lLS"/>
+                                    <constraint firstAttribute="height" constant="44" id="mWg-dC-Ik3"/>
+                                </constraints>
+                            </view>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="You can install certificates from a PKCS#12 file with pfx or p12 extension." textAlignment="natural" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="UoO-HA-SVc">
+                                <rect key="frame" x="15" y="109" width="345" height="33.5"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="cjW-BP-ZFL">
+                                <rect key="frame" x="15" y="330" width="345" height="50"/>
+                                <color key="backgroundColor" red="0.90588235294117647" green="0.0" blue="0.070588235294117646" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="50" id="lu0-p7-H2a"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                <state key="normal" title="Install">
+                                    <color key="titleColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
+                                </state>
+                                <connections>
+                                    <action selector="installButtonClicked:" destination="ge6-AP-0um" eventType="touchUpInside" id="PYu-57-QWz"/>
+                                    <action selector="loginButtonClicked:" destination="b5l-8Z-fX3" eventType="touchUpInside" id="UKB-Hy-PM1"/>
+                                    <action selector="registerButtonClicked:" destination="A29-A2-ywC" eventType="touchUpInside" id="ZPB-L1-LcO"/>
+                                </connections>
+                            </button>
+                            <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" scrollEnabled="NO" dataMode="prototypes" style="grouped" rowHeight="44" sectionHeaderHeight="-1" sectionFooterHeight="-1" translatesAutoresizingMaskIntoConstraints="NO" id="Z4E-xR-btY">
+                                <rect key="frame" x="15" y="225" width="345" height="50"/>
+                                <color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="50" id="IH7-BE-LEw"/>
+                                </constraints>
+                                <color key="separatorColor" red="0.98039215686274506" green="0.98039215686274506" blue="0.98039215686274506" alpha="1" colorSpace="calibratedRGB"/>
+                                <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                <connections>
+                                    <outlet property="dataSource" destination="ge6-AP-0um" id="3sG-Ui-Q9k"/>
+                                    <outlet property="delegate" destination="ge6-AP-0um" id="Jji-cS-5KC"/>
+                                </connections>
+                            </tableView>
+                        </subviews>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="calibratedRGB"/>
+                        <constraints>
+                            <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="hly-Eq-Kfh" secondAttribute="trailing" constant="20" symbolic="YES" id="6yE-eh-4JC"/>
+                            <constraint firstItem="Arr-MX-tZv" firstAttribute="leading" secondItem="4fd-Yp-3nJ" secondAttribute="leading" constant="18" id="8eg-Kp-h0c"/>
+                            <constraint firstAttribute="trailing" secondItem="UoO-HA-SVc" secondAttribute="trailing" constant="15" id="9iT-QF-3zu"/>
+                            <constraint firstItem="nLW-cz-kvJ" firstAttribute="leading" secondItem="4fd-Yp-3nJ" secondAttribute="leadingMargin" constant="2" id="AYP-VA-cke"/>
+                            <constraint firstItem="oTL-pD-XOH" firstAttribute="leading" secondItem="4fd-Yp-3nJ" secondAttribute="leading" constant="15" id="C7P-k7-MdP"/>
+                            <constraint firstItem="nLW-cz-kvJ" firstAttribute="top" secondItem="4fd-Yp-3nJ" secondAttribute="topMargin" constant="190" id="CD7-4k-64T"/>
+                            <constraint firstItem="UoO-HA-SVc" firstAttribute="top" secondItem="oTL-pD-XOH" secondAttribute="bottom" constant="15" id="ERj-3C-f9B"/>
+                            <constraint firstItem="Arr-MX-tZv" firstAttribute="top" secondItem="JbV-43-RVv" secondAttribute="bottom" constant="20" id="Hxi-NT-Lc8"/>
+                            <constraint firstAttribute="trailing" secondItem="Z4E-xR-btY" secondAttribute="trailing" constant="15" id="Kdq-Sj-ttX"/>
+                            <constraint firstAttribute="trailing" secondItem="oTL-pD-XOH" secondAttribute="trailing" constant="15" id="Le2-p8-Glc"/>
+                            <constraint firstItem="hly-Eq-Kfh" firstAttribute="top" secondItem="4fd-Yp-3nJ" secondAttribute="topMargin" constant="191.5" id="UJ3-tj-4po"/>
+                            <constraint firstItem="lXS-nR-USh" firstAttribute="top" secondItem="JbV-43-RVv" secondAttribute="bottom" constant="21.5" id="UwR-E9-mAj"/>
+                            <constraint firstAttribute="trailing" secondItem="cjW-BP-ZFL" secondAttribute="trailing" constant="15" id="bq5-oJ-Kvz"/>
+                            <constraint firstItem="cjW-BP-ZFL" firstAttribute="top" secondItem="JbV-43-RVv" secondAttribute="bottom" constant="330" id="dsn-bv-ysa"/>
+                            <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="lXS-nR-USh" secondAttribute="trailing" constant="20" symbolic="YES" id="ebu-M3-TZ0"/>
+                            <constraint firstItem="Z4E-xR-btY" firstAttribute="top" secondItem="JbV-43-RVv" secondAttribute="bottom" constant="225" id="fdS-un-lzW"/>
+                            <constraint firstItem="cjW-BP-ZFL" firstAttribute="leading" secondItem="4fd-Yp-3nJ" secondAttribute="leading" constant="15" id="nHQ-pb-dMI"/>
+                            <constraint firstItem="hly-Eq-Kfh" firstAttribute="leading" secondItem="nLW-cz-kvJ" secondAttribute="trailing" constant="8" id="pfM-Px-JLB"/>
+                            <constraint firstItem="oTL-pD-XOH" firstAttribute="top" secondItem="JbV-43-RVv" secondAttribute="bottom" constant="50" id="uHI-5j-Kee"/>
+                            <constraint firstItem="lXS-nR-USh" firstAttribute="leading" secondItem="Arr-MX-tZv" secondAttribute="trailing" constant="8" id="wib-7k-aNB"/>
+                            <constraint firstItem="UoO-HA-SVc" firstAttribute="leading" secondItem="4fd-Yp-3nJ" secondAttribute="leading" constant="15" id="xLS-ek-2XS"/>
+                            <constraint firstItem="Z4E-xR-btY" firstAttribute="leading" secondItem="4fd-Yp-3nJ" secondAttribute="leading" constant="15" id="zhc-Cn-kTH"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" title="Certificate" id="TL5-4y-mEM">
+                        <barButtonItem key="rightBarButtonItem" image="GatewayDelete" id="H0t-dw-hku">
+                            <connections>
+                                <action selector="closeButtonClicked:" destination="ge6-AP-0um" id="Mfr-s9-Nmd"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                    <connections>
+                        <outlet property="addressTextField" destination="FJA-EM-1G3" id="c8g-dT-AFG"/>
+                        <outlet property="installButton" destination="cjW-BP-ZFL" id="SMv-iT-qNc"/>
+                        <outlet property="localCertTableView" destination="Z4E-xR-btY" id="kCw-Oo-izR"/>
+                        <outlet property="localSelectButton" destination="nLW-cz-kvJ" id="jqZ-cO-wtB"/>
+                        <outlet property="urlSelectButton" destination="Arr-MX-tZv" id="7mf-cd-ah6"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="ZvR-4T-YnU" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="5440.8000000000002" y="689.5052473763119"/>
+        </scene>
+        <!--GatewayNavigation-->
+        <scene sceneID="lf3-g6-jVa">
+            <objects>
+                <navigationController storyboardIdentifier="GatewayNavigationID" title="GatewayNavigation" automaticallyAdjustsScrollViewInsets="NO" id="idK-RG-cFM" sceneMemberID="viewController">
+                    <toolbarItems/>
+                    <navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="4K2-hC-btu">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        <color key="barTintColor" red="0.90588235294117647" green="0.0" blue="0.070588235294117646" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <textAttributes key="titleTextAttributes">
+                            <fontDescription key="fontDescription" type="boldSystem" pointSize="18"/>
+                            <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        </textAttributes>
+                    </navigationBar>
+                    <nil name="viewControllers"/>
+                    <connections>
+                        <segue destination="BYZ-38-t0r" kind="relationship" relationship="rootViewController" id="C7D-AS-2gf"/>
+                    </connections>
+                </navigationController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="ebJ-c7-H6h" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="117.59999999999999" y="690.40479760119945"/>
+        </scene>
+        <!--GatewaySettingsNavigation-->
+        <scene sceneID="8Tb-e8-GT6">
+            <objects>
+                <navigationController title="GatewaySettingsNavigation" automaticallyAdjustsScrollViewInsets="NO" id="LP6-tU-vWi" sceneMemberID="viewController">
+                    <toolbarItems/>
+                    <navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="W1g-yv-aUZ">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        <color key="barTintColor" red="0.90588235294117647" green="0.0" blue="0.070588235294117646" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <textAttributes key="titleTextAttributes">
+                            <fontDescription key="fontDescription" type="boldSystem" pointSize="18"/>
+                            <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        </textAttributes>
+                    </navigationBar>
+                    <nil name="viewControllers"/>
+                    <connections>
+                        <segue destination="XsL-WP-fGg" kind="relationship" relationship="rootViewController" id="cmf-Ie-86q"/>
+                    </connections>
+                </navigationController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="qPU-ev-P7K" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="1924" y="690"/>
+        </scene>
+        <!--LoginViewController-->
+        <scene sceneID="b0p-2j-xl6">
+            <objects>
+                <viewController title="LoginViewController" id="b5l-8Z-fX3" customClass="LoginViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="1DN-bp-EJl"/>
+                        <viewControllerLayoutGuide type="bottom" id="oXm-vm-vtE"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="soR-It-UbC">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <tableView clipsSubviews="YES" contentMode="scaleToFill" bounces="NO" scrollEnabled="NO" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="60" sectionHeaderHeight="15" sectionFooterHeight="1" translatesAutoresizingMaskIntoConstraints="NO" id="yPl-Nz-dId">
+                                <rect key="frame" x="0.0" y="0.0" width="375" height="310"/>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="310" id="u0Q-Ci-6Qx"/>
+                                </constraints>
+                                <color key="separatorColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <prototypes>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="LoginMethodCell" id="EHi-YO-eyO">
+                                        <rect key="frame" x="0.0" y="28" width="375" height="60"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="EHi-YO-eyO" id="Ga2-CA-3Ow">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginMethodName" translatesAutoresizingMaskIntoConstraints="NO" id="9py-By-48Z">
+                                                    <rect key="frame" x="38" y="22" width="16" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="height" constant="16" id="RgD-7G-4uy"/>
+                                                        <constraint firstAttribute="width" constant="16" id="ZXh-15-zuv"/>
+                                                    </constraints>
+                                                </imageView>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7xH-e1-dzC">
+                                                    <rect key="frame" x="69" y="0.0" width="306" height="60"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <imageView userInteractionEnabled="NO" tag="2" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginDropArrow" translatesAutoresizingMaskIntoConstraints="NO" id="Mg8-8x-MA8">
+                                                    <rect key="frame" x="339" y="26" width="13" height="8"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="13" id="DYc-0F-P3R"/>
+                                                        <constraint firstAttribute="height" constant="8" id="Iwh-O3-OX8"/>
+                                                    </constraints>
+                                                </imageView>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="9py-By-48Z" firstAttribute="leading" secondItem="Ga2-CA-3Ow" secondAttribute="leadingMargin" constant="22" id="5o2-cA-9fQ"/>
+                                                <constraint firstItem="7xH-e1-dzC" firstAttribute="top" secondItem="Ga2-CA-3Ow" secondAttribute="top" id="6Z3-iq-mpz"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="Mg8-8x-MA8" secondAttribute="trailing" constant="7" id="RLx-XR-lzm"/>
+                                                <constraint firstAttribute="bottom" secondItem="7xH-e1-dzC" secondAttribute="bottom" id="YYP-gn-dWe"/>
+                                                <constraint firstAttribute="trailing" secondItem="7xH-e1-dzC" secondAttribute="trailing" id="eM0-ft-fP6"/>
+                                                <constraint firstItem="Mg8-8x-MA8" firstAttribute="centerY" secondItem="Ga2-CA-3Ow" secondAttribute="centerY" id="gMQ-Wl-nnF"/>
+                                                <constraint firstItem="9py-By-48Z" firstAttribute="centerY" secondItem="Ga2-CA-3Ow" secondAttribute="centerY" id="p7l-x4-Nb5"/>
+                                                <constraint firstItem="7xH-e1-dzC" firstAttribute="leading" secondItem="9py-By-48Z" secondAttribute="trailing" constant="15" id="y9L-o4-z5I"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="LoginUsernameCell" id="NDm-Ji-2te">
+                                        <rect key="frame" x="0.0" y="88" width="375" height="60"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="NDm-Ji-2te" id="hWB-Bo-89k">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginUsername" translatesAutoresizingMaskIntoConstraints="NO" id="HQb-cc-76v">
+                                                    <rect key="frame" x="38" y="22" width="16" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="16" id="u3X-g7-Fj3"/>
+                                                        <constraint firstAttribute="height" constant="16" id="zbS-TB-O6I"/>
+                                                    </constraints>
+                                                </imageView>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Username" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="Ng3-FM-4LL">
+                                                    <rect key="frame" x="69" y="0.0" width="298" height="60"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits" returnKeyType="next"/>
+                                                    <connections>
+                                                        <outlet property="delegate" destination="b5l-8Z-fX3" id="rym-gW-6DF"/>
+                                                    </connections>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="HQb-cc-76v" firstAttribute="centerY" secondItem="hWB-Bo-89k" secondAttribute="centerY" id="2Yo-rD-Ygw"/>
+                                                <constraint firstItem="Ng3-FM-4LL" firstAttribute="top" secondItem="hWB-Bo-89k" secondAttribute="top" id="8hc-H9-bw2"/>
+                                                <constraint firstItem="Ng3-FM-4LL" firstAttribute="leading" secondItem="HQb-cc-76v" secondAttribute="trailing" constant="15" id="a3X-2Y-u65"/>
+                                                <constraint firstItem="HQb-cc-76v" firstAttribute="leading" secondItem="hWB-Bo-89k" secondAttribute="leadingMargin" constant="22" id="knC-iq-6MK"/>
+                                                <constraint firstAttribute="bottom" secondItem="Ng3-FM-4LL" secondAttribute="bottom" id="ouy-1v-nVF"/>
+                                                <constraint firstAttribute="trailing" secondItem="Ng3-FM-4LL" secondAttribute="trailing" constant="8" id="uAL-Y2-W5k"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="LoginPasswordCell" id="eR7-cR-QhZ">
+                                        <rect key="frame" x="0.0" y="148" width="375" height="60"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="eR7-cR-QhZ" id="jQq-9k-lhQ">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginPassword" translatesAutoresizingMaskIntoConstraints="NO" id="UMX-OB-kx0">
+                                                    <rect key="frame" x="38" y="22" width="16" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="height" constant="16" id="an0-dd-Emf"/>
+                                                        <constraint firstAttribute="width" constant="16" id="dcl-RO-fI7"/>
+                                                    </constraints>
+                                                </imageView>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Password" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="BYe-pr-0gN">
+                                                    <rect key="frame" x="69" y="0.0" width="298" height="60"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits" secureTextEntry="YES"/>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="trailing" secondItem="BYe-pr-0gN" secondAttribute="trailing" constant="8" id="EMa-yK-twW"/>
+                                                <constraint firstAttribute="bottom" secondItem="BYe-pr-0gN" secondAttribute="bottom" id="JOT-xs-CfB"/>
+                                                <constraint firstItem="BYe-pr-0gN" firstAttribute="top" secondItem="jQq-9k-lhQ" secondAttribute="top" id="LZM-q9-IBK"/>
+                                                <constraint firstItem="UMX-OB-kx0" firstAttribute="centerY" secondItem="jQq-9k-lhQ" secondAttribute="centerY" id="Pb8-2W-qgs"/>
+                                                <constraint firstItem="UMX-OB-kx0" firstAttribute="leading" secondItem="jQq-9k-lhQ" secondAttribute="leadingMargin" constant="22" id="ZNN-4r-f9M"/>
+                                                <constraint firstItem="BYe-pr-0gN" firstAttribute="leading" secondItem="UMX-OB-kx0" secondAttribute="trailing" constant="15" id="zry-9V-amM"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="LoginPassword2Cell" id="8XD-jR-JGc">
+                                        <rect key="frame" x="0.0" y="208" width="375" height="60"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="8XD-jR-JGc" id="9St-AD-g1q">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginPassword" translatesAutoresizingMaskIntoConstraints="NO" id="GOs-Xf-93O">
+                                                    <rect key="frame" x="38" y="22" width="16" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="height" constant="16" id="YDE-Qz-jwN"/>
+                                                        <constraint firstAttribute="width" constant="16" id="Z6L-WW-rcp"/>
+                                                    </constraints>
+                                                </imageView>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Password" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="WBC-j3-bju">
+                                                    <rect key="frame" x="69" y="0.0" width="298" height="60"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits" secureTextEntry="YES"/>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="trailing" secondItem="WBC-j3-bju" secondAttribute="trailing" constant="8" id="0PB-rq-UNs"/>
+                                                <constraint firstAttribute="bottom" secondItem="WBC-j3-bju" secondAttribute="bottom" id="8rC-p4-cb4"/>
+                                                <constraint firstItem="WBC-j3-bju" firstAttribute="top" secondItem="9St-AD-g1q" secondAttribute="top" id="DCn-jf-i3k"/>
+                                                <constraint firstItem="WBC-j3-bju" firstAttribute="leading" secondItem="GOs-Xf-93O" secondAttribute="trailing" constant="15" id="NaE-3Z-I7U"/>
+                                                <constraint firstItem="GOs-Xf-93O" firstAttribute="centerY" secondItem="9St-AD-g1q" secondAttribute="centerY" id="m9I-dH-xBR"/>
+                                                <constraint firstItem="GOs-Xf-93O" firstAttribute="leading" secondItem="9St-AD-g1q" secondAttribute="leadingMargin" constant="22" id="tcR-SP-cWl"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="LoginPassword3Cell" id="tcv-4Q-uf2">
+                                        <rect key="frame" x="0.0" y="268" width="375" height="60"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="tcv-4Q-uf2" id="se0-Iw-Atg">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginPassword" translatesAutoresizingMaskIntoConstraints="NO" id="pxH-M1-LKn">
+                                                    <rect key="frame" x="38" y="22" width="16" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="16" id="9yc-d6-iKI"/>
+                                                        <constraint firstAttribute="height" constant="16" id="fyT-rh-AtW"/>
+                                                    </constraints>
+                                                </imageView>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Password" minimumFontSize="17" clearButtonMode="unlessEditing" translatesAutoresizingMaskIntoConstraints="NO" id="WbM-xG-5wO">
+                                                    <rect key="frame" x="69" y="0.0" width="298" height="60"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits" secureTextEntry="YES"/>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="pxH-M1-LKn" firstAttribute="centerY" secondItem="se0-Iw-Atg" secondAttribute="centerY" id="51y-Zm-PlY"/>
+                                                <constraint firstItem="WbM-xG-5wO" firstAttribute="top" secondItem="se0-Iw-Atg" secondAttribute="top" id="Bvb-uQ-uoy"/>
+                                                <constraint firstAttribute="bottom" secondItem="WbM-xG-5wO" secondAttribute="bottom" id="C66-K5-6fF"/>
+                                                <constraint firstAttribute="trailing" secondItem="WbM-xG-5wO" secondAttribute="trailing" constant="8" id="HSz-Dr-pYM"/>
+                                                <constraint firstItem="WbM-xG-5wO" firstAttribute="leading" secondItem="pxH-M1-LKn" secondAttribute="trailing" constant="15" id="lPi-HR-9xh"/>
+                                                <constraint firstItem="pxH-M1-LKn" firstAttribute="leading" secondItem="se0-Iw-Atg" secondAttribute="leadingMargin" constant="22" id="ly8-VL-glD"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                </prototypes>
+                                <sections/>
+                                <connections>
+                                    <outlet property="dataSource" destination="b5l-8Z-fX3" id="V6c-qY-byk"/>
+                                    <outlet property="delegate" destination="b5l-8Z-fX3" id="Dz9-cr-uHB"/>
+                                </connections>
+                            </tableView>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="juX-Xb-hIb">
+                                <rect key="frame" x="15" y="345" width="345" height="50"/>
+                                <color key="backgroundColor" red="0.90588235294117647" green="0.0" blue="0.070588235294117646" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="50" id="uvY-JN-4i9"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                <state key="normal" title="Login">
+                                    <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                </state>
+                                <connections>
+                                    <action selector="loginButtonClicked:" destination="b5l-8Z-fX3" eventType="touchUpInside" id="HMl-Da-MHs"/>
+                                </connections>
+                            </button>
+                        </subviews>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <gestureRecognizers/>
+                        <constraints>
+                            <constraint firstAttribute="trailing" secondItem="yPl-Nz-dId" secondAttribute="trailing" id="InS-1e-X9j"/>
+                            <constraint firstItem="juX-Xb-hIb" firstAttribute="top" secondItem="yPl-Nz-dId" secondAttribute="bottom" constant="35" id="Ljw-ED-3H0"/>
+                            <constraint firstItem="juX-Xb-hIb" firstAttribute="leading" secondItem="soR-It-UbC" secondAttribute="leading" constant="15" id="OeV-gm-PZS"/>
+                            <constraint firstItem="yPl-Nz-dId" firstAttribute="leading" secondItem="soR-It-UbC" secondAttribute="leading" id="ZnM-1s-hqH"/>
+                            <constraint firstItem="yPl-Nz-dId" firstAttribute="top" secondItem="1DN-bp-EJl" secondAttribute="bottom" id="izh-n9-cwJ"/>
+                            <constraint firstAttribute="trailing" secondItem="juX-Xb-hIb" secondAttribute="trailing" constant="15" id="sKU-HK-ebF"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" title="Login" id="Wmb-C6-ThL">
+                        <barButtonItem key="rightBarButtonItem" image="LoginExit" id="gHd-dU-Gol">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            <connections>
+                                <action selector="exitButtonClicked:" destination="b5l-8Z-fX3" id="KHf-3E-X4k"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                    <connections>
+                        <outlet property="loginButton" destination="juX-Xb-hIb" id="nFg-cS-YXi"/>
+                        <outlet property="tableView" destination="yPl-Nz-dId" id="OVL-Ge-HIU"/>
+                        <outlet property="tableViewHeightConstraint" destination="u0Q-Ci-6Qx" id="3Hr-AO-JhT"/>
+                        <segue destination="MGw-hc-Bqe" kind="show" identifier="LoginToChangePassword" id="Iyn-qq-u9T"/>
+                        <segue destination="A29-A2-ywC" kind="show" identifier="LoginToRegister" id="sO0-s5-1Pp"/>
+                        <segue destination="Qv9-5w-hBC" kind="show" identifier="LoginToChallenge" id="3ah-39-IJ1"/>
+                        <segue destination="axh-t8-XkJ" kind="show" identifier="LoginToSMS" id="Xr9-Sq-bCI"/>
+                        <segue destination="Own-rK-e3P" kind="show" identifier="LoginToSyferLock" id="f3w-K1-XbV"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="LYB-28-XzO" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="2796" y="1804.9475262368817"/>
+        </scene>
+        <!--Register-->
+        <scene sceneID="yMl-II-Gfg">
+            <objects>
+                <viewController id="A29-A2-ywC" customClass="RegisterViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="r4c-Ow-sH6"/>
+                        <viewControllerLayoutGuide type="bottom" id="ZRV-XI-4sK"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="HOP-1B-zgP">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <tableView clipsSubviews="YES" contentMode="scaleToFill" bounces="NO" scrollEnabled="NO" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="60" sectionHeaderHeight="15" sectionFooterHeight="1" translatesAutoresizingMaskIntoConstraints="NO" id="j8h-Cg-Eax">
+                                <rect key="frame" x="0.0" y="0.0" width="375" height="195"/>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="195" id="6nG-hW-ZyK"/>
+                                </constraints>
+                                <color key="separatorColor" red="0.8862745098" green="0.8862745098" blue="0.8862745098" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <prototypes>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="RegisterUsernameCell" id="BZv-R7-xmh">
+                                        <rect key="frame" x="0.0" y="28" width="375" height="60"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="BZv-R7-xmh" id="hgS-NV-k22">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginUsername" translatesAutoresizingMaskIntoConstraints="NO" id="Oqq-Od-aq5">
+                                                    <rect key="frame" x="38" y="22" width="16" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="height" constant="16" id="FhU-2U-ywL"/>
+                                                        <constraint firstAttribute="width" constant="16" id="qXk-M0-hsO"/>
+                                                    </constraints>
+                                                </imageView>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Username" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="FMa-ck-fFH">
+                                                    <rect key="frame" x="69" y="0.0" width="298" height="60"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits"/>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="bottom" secondItem="FMa-ck-fFH" secondAttribute="bottom" id="4W4-Ko-8YJ"/>
+                                                <constraint firstItem="Oqq-Od-aq5" firstAttribute="leading" secondItem="hgS-NV-k22" secondAttribute="leadingMargin" constant="22" id="JRI-vU-QrP"/>
+                                                <constraint firstItem="FMa-ck-fFH" firstAttribute="top" secondItem="hgS-NV-k22" secondAttribute="top" id="NCr-0R-g2t"/>
+                                                <constraint firstItem="Oqq-Od-aq5" firstAttribute="centerY" secondItem="hgS-NV-k22" secondAttribute="centerY" id="clN-JP-BeW"/>
+                                                <constraint firstItem="FMa-ck-fFH" firstAttribute="leading" secondItem="Oqq-Od-aq5" secondAttribute="trailing" constant="15" id="stn-Dv-8eT"/>
+                                                <constraint firstAttribute="trailing" secondItem="FMa-ck-fFH" secondAttribute="trailing" constant="8" id="yS8-gU-fQg"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="RegisterPasswordCell" id="PPm-fN-k3B">
+                                        <rect key="frame" x="0.0" y="88" width="375" height="60"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="PPm-fN-k3B" id="R80-Za-JQG">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginPassword" translatesAutoresizingMaskIntoConstraints="NO" id="xa5-Ev-e6r">
+                                                    <rect key="frame" x="38" y="22" width="16" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="16" id="AcV-yK-IUo"/>
+                                                        <constraint firstAttribute="height" constant="16" id="rwx-7D-V8W"/>
+                                                    </constraints>
+                                                </imageView>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Password" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="dzG-jd-47k">
+                                                    <rect key="frame" x="69" y="0.0" width="298" height="60"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits" secureTextEntry="YES"/>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="xa5-Ev-e6r" firstAttribute="leading" secondItem="R80-Za-JQG" secondAttribute="leadingMargin" constant="22" id="3ts-hQ-klY"/>
+                                                <constraint firstItem="dzG-jd-47k" firstAttribute="top" secondItem="R80-Za-JQG" secondAttribute="top" id="79N-dx-T4g"/>
+                                                <constraint firstItem="xa5-Ev-e6r" firstAttribute="centerY" secondItem="R80-Za-JQG" secondAttribute="centerY" id="apF-6G-PWi"/>
+                                                <constraint firstAttribute="trailing" secondItem="dzG-jd-47k" secondAttribute="trailing" constant="8" id="j9l-wX-yoc"/>
+                                                <constraint firstAttribute="bottom" secondItem="dzG-jd-47k" secondAttribute="bottom" id="xTZ-HY-3ly"/>
+                                                <constraint firstItem="dzG-jd-47k" firstAttribute="leading" secondItem="xa5-Ev-e6r" secondAttribute="trailing" constant="15" id="yrl-pf-dj4"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="RegisterDeviceNameCell" id="wHL-5P-nIf">
+                                        <rect key="frame" x="0.0" y="148" width="375" height="60"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="wHL-5P-nIf" id="r3W-bH-Cpu">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="n6p-E3-OCI">
+                                                    <rect key="frame" x="152.5" y="0.0" width="214.5" height="60"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits"/>
+                                                </textField>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="1000" text="Device Name:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gLM-TK-KzW">
+                                                    <rect key="frame" x="38" y="19.5" width="106" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="bottom" secondItem="n6p-E3-OCI" secondAttribute="bottom" id="4Fx-Sj-kGV"/>
+                                                <constraint firstAttribute="trailing" secondItem="n6p-E3-OCI" secondAttribute="trailing" constant="8" id="5IE-T8-2sZ"/>
+                                                <constraint firstItem="n6p-E3-OCI" firstAttribute="top" secondItem="r3W-bH-Cpu" secondAttribute="top" id="JBu-fH-Pta"/>
+                                                <constraint firstItem="gLM-TK-KzW" firstAttribute="leading" secondItem="r3W-bH-Cpu" secondAttribute="leadingMargin" constant="22" id="oQ5-KI-ywV"/>
+                                                <constraint firstItem="n6p-E3-OCI" firstAttribute="leading" secondItem="gLM-TK-KzW" secondAttribute="trailing" constant="8.5" id="wOT-ZX-56l"/>
+                                                <constraint firstItem="gLM-TK-KzW" firstAttribute="centerY" secondItem="r3W-bH-Cpu" secondAttribute="centerY" id="wnv-Ft-1Yr"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                </prototypes>
+                                <sections/>
+                                <connections>
+                                    <outlet property="dataSource" destination="A29-A2-ywC" id="xC8-Oy-LkW"/>
+                                    <outlet property="delegate" destination="A29-A2-ywC" id="zWB-Cr-Pda"/>
+                                </connections>
+                            </tableView>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Pbw-TK-XUH">
+                                <rect key="frame" x="15" y="235" width="345" height="50"/>
+                                <color key="backgroundColor" red="0.90588235294117647" green="0.0" blue="0.070588235294117646" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="50" id="DYJ-nA-Eg7"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                <state key="normal" title="Register">
+                                    <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                </state>
+                                <connections>
+                                    <action selector="loginButtonClicked:" destination="b5l-8Z-fX3" eventType="touchUpInside" id="q74-AZ-KcJ"/>
+                                    <action selector="registerButtonClicked:" destination="A29-A2-ywC" eventType="touchUpInside" id="thg-yU-YnC"/>
+                                </connections>
+                            </button>
+                        </subviews>
+                        <color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <constraints>
+                            <constraint firstItem="Pbw-TK-XUH" firstAttribute="top" secondItem="j8h-Cg-Eax" secondAttribute="bottom" constant="40" id="DN6-Pp-wYE"/>
+                            <constraint firstAttribute="trailing" secondItem="j8h-Cg-Eax" secondAttribute="trailing" id="Fig-tR-38v"/>
+                            <constraint firstItem="j8h-Cg-Eax" firstAttribute="top" secondItem="r4c-Ow-sH6" secondAttribute="bottom" id="I6E-gn-Gna"/>
+                            <constraint firstItem="Pbw-TK-XUH" firstAttribute="leading" secondItem="HOP-1B-zgP" secondAttribute="leading" constant="15" id="LN9-KY-ojG"/>
+                            <constraint firstAttribute="trailing" secondItem="Pbw-TK-XUH" secondAttribute="trailing" constant="15" id="rCa-HH-paQ"/>
+                            <constraint firstItem="j8h-Cg-Eax" firstAttribute="leading" secondItem="HOP-1B-zgP" secondAttribute="leading" id="vfP-L1-ROT"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" title="Register" id="aHJ-lm-gVt">
+                        <barButtonItem key="leftBarButtonItem" title="Cancel" id="yPq-1N-cfx">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            <connections>
+                                <action selector="cancelButtonClicked:" destination="A29-A2-ywC" id="0EG-yG-Da1"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                    <connections>
+                        <outlet property="registerButton" destination="Pbw-TK-XUH" id="442-X6-atp"/>
+                        <outlet property="tableView" destination="j8h-Cg-Eax" id="Nkx-uy-p8O"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="WKG-Ms-hFh" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="3664.8000000000002" y="1804.9475262368817"/>
+        </scene>
+        <!--Challenge-->
+        <scene sceneID="4sx-It-vfN">
+            <objects>
+                <viewController id="Qv9-5w-hBC" customClass="ChallengeViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="yZz-4a-ccD"/>
+                        <viewControllerLayoutGuide type="bottom" id="Eas-o5-h4e"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="1Zb-xl-XyS">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <tableView clipsSubviews="YES" contentMode="scaleToFill" bounces="NO" dataMode="prototypes" style="grouped" separatorStyle="default" allowsSelection="NO" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" translatesAutoresizingMaskIntoConstraints="NO" id="VTT-we-cnt">
+                                <rect key="frame" x="0.0" y="0.0" width="375" height="75"/>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="75" id="1zN-bi-q3G"/>
+                                </constraints>
+                                <color key="separatorColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="calibratedRGB"/>
+                                <prototypes>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="ChallengePasswordCell" id="tnh-FZ-LtH">
+                                        <rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="tnh-FZ-LtH" id="TvW-8M-FMf">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginPassword" translatesAutoresizingMaskIntoConstraints="NO" id="f96-7e-hfK">
+                                                    <rect key="frame" x="23" y="14" width="16" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="height" constant="16" id="hxB-DA-eED"/>
+                                                        <constraint firstAttribute="width" constant="16" id="omO-tp-o2Z"/>
+                                                    </constraints>
+                                                </imageView>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Password" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="QYy-f0-w8v">
+                                                    <rect key="frame" x="49" y="0.0" width="311" height="44"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits" secureTextEntry="YES"/>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="trailing" secondItem="QYy-f0-w8v" secondAttribute="trailing" constant="15" id="42j-2d-OW3"/>
+                                                <constraint firstAttribute="bottom" secondItem="QYy-f0-w8v" secondAttribute="bottom" id="4k8-Wi-a1F"/>
+                                                <constraint firstItem="QYy-f0-w8v" firstAttribute="leading" secondItem="f96-7e-hfK" secondAttribute="trailing" constant="10" id="E0v-Sk-eeS"/>
+                                                <constraint firstItem="f96-7e-hfK" firstAttribute="centerY" secondItem="TvW-8M-FMf" secondAttribute="centerY" id="Nlp-Z7-u0n"/>
+                                                <constraint firstItem="f96-7e-hfK" firstAttribute="leading" secondItem="TvW-8M-FMf" secondAttribute="leadingMargin" constant="7" id="e7F-tL-zeK"/>
+                                                <constraint firstItem="QYy-f0-w8v" firstAttribute="top" secondItem="TvW-8M-FMf" secondAttribute="top" id="qnv-gI-M6h"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                </prototypes>
+                                <connections>
+                                    <outlet property="dataSource" destination="Qv9-5w-hBC" id="fG0-JY-Hwd"/>
+                                    <outlet property="delegate" destination="Qv9-5w-hBC" id="fwC-wA-F2p"/>
+                                </connections>
+                            </tableView>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kzl-9l-9Ef">
+                                <rect key="frame" x="15" y="120" width="345" height="50"/>
+                                <color key="backgroundColor" red="0.90588235294117647" green="0.0" blue="0.070588235294117646" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="50" id="RPp-IU-QdT"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                <state key="normal" title="Login">
+                                    <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                </state>
+                                <connections>
+                                    <action selector="loginButtonClicked:" destination="Qv9-5w-hBC" eventType="touchUpInside" id="3Fw-Tq-qBb"/>
+                                    <action selector="loginButtonClicked:" destination="b5l-8Z-fX3" eventType="touchUpInside" id="sLr-X7-gTy"/>
+                                </connections>
+                            </button>
+                        </subviews>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="calibratedRGB"/>
+                        <constraints>
+                            <constraint firstItem="kzl-9l-9Ef" firstAttribute="leading" secondItem="1Zb-xl-XyS" secondAttribute="leading" constant="15" id="45B-nk-KYJ"/>
+                            <constraint firstAttribute="trailing" secondItem="kzl-9l-9Ef" secondAttribute="trailing" constant="15" id="edV-wK-cBf"/>
+                            <constraint firstItem="VTT-we-cnt" firstAttribute="leading" secondItem="1Zb-xl-XyS" secondAttribute="leading" id="f98-DC-F16"/>
+                            <constraint firstItem="VTT-we-cnt" firstAttribute="top" secondItem="yZz-4a-ccD" secondAttribute="bottom" id="hM8-8u-Ke5"/>
+                            <constraint firstItem="kzl-9l-9Ef" firstAttribute="top" secondItem="VTT-we-cnt" secondAttribute="bottom" constant="45" id="rxT-vs-Bic"/>
+                            <constraint firstAttribute="trailing" secondItem="VTT-we-cnt" secondAttribute="trailing" id="zL6-EK-fxL"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" title="Challenge" id="EhN-hu-nGU">
+                        <barButtonItem key="leftBarButtonItem" title="Cancel" id="WOr-DE-WNk">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                            <connections>
+                                <action selector="cancelButtonClicked:" destination="Qv9-5w-hBC" id="jcg-19-qT7"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                    <connections>
+                        <outlet property="loginButton" destination="kzl-9l-9Ef" id="f1D-ue-Rrh"/>
+                        <outlet property="tableView" destination="VTT-we-cnt" id="bWs-dg-BPN"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="WYE-DD-Yek" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="3664.8000000000002" y="2623.5382308845578"/>
+        </scene>
+        <!--SMS-->
+        <scene sceneID="pcD-2e-Qek">
+            <objects>
+                <viewController id="axh-t8-XkJ" userLabel="SMS" customClass="SMSViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="YbF-IW-N0J"/>
+                        <viewControllerLayoutGuide type="bottom" id="7UW-9S-1DG"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="zfg-q5-hIg">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <tableView clipsSubviews="YES" contentMode="scaleToFill" bounces="NO" dataMode="prototypes" style="grouped" separatorStyle="default" allowsSelection="NO" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" translatesAutoresizingMaskIntoConstraints="NO" id="tYf-Cx-xgr">
+                                <rect key="frame" x="0.0" y="0.0" width="375" height="75"/>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="75" id="byo-tF-H87"/>
+                                </constraints>
+                                <color key="separatorColor" red="0.8862745098" green="0.8862745098" blue="0.8862745098" alpha="1" colorSpace="calibratedRGB"/>
+                                <prototypes>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="ValidateCodeCellID" id="723-mL-Qnc">
+                                        <rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="723-mL-Qnc" id="zuF-UF-KZu">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginPassword" translatesAutoresizingMaskIntoConstraints="NO" id="bYS-z6-32w">
+                                                    <rect key="frame" x="23" y="14" width="16" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="16" id="AQ5-j3-Abm"/>
+                                                        <constraint firstAttribute="height" constant="16" id="ccH-Dk-G6x"/>
+                                                    </constraints>
+                                                </imageView>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Verification Code" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="Wkf-H4-MkU">
+                                                    <rect key="frame" x="49" y="0.0" width="223" height="45"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits"/>
+                                                </textField>
+                                                <button opaque="NO" tag="2" contentMode="scaleToFill" horizontalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="W4E-oF-QCg">
+                                                    <rect key="frame" x="270" y="7" width="90" height="30"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="90" id="VLm-6K-t9k"/>
+                                                    </constraints>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <state key="normal" title="Resend">
+                                                        <color key="titleColor" red="0.89411764709999997" green="0.43921568630000002" blue="0.1137254902" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    </state>
+                                                    <state key="highlighted" title="Resend">
+                                                        <color key="titleColor" red="0.89411764709999997" green="0.43921568630000002" blue="0.1137254902" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    </state>
+                                                </button>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="trailing" secondItem="W4E-oF-QCg" secondAttribute="trailing" constant="15" id="5dO-vl-AKa"/>
+                                                <constraint firstItem="Wkf-H4-MkU" firstAttribute="leading" secondItem="bYS-z6-32w" secondAttribute="trailing" constant="10" id="Knm-pn-mYg"/>
+                                                <constraint firstItem="W4E-oF-QCg" firstAttribute="centerY" secondItem="zuF-UF-KZu" secondAttribute="centerY" id="VoL-M7-vyO"/>
+                                                <constraint firstItem="bYS-z6-32w" firstAttribute="leading" secondItem="zuF-UF-KZu" secondAttribute="leadingMargin" constant="7" id="aF9-bE-5c1"/>
+                                                <constraint firstItem="bYS-z6-32w" firstAttribute="centerY" secondItem="zuF-UF-KZu" secondAttribute="centerY" id="aua-TM-OQb"/>
+                                                <constraint firstItem="Wkf-H4-MkU" firstAttribute="top" secondItem="zuF-UF-KZu" secondAttribute="top" id="kay-cg-6Mw"/>
+                                                <constraint firstAttribute="bottom" secondItem="Wkf-H4-MkU" secondAttribute="bottom" constant="-1" id="mAd-0a-5Kt"/>
+                                                <constraint firstItem="W4E-oF-QCg" firstAttribute="leading" secondItem="Wkf-H4-MkU" secondAttribute="trailing" constant="-2" id="nFf-9K-y4u"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                </prototypes>
+                                <connections>
+                                    <outlet property="dataSource" destination="axh-t8-XkJ" id="JPu-9h-IpA"/>
+                                    <outlet property="delegate" destination="axh-t8-XkJ" id="kf9-F3-jfa"/>
+                                </connections>
+                            </tableView>
+                            <button opaque="NO" tag="2" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="UOd-np-41k">
+                                <rect key="frame" x="15" y="120" width="345" height="50"/>
+                                <color key="backgroundColor" red="0.90588235294117647" green="0.0" blue="0.070588235294117646" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="50" id="icY-tA-0j1"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                <state key="normal" title="Login">
+                                    <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                </state>
+                                <connections>
+                                    <action selector="loginButtonClicked:" destination="b5l-8Z-fX3" eventType="touchUpInside" id="A85-zG-8B3"/>
+                                    <action selector="loginButtonClicked:" destination="axh-t8-XkJ" eventType="touchUpInside" id="Psh-At-hvb"/>
+                                    <action selector="loginButtonClicked:" destination="Qv9-5w-hBC" eventType="touchUpInside" id="bEB-CX-zy1"/>
+                                </connections>
+                            </button>
+                        </subviews>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="calibratedRGB"/>
+                        <constraints>
+                            <constraint firstItem="UOd-np-41k" firstAttribute="top" secondItem="tYf-Cx-xgr" secondAttribute="bottom" constant="45" id="714-tV-VIp"/>
+                            <constraint firstItem="UOd-np-41k" firstAttribute="leading" secondItem="zfg-q5-hIg" secondAttribute="leading" constant="15" id="Ets-1C-895"/>
+                            <constraint firstItem="tYf-Cx-xgr" firstAttribute="leading" secondItem="zfg-q5-hIg" secondAttribute="leading" id="Iio-3P-dXe"/>
+                            <constraint firstAttribute="trailing" secondItem="UOd-np-41k" secondAttribute="trailing" constant="15" id="WEe-mz-UKY"/>
+                            <constraint firstAttribute="trailing" secondItem="tYf-Cx-xgr" secondAttribute="trailing" id="cmX-kT-WHf"/>
+                            <constraint firstItem="tYf-Cx-xgr" firstAttribute="top" secondItem="YbF-IW-N0J" secondAttribute="bottom" id="fTj-Uu-qr1"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" title="OTP Authentication" id="2GC-VR-kJB">
+                        <barButtonItem key="leftBarButtonItem" title="Cancel" id="hGm-60-ZTY">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                            <connections>
+                                <action selector="cancelButtonClicked:" destination="axh-t8-XkJ" id="gdJ-SW-FFw"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                    <connections>
+                        <outlet property="loginButton" destination="UOd-np-41k" id="O6R-i0-Xig"/>
+                        <outlet property="tableView" destination="tYf-Cx-xgr" id="7YT-TS-6iB"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="CoK-La-pf4" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="4532" y="2623.5382308845578"/>
+        </scene>
+        <!--Remote Desktop-->
+        <scene sceneID="JJ1-oV-W3X">
+            <objects>
+                <viewController id="EyZ-YP-cnm" customClass="CustomDesktopViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="VWM-U1-5o9"/>
+                        <viewControllerLayoutGuide type="bottom" id="YXS-ze-ieJ"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="c8C-Mw-TJi">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <tableView clipsSubviews="YES" contentMode="scaleToFill" bounces="NO" scrollEnabled="NO" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="66" sectionHeaderHeight="15" sectionFooterHeight="1" translatesAutoresizingMaskIntoConstraints="NO" id="SdP-hh-QXC">
+                                <rect key="frame" x="0.0" y="0.0" width="375" height="213"/>
+                                <color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="213" id="1YP-8G-8ld"/>
+                                </constraints>
+                                <color key="separatorColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="calibratedRGB"/>
+                                <prototypes>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="HostnameCellID" id="etB-7Z-yn2">
+                                        <rect key="frame" x="0.0" y="55.5" width="375" height="66"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="etB-7Z-yn2" id="gMD-73-OSA">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="66"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Host/IP" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="uEq-nN-ns5">
+                                                    <rect key="frame" x="15" y="0.0" width="352" height="66"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits"/>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="uEq-nN-ns5" firstAttribute="leading" secondItem="gMD-73-OSA" secondAttribute="leading" constant="15" id="B5n-QH-6ks"/>
+                                                <constraint firstItem="uEq-nN-ns5" firstAttribute="top" secondItem="gMD-73-OSA" secondAttribute="top" id="g4H-pu-NeQ"/>
+                                                <constraint firstAttribute="trailing" secondItem="uEq-nN-ns5" secondAttribute="trailing" constant="8" id="m8M-Nd-goU"/>
+                                                <constraint firstAttribute="bottom" secondItem="uEq-nN-ns5" secondAttribute="bottom" id="wkY-LW-N8M"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="UsernameCellID" id="cvj-EV-isL">
+                                        <rect key="frame" x="0.0" y="121.5" width="375" height="66"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="cvj-EV-isL" id="bLG-Jv-A7P">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="66"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Username" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="GD0-qw-dtZ">
+                                                    <rect key="frame" x="15" y="0.0" width="352" height="66"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits"/>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="GD0-qw-dtZ" firstAttribute="leading" secondItem="bLG-Jv-A7P" secondAttribute="leading" constant="15" id="Z1u-Fo-sjt"/>
+                                                <constraint firstItem="GD0-qw-dtZ" firstAttribute="top" secondItem="bLG-Jv-A7P" secondAttribute="top" id="aHq-h6-HkE"/>
+                                                <constraint firstAttribute="bottom" secondItem="GD0-qw-dtZ" secondAttribute="bottom" id="bR5-fk-ZfA"/>
+                                                <constraint firstAttribute="trailing" secondItem="GD0-qw-dtZ" secondAttribute="trailing" constant="8" id="gDV-IP-KmW"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="DomainCellID" id="qnG-5C-1eQ">
+                                        <rect key="frame" x="0.0" y="187.5" width="375" height="66"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="qnG-5C-1eQ" id="mUl-yZ-dMC">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="66"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Domain" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="Q7j-qj-9b8">
+                                                    <rect key="frame" x="15" y="0.0" width="352" height="66"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits"/>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="Q7j-qj-9b8" firstAttribute="leading" secondItem="mUl-yZ-dMC" secondAttribute="leading" constant="15" id="2w0-g0-FC4"/>
+                                                <constraint firstAttribute="bottom" secondItem="Q7j-qj-9b8" secondAttribute="bottom" id="AXg-1v-Hfr"/>
+                                                <constraint firstItem="Q7j-qj-9b8" firstAttribute="top" secondItem="mUl-yZ-dMC" secondAttribute="top" id="OpS-hS-cYR"/>
+                                                <constraint firstAttribute="trailing" secondItem="Q7j-qj-9b8" secondAttribute="trailing" constant="8" id="dLC-b2-dtN"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </prototypes>
+                                <connections>
+                                    <outlet property="dataSource" destination="EyZ-YP-cnm" id="glA-Sa-g6B"/>
+                                    <outlet property="delegate" destination="EyZ-YP-cnm" id="uzs-PR-4Fq"/>
+                                </connections>
+                            </tableView>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="cOm-0d-WcQ">
+                                <rect key="frame" x="15" y="258" width="345" height="50"/>
+                                <color key="backgroundColor" red="0.90588235294117647" green="0.0" blue="0.070588235294117646" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="50" id="lA9-cA-1fW"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                <state key="normal" title="Connect">
+                                    <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                </state>
+                                <connections>
+                                    <action selector="connectButtonClicked:" destination="EyZ-YP-cnm" eventType="touchUpInside" id="kga-2U-pIz"/>
+                                    <action selector="loginButtonClicked:" destination="b5l-8Z-fX3" eventType="touchUpInside" id="2xf-Pf-bE4"/>
+                                </connections>
+                            </button>
+                        </subviews>
+                        <color key="backgroundColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="calibratedRGB"/>
+                        <constraints>
+                            <constraint firstAttribute="trailing" secondItem="cOm-0d-WcQ" secondAttribute="trailing" constant="15" id="1FF-Oy-GiT"/>
+                            <constraint firstItem="SdP-hh-QXC" firstAttribute="top" secondItem="VWM-U1-5o9" secondAttribute="bottom" id="2p8-dW-pSI"/>
+                            <constraint firstItem="cOm-0d-WcQ" firstAttribute="leading" secondItem="c8C-Mw-TJi" secondAttribute="leading" constant="15" id="fNM-Y8-wtw"/>
+                            <constraint firstItem="cOm-0d-WcQ" firstAttribute="top" secondItem="SdP-hh-QXC" secondAttribute="bottom" constant="45" id="g7m-A8-RTu"/>
+                            <constraint firstAttribute="trailing" secondItem="SdP-hh-QXC" secondAttribute="trailing" id="gNm-Jx-2iq"/>
+                            <constraint firstItem="SdP-hh-QXC" firstAttribute="leading" secondItem="c8C-Mw-TJi" secondAttribute="leading" id="vka-uQ-P8W"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" title="Remote Desktop" id="rIh-wP-43Y"/>
+                    <connections>
+                        <outlet property="connectButton" destination="cOm-0d-WcQ" id="ObK-fm-Ebi"/>
+                        <outlet property="tableView" destination="SdP-hh-QXC" id="eiW-cw-c6i"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="uUH-qY-4Qt" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="-1876" y="4589.9550224887562"/>
+        </scene>
+        <!--Sub Resource View Controller-->
+        <scene sceneID="aB2-YP-vxA">
+            <objects>
+                <tableViewController storyboardIdentifier="SubResourceViewControllerID" id="ixp-zo-wwn" customClass="SubResourceViewController" sceneMemberID="viewController">
+                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="i4P-Z6-S9g">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
+                        <color key="separatorColor" red="0.8862745098" green="0.8862745098" blue="0.8862745098" alpha="1" colorSpace="calibratedRGB"/>
+                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                        <connections>
+                            <outlet property="dataSource" destination="ixp-zo-wwn" id="hHh-w9-ItC"/>
+                            <outlet property="delegate" destination="ixp-zo-wwn" id="Dj0-Kz-Mk6"/>
+                        </connections>
+                    </tableView>
+                </tableViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="NUl-g4-55J" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="-1018" y="4590"/>
+        </scene>
+        <!--Access Mode Select View Controller-->
+        <scene sceneID="Ne8-3d-fdj">
+            <objects>
+                <tableViewController storyboardIdentifier="AcsModeViewControllerID" id="Lt7-EO-i16" customClass="AccessModeSelectViewController" sceneMemberID="viewController">
+                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="47q-3J-XW7">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
+                        <color key="separatorColor" red="0.88627450980392153" green="0.88627450980392153" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
+                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                        <connections>
+                            <outlet property="dataSource" destination="Lt7-EO-i16" id="DeZ-Ly-dbI"/>
+                            <outlet property="delegate" destination="Lt7-EO-i16" id="BxC-eJ-gED"/>
+                        </connections>
+                    </tableView>
+                    <navigationItem key="navigationItem" id="WsC-qd-FpB">
+                        <barButtonItem key="leftBarButtonItem" title="Cancel" id="OtV-xl-Ohs">
+                            <color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
+                            <connections>
+                                <action selector="cancelButtonClicked:" destination="Lt7-EO-i16" id="vjS-CA-vV7"/>
+                            </connections>
+                        </barButtonItem>
+                        <barButtonItem key="rightBarButtonItem" title="Confirm" id="yeD-Au-sFK">
+                            <color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
+                            <connections>
+                                <action selector="saveButtonClicked:" destination="Lt7-EO-i16" id="VN8-4x-rAN"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                </tableViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="Iow-K3-TGC" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="687" y="4590"/>
+        </scene>
+        <!--Navigation Controller-->
+        <scene sceneID="AGU-BE-BrM">
+            <objects>
+                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="RPI-UI-YjC" sceneMemberID="viewController">
+                    <navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="Jdo-AZ-1vk">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
+                        <color key="barTintColor" red="0.90588235294117647" green="0.0" blue="0.070588235294117646" alpha="1" colorSpace="calibratedRGB"/>
+                    </navigationBar>
+                    <connections>
+                        <segue destination="Lt7-EO-i16" kind="relationship" relationship="rootViewController" id="FEy-OB-dHW"/>
+                    </connections>
+                </navigationController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="U3E-52-6EV" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="-137" y="4590"/>
+        </scene>
+        <!--Gateway-->
+        <scene sceneID="Cah-u3-yRy">
+            <objects>
+                <viewController id="v1Y-JU-ghZ" customClass="ResourcesViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="jte-We-k7c"/>
+                        <viewControllerLayoutGuide type="bottom" id="spO-fb-3hh"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="cM6-BE-uc6">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qPJ-dc-5yP">
+                                <rect key="frame" x="0.0" y="0.0" width="375" height="50"/>
+                                <subviews>
+                                    <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="tih-jI-rGn">
+                                        <rect key="frame" x="311" y="9.5" width="51" height="31"/>
+                                        <connections>
+                                            <action selector="vpnEnableSwitched:" destination="v1Y-JU-ghZ" eventType="valueChanged" id="iL2-0D-4Fm"/>
+                                        </connections>
+                                    </switch>
+                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Secure Tunnel" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="PWl-K8-Dro">
+                                        <rect key="frame" x="15" y="14.5" width="112" height="21"/>
+                                        <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                        <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                        <nil key="highlightedColor"/>
+                                    </label>
+                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Connecting..." textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FFN-Tu-ZTR">
+                                        <rect key="frame" x="211" y="16" width="92" height="18"/>
+                                        <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                        <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                        <nil key="highlightedColor"/>
+                                    </label>
+                                    <activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="jEM-OB-Frs">
+                                        <rect key="frame" x="183" y="15" width="20" height="20"/>
+                                    </activityIndicatorView>
+                                    <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ResourceConnectSuccess" translatesAutoresizingMaskIntoConstraints="NO" id="4qi-ej-DYj">
+                                        <rect key="frame" x="189" y="18" width="14" height="14"/>
+                                        <constraints>
+                                            <constraint firstAttribute="width" constant="14" id="TtM-hi-btC"/>
+                                            <constraint firstAttribute="height" constant="14" id="dEQ-mr-7fK"/>
+                                        </constraints>
+                                    </imageView>
+                                </subviews>
+                                <color key="backgroundColor" red="0.98039215686274506" green="0.98039215686274506" blue="0.98039215686274506" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstItem="4qi-ej-DYj" firstAttribute="centerY" secondItem="qPJ-dc-5yP" secondAttribute="centerY" id="0yz-xn-UBa"/>
+                                    <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="PWl-K8-Dro" secondAttribute="trailing" constant="20" symbolic="YES" id="3O5-Wc-fl1"/>
+                                    <constraint firstItem="tih-jI-rGn" firstAttribute="centerY" secondItem="qPJ-dc-5yP" secondAttribute="centerY" id="6Km-eu-1dT"/>
+                                    <constraint firstAttribute="trailing" secondItem="tih-jI-rGn" secondAttribute="trailing" constant="15" id="CSc-q1-LGc"/>
+                                    <constraint firstItem="PWl-K8-Dro" firstAttribute="centerY" secondItem="qPJ-dc-5yP" secondAttribute="centerY" id="SfX-pu-Hck"/>
+                                    <constraint firstItem="PWl-K8-Dro" firstAttribute="leading" secondItem="qPJ-dc-5yP" secondAttribute="leading" constant="15" id="Y3C-14-l81"/>
+                                    <constraint firstItem="jEM-OB-Frs" firstAttribute="centerY" secondItem="qPJ-dc-5yP" secondAttribute="centerY" id="Yl4-Id-Myy"/>
+                                    <constraint firstItem="FFN-Tu-ZTR" firstAttribute="centerY" secondItem="qPJ-dc-5yP" secondAttribute="centerY" id="aX6-Om-muy"/>
+                                    <constraint firstItem="tih-jI-rGn" firstAttribute="leading" secondItem="FFN-Tu-ZTR" secondAttribute="trailing" constant="8" id="cBZ-Gs-M7Q"/>
+                                    <constraint firstAttribute="height" constant="50" id="pLS-7h-weF"/>
+                                    <constraint firstItem="FFN-Tu-ZTR" firstAttribute="leading" secondItem="4qi-ej-DYj" secondAttribute="trailing" constant="8" id="q5O-pe-eyM"/>
+                                    <constraint firstItem="FFN-Tu-ZTR" firstAttribute="leading" secondItem="jEM-OB-Frs" secondAttribute="trailing" constant="8" id="s5d-Wc-rut"/>
+                                </constraints>
+                            </view>
+                            <tableView hidden="YES" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" scrollEnabled="NO" dataMode="prototypes" style="grouped" rowHeight="44" sectionHeaderHeight="-1" sectionFooterHeight="-1" translatesAutoresizingMaskIntoConstraints="NO" id="fVv-Jr-fwe">
+                                <rect key="frame" x="0.0" y="45" width="375" height="50"/>
+                                <color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="50" id="1Qf-xq-abz"/>
+                                </constraints>
+                                <color key="separatorColor" red="0.98039215686274506" green="0.98039215686274506" blue="0.98039215686274506" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                <connections>
+                                    <outlet property="dataSource" destination="v1Y-JU-ghZ" id="gUP-Ln-clk"/>
+                                    <outlet property="delegate" destination="v1Y-JU-ghZ" id="a5Q-8i-KX0"/>
+                                </connections>
+                            </tableView>
+                            <view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BGN-X3-l8M">
+                                <rect key="frame" x="0.0" y="50" width="375" height="50"/>
+                                <subviews>
+                                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ppE-On-UgE">
+                                        <rect key="frame" x="15" y="0.0" width="345" height="1"/>
+                                        <color key="backgroundColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="calibratedRGB"/>
+                                        <constraints>
+                                            <constraint firstAttribute="height" constant="1" id="tue-lM-ylZ"/>
+                                        </constraints>
+                                    </view>
+                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hhP-By-cX0">
+                                        <rect key="frame" x="170" y="16.5" width="35.5" height="17"/>
+                                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                        <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
+                                        <nil key="highlightedColor"/>
+                                    </label>
+                                </subviews>
+                                <color key="backgroundColor" red="0.98039215686274506" green="0.98039215686274506" blue="0.98039215686274506" alpha="1" colorSpace="calibratedRGB"/>
+                                <constraints>
+                                    <constraint firstItem="ppE-On-UgE" firstAttribute="top" secondItem="BGN-X3-l8M" secondAttribute="top" id="3aJ-1O-Ev3"/>
+                                    <constraint firstItem="hhP-By-cX0" firstAttribute="centerX" secondItem="BGN-X3-l8M" secondAttribute="centerX" id="Cyt-SX-yT4"/>
+                                    <constraint firstItem="ppE-On-UgE" firstAttribute="leading" secondItem="BGN-X3-l8M" secondAttribute="leading" constant="15" id="OcB-wq-M3J"/>
+                                    <constraint firstItem="hhP-By-cX0" firstAttribute="centerY" secondItem="BGN-X3-l8M" secondAttribute="centerY" id="dLG-Qb-PCQ"/>
+                                    <constraint firstAttribute="height" constant="50" id="fqC-er-5ET"/>
+                                    <constraint firstItem="ppE-On-UgE" firstAttribute="centerX" secondItem="BGN-X3-l8M" secondAttribute="centerX" id="pMx-ZS-QwR"/>
+                                </constraints>
+                            </view>
+                            <view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fSs-by-PN4">
+                                <rect key="frame" x="0.0" y="50" width="375" height="524"/>
+                                <subviews>
+                                    <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ResourceEmpty" translatesAutoresizingMaskIntoConstraints="NO" id="qeA-Ck-j1u">
+                                        <rect key="frame" x="117.5" y="95" width="140" height="128"/>
+                                        <constraints>
+                                            <constraint firstAttribute="height" constant="128" id="1Es-6G-ZAk"/>
+                                            <constraint firstAttribute="width" constant="140" id="o1x-P9-4kq"/>
+                                        </constraints>
+                                    </imageView>
+                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="No resource has been found" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iYp-n0-3JW">
+                                        <rect key="frame" x="96" y="253" width="183" height="17"/>
+                                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                        <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
+                                        <nil key="highlightedColor"/>
+                                    </label>
+                                </subviews>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                                <constraints>
+                                    <constraint firstItem="qeA-Ck-j1u" firstAttribute="centerX" secondItem="fSs-by-PN4" secondAttribute="centerX" id="5Qu-mO-edY"/>
+                                    <constraint firstItem="qeA-Ck-j1u" firstAttribute="top" secondItem="fSs-by-PN4" secondAttribute="top" constant="95" id="8du-wI-6ZF"/>
+                                    <constraint firstItem="iYp-n0-3JW" firstAttribute="centerX" secondItem="fSs-by-PN4" secondAttribute="centerX" id="m6b-WQ-Xi2"/>
+                                    <constraint firstItem="iYp-n0-3JW" firstAttribute="top" secondItem="qeA-Ck-j1u" secondAttribute="bottom" constant="30" id="oQs-az-YdD"/>
+                                </constraints>
+                            </view>
+                            <tableView hidden="YES" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" rowHeight="44" sectionHeaderHeight="1" sectionFooterHeight="1" translatesAutoresizingMaskIntoConstraints="NO" id="lt6-TN-CBy">
+                                <rect key="frame" x="0.0" y="45" width="375" height="529"/>
+                                <color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
+                                <color key="separatorColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="calibratedRGB"/>
+                                <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                <connections>
+                                    <outlet property="dataSource" destination="v1Y-JU-ghZ" id="Ebg-Ao-7f2"/>
+                                    <outlet property="delegate" destination="v1Y-JU-ghZ" id="duQ-PP-bvU"/>
+                                </connections>
+                            </tableView>
+                        </subviews>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <constraints>
+                            <constraint firstAttribute="trailing" secondItem="BGN-X3-l8M" secondAttribute="trailing" id="3va-Jk-A3v"/>
+                            <constraint firstItem="fVv-Jr-fwe" firstAttribute="leading" secondItem="cM6-BE-uc6" secondAttribute="leading" id="Fkd-jg-bPF"/>
+                            <constraint firstItem="BGN-X3-l8M" firstAttribute="leading" secondItem="cM6-BE-uc6" secondAttribute="leading" id="Ih2-h0-Z7L"/>
+                            <constraint firstItem="qPJ-dc-5yP" firstAttribute="leading" secondItem="cM6-BE-uc6" secondAttribute="leading" id="MYp-5R-gFR"/>
+                            <constraint firstItem="spO-fb-3hh" firstAttribute="top" secondItem="fSs-by-PN4" secondAttribute="bottom" id="R8r-Eu-HS6"/>
+                            <constraint firstItem="lt6-TN-CBy" firstAttribute="top" secondItem="jte-We-k7c" secondAttribute="bottom" constant="45" id="WhV-ye-ZlA"/>
+                            <constraint firstItem="fVv-Jr-fwe" firstAttribute="top" secondItem="jte-We-k7c" secondAttribute="bottom" constant="45" id="X6z-Fq-W8V"/>
+                            <constraint firstAttribute="trailing" secondItem="fVv-Jr-fwe" secondAttribute="trailing" id="cAN-9H-6vt"/>
+                            <constraint firstItem="spO-fb-3hh" firstAttribute="top" secondItem="lt6-TN-CBy" secondAttribute="bottom" id="cy4-DW-YTo"/>
+                            <constraint firstItem="lt6-TN-CBy" firstAttribute="leading" secondItem="cM6-BE-uc6" secondAttribute="leading" id="hpI-WN-qt6"/>
+                            <constraint firstItem="BGN-X3-l8M" firstAttribute="top" secondItem="jte-We-k7c" secondAttribute="bottom" constant="50" id="jIJ-bT-9O4"/>
+                            <constraint firstAttribute="trailing" secondItem="lt6-TN-CBy" secondAttribute="trailing" id="jmU-lg-4oZ"/>
+                            <constraint firstAttribute="trailing" secondItem="fSs-by-PN4" secondAttribute="trailing" id="k94-Cs-dt9"/>
+                            <constraint firstAttribute="trailing" secondItem="qPJ-dc-5yP" secondAttribute="trailing" id="nJX-OJ-sHb"/>
+                            <constraint firstItem="fSs-by-PN4" firstAttribute="leading" secondItem="cM6-BE-uc6" secondAttribute="leading" id="sil-Nc-xyd"/>
+                            <constraint firstItem="qPJ-dc-5yP" firstAttribute="top" secondItem="jte-We-k7c" secondAttribute="bottom" id="urT-OZ-LXv"/>
+                            <constraint firstItem="fSs-by-PN4" firstAttribute="top" secondItem="jte-We-k7c" secondAttribute="bottom" constant="50" id="ylU-8G-nvb"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" title="Gateway" id="SuR-By-ib7">
+                        <barButtonItem key="rightBarButtonItem" image="ResourceExit" id="S7O-fw-4OT">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            <connections>
+                                <action selector="exitButtonClicked:" destination="v1Y-JU-ghZ" id="kYY-gS-Rro"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                    <connections>
+                        <outlet property="acsModeTableView" destination="fVv-Jr-fwe" id="SLN-wF-fIP"/>
+                        <outlet property="activityIndicator" destination="jEM-OB-Frs" id="vCw-zX-m9O"/>
+                        <outlet property="emptyResourceImageView" destination="qeA-Ck-j1u" id="xg7-1L-gbR"/>
+                        <outlet property="emptyResourceLabel" destination="iYp-n0-3JW" id="Bsu-FX-Qxx"/>
+                        <outlet property="emptyResourceView" destination="fSs-by-PN4" id="YfI-9s-PmN"/>
+                        <outlet property="emptyViewTopConstraint" destination="ylU-8G-nvb" id="KNz-Sw-UmL"/>
+                        <outlet property="messageLabel" destination="hhP-By-cX0" id="JdZ-pk-JNL"/>
+                        <outlet property="messageView" destination="BGN-X3-l8M" id="KbK-FX-eKE"/>
+                        <outlet property="messageViewTopConstraint" destination="jIJ-bT-9O4" id="7Mq-be-v6q"/>
+                        <outlet property="resourceTableView" destination="lt6-TN-CBy" id="co6-VW-c8N"/>
+                        <outlet property="resourceViewTopConstraint" destination="WhV-ye-ZlA" id="70s-di-07h"/>
+                        <outlet property="statusImageView" destination="4qi-ej-DYj" id="OPr-Nl-YzP"/>
+                        <outlet property="statusLabel" destination="FFN-Tu-ZTR" id="ntl-gw-bwo"/>
+                        <outlet property="vpnEnableSwitch" destination="tih-jI-rGn" id="idl-cR-f8x"/>
+                        <segue destination="ixp-zo-wwn" kind="show" identifier="ResourceToSubResource" id="PDU-he-Ld0"/>
+                        <segue destination="EyZ-YP-cnm" kind="show" identifier="ResourceToCustomDesktop" id="ztu-Kd-80v"/>
+                        <segue destination="RPI-UI-YjC" kind="presentation" identifier="ResourceToAccessModeSelect" modalPresentationStyle="fullScreen" id="5T7-PF-nT2"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="FEY-bC-a3K" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="-1018.4" y="3813.6431784107949"/>
+        </scene>
+        <!--ANTabBarController-->
+        <scene sceneID="fKa-RZ-Ufs">
+            <objects>
+                <tabBarController title="ANTabBarController" id="LZd-Ei-vmr" customClass="ANTabBarController" sceneMemberID="viewController">
+                    <tabBar key="tabBar" contentMode="scaleToFill" id="ALn-CL-2Tp">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="49"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                    </tabBar>
+                    <connections>
+                        <segue destination="zh2-KR-niN" kind="relationship" relationship="viewControllers" id="KzF-KZ-2kZ"/>
+                        <segue destination="NBi-af-Ul6" kind="relationship" relationship="viewControllers" id="S0o-0Y-HuX"/>
+                        <segue destination="ji1-Yh-QLz" kind="relationship" relationship="viewControllers" id="Q0y-GY-mgF"/>
+                    </connections>
+                </tabBarController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="DVr-0R-XF3" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="118" y="2168"/>
+        </scene>
+        <!--LoginNavigation-->
+        <scene sceneID="Xnm-pw-ikw">
+            <objects>
+                <navigationController title="LoginNavigation" automaticallyAdjustsScrollViewInsets="NO" id="nnp-7I-qjc" sceneMemberID="viewController">
+                    <toolbarItems/>
+                    <navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="97A-SE-cgY">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <color key="barTintColor" red="0.90588235294117647" green="0.0" blue="0.070588235294117646" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <textAttributes key="titleTextAttributes">
+                            <fontDescription key="fontDescription" type="boldSystem" pointSize="18"/>
+                            <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        </textAttributes>
+                    </navigationBar>
+                    <nil name="viewControllers"/>
+                    <connections>
+                        <segue destination="b5l-8Z-fX3" kind="relationship" relationship="rootViewController" id="i7q-E7-SYr"/>
+                    </connections>
+                </navigationController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="wjZ-Tq-ACH" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="1924" y="1807"/>
+        </scene>
+        <!--Gateway-->
+        <scene sceneID="zRt-jZ-TLQ">
+            <objects>
+                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="zh2-KR-niN" sceneMemberID="viewController">
+                    <tabBarItem key="tabBarItem" title="Gateway" image="ResourceGatewayUnselected" selectedImage="ResourceGatewaySelected" id="M5q-8a-7xR"/>
+                    <toolbarItems/>
+                    <navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="YkX-q2-1AP">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        <color key="barTintColor" red="0.90588235294117647" green="0.0" blue="0.070588235294117646" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <textAttributes key="titleTextAttributes">
+                            <fontDescription key="fontDescription" type="boldSystem" pointSize="18"/>
+                            <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        </textAttributes>
+                    </navigationBar>
+                    <nil name="viewControllers"/>
+                    <connections>
+                        <segue destination="v1Y-JU-ghZ" kind="relationship" relationship="rootViewController" id="Yzh-jw-MTk"/>
+                    </connections>
+                </navigationController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="oWu-Pm-D4a" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="-1018.4" y="3026.5367316341831"/>
+        </scene>
+        <!--Status-->
+        <scene sceneID="1Yn-DC-CWm">
+            <objects>
+                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="NBi-af-Ul6" sceneMemberID="viewController">
+                    <tabBarItem key="tabBarItem" title="Status" image="ResourceStatusUnselected" selectedImage="ResourceStatusSelected" id="0rx-RB-iIc"/>
+                    <toolbarItems/>
+                    <navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="pIg-vb-CbM">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <color key="barTintColor" red="0.90588235294117647" green="0.0" blue="0.070588235294117646" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <textAttributes key="titleTextAttributes">
+                            <fontDescription key="fontDescription" type="boldSystem" pointSize="18"/>
+                            <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        </textAttributes>
+                    </navigationBar>
+                    <nil name="viewControllers"/>
+                    <connections>
+                        <segue destination="r5T-k1-WRt" kind="relationship" relationship="rootViewController" id="QPO-dA-4ed"/>
+                    </connections>
+                </navigationController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="GQg-Rn-hev" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="117.59999999999999" y="3026.5367316341831"/>
+        </scene>
+        <!--Status-->
+        <scene sceneID="LFl-be-CdD">
+            <objects>
+                <tableViewController id="r5T-k1-WRt" customClass="StatusViewController" sceneMemberID="viewController">
+                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" bounces="NO" dataMode="static" style="grouped" separatorStyle="default" allowsSelection="NO" rowHeight="44" sectionHeaderHeight="40" sectionFooterHeight="1" id="Qvp-QE-kvM">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <color key="separatorColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="calibratedRGB"/>
+                        <sections>
+                            <tableViewSection headerTitle="CONNECTION INFO" id="YG5-K0-czK">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="RaH-oW-4eo">
+                                        <rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="RaH-oW-4eo" id="lQa-DO-3OA">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="State" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hbN-yy-oxI">
+                                                    <rect key="frame" x="23" y="11.5" width="41.5" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pOD-Lz-clG">
+                                                    <rect key="frame" x="352" y="22" width="0.0" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="hbN-yy-oxI" secondAttribute="trailingMargin" id="5Gg-YQ-Rlt"/>
+                                                <constraint firstItem="hbN-yy-oxI" firstAttribute="leading" secondItem="lQa-DO-3OA" secondAttribute="leadingMargin" constant="7" id="Jpu-tP-gw8"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="pOD-Lz-clG" secondAttribute="trailing" constant="7" id="KSW-dh-9ev"/>
+                                                <constraint firstItem="pOD-Lz-clG" firstAttribute="centerY" secondItem="lQa-DO-3OA" secondAttribute="centerY" id="eEd-bU-hmg"/>
+                                                <constraint firstItem="pOD-Lz-clG" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="lQa-DO-3OA" secondAttribute="leadingMargin" id="nsH-55-R5N"/>
+                                                <constraint firstItem="hbN-yy-oxI" firstAttribute="centerY" secondItem="lQa-DO-3OA" secondAttribute="centerY" id="u7h-S6-Vyj"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="mTz-aC-JEX">
+                                        <rect key="frame" x="0.0" y="99.5" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="mTz-aC-JEX" id="Vng-j3-UH5">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Server" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mlq-pq-j6g">
+                                                    <rect key="frame" x="23" y="11.5" width="51.5" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="feC-60-gST">
+                                                    <rect key="frame" x="352" y="22" width="0.0" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="mlq-pq-j6g" firstAttribute="leading" secondItem="Vng-j3-UH5" secondAttribute="leadingMargin" constant="7" id="PfG-de-SmE"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="feC-60-gST" secondAttribute="trailing" constant="7" id="cQI-Sf-9lQ"/>
+                                                <constraint firstItem="feC-60-gST" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Vng-j3-UH5" secondAttribute="leadingMargin" id="naJ-tN-4dx"/>
+                                                <constraint firstItem="feC-60-gST" firstAttribute="centerY" secondItem="Vng-j3-UH5" secondAttribute="centerY" id="rr3-kv-n4x"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="mlq-pq-j6g" secondAttribute="trailingMargin" id="shQ-Su-Q4j"/>
+                                                <constraint firstItem="mlq-pq-j6g" firstAttribute="centerY" secondItem="Vng-j3-UH5" secondAttribute="centerY" id="zL3-20-u5f"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="Egg-NT-aro">
+                                        <rect key="frame" x="0.0" y="143.5" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Egg-NT-aro" id="kkh-XZ-yBK">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="IP Address" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="IOa-mi-PjO">
+                                                    <rect key="frame" x="23" y="11.5" width="84" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Qof-NW-hNB">
+                                                    <rect key="frame" x="352" y="22" width="0.0" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="IOa-mi-PjO" firstAttribute="leading" secondItem="kkh-XZ-yBK" secondAttribute="leadingMargin" constant="7" id="0wh-AT-G8p"/>
+                                                <constraint firstItem="Qof-NW-hNB" firstAttribute="centerY" secondItem="kkh-XZ-yBK" secondAttribute="centerY" id="Q6M-Ol-qae"/>
+                                                <constraint firstItem="Qof-NW-hNB" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="kkh-XZ-yBK" secondAttribute="leadingMargin" id="QZ0-PA-ewi"/>
+                                                <constraint firstItem="IOa-mi-PjO" firstAttribute="centerY" secondItem="kkh-XZ-yBK" secondAttribute="centerY" id="hJv-Gj-lpT"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="Qof-NW-hNB" secondAttribute="trailing" constant="7" id="lMe-nl-TDV"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="IOa-mi-PjO" secondAttribute="trailingMargin" id="tPy-f4-LAq"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="39e-aA-bUj">
+                                        <rect key="frame" x="0.0" y="187.5" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="39e-aA-bUj" id="G1w-a4-dGa">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Time Connected" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mLt-BF-kGM">
+                                                    <rect key="frame" x="23" y="11.5" width="129" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OUx-0G-8Uc">
+                                                    <rect key="frame" x="352" y="22" width="0.0" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="trailingMargin" secondItem="OUx-0G-8Uc" secondAttribute="trailing" constant="7" id="7K6-Pc-pcS"/>
+                                                <constraint firstItem="mLt-BF-kGM" firstAttribute="leading" secondItem="G1w-a4-dGa" secondAttribute="leadingMargin" constant="7" id="B96-n2-HEe"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="mLt-BF-kGM" secondAttribute="trailingMargin" id="Eto-rR-7st"/>
+                                                <constraint firstItem="mLt-BF-kGM" firstAttribute="centerY" secondItem="G1w-a4-dGa" secondAttribute="centerY" id="LV8-V1-M53"/>
+                                                <constraint firstItem="OUx-0G-8Uc" firstAttribute="centerY" secondItem="G1w-a4-dGa" secondAttribute="centerY" id="OKK-xc-yRZ"/>
+                                                <constraint firstItem="OUx-0G-8Uc" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="G1w-a4-dGa" secondAttribute="leadingMargin" id="sM6-oA-kWt"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="TOd-p6-GdM">
+                                        <rect key="frame" x="0.0" y="231.5" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="TOd-p6-GdM" id="UwS-Ts-KIN">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="MTU" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lao-gf-Bxh">
+                                                    <rect key="frame" x="23" y="11.5" width="38" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="f8E-ob-VIF">
+                                                    <rect key="frame" x="352" y="22" width="0.0" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="f8E-ob-VIF" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="UwS-Ts-KIN" secondAttribute="leadingMargin" id="412-vT-64k"/>
+                                                <constraint firstItem="lao-gf-Bxh" firstAttribute="leading" secondItem="UwS-Ts-KIN" secondAttribute="leadingMargin" constant="7" id="Ddw-Le-yZo"/>
+                                                <constraint firstItem="f8E-ob-VIF" firstAttribute="centerY" secondItem="UwS-Ts-KIN" secondAttribute="centerY" id="Ggr-mN-uQY"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="f8E-ob-VIF" secondAttribute="trailing" constant="7" id="MjU-x4-VXC"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="lao-gf-Bxh" secondAttribute="trailingMargin" id="Pwa-mT-4Ue"/>
+                                                <constraint firstItem="lao-gf-Bxh" firstAttribute="centerY" secondItem="UwS-Ts-KIN" secondAttribute="centerY" id="aQl-An-gCP"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="hcB-x9-YAW">
+                                        <rect key="frame" x="0.0" y="275.5" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="hcB-x9-YAW" id="04e-Md-7Gv">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Mode" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sVN-85-RxM">
+                                                    <rect key="frame" x="23" y="11.5" width="44.5" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9vS-xT-Gre">
+                                                    <rect key="frame" x="352" y="22" width="0.0" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="9vS-xT-Gre" firstAttribute="centerY" secondItem="04e-Md-7Gv" secondAttribute="centerY" id="LPo-8X-vkX"/>
+                                                <constraint firstItem="9vS-xT-Gre" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="04e-Md-7Gv" secondAttribute="leadingMargin" id="Ojy-K2-qTn"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="9vS-xT-Gre" secondAttribute="trailing" constant="7" id="RMn-7x-L1c"/>
+                                                <constraint firstItem="sVN-85-RxM" firstAttribute="leading" secondItem="04e-Md-7Gv" secondAttribute="leadingMargin" constant="7" id="mfT-Sg-EJU"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="sVN-85-RxM" secondAttribute="trailingMargin" id="npn-ib-HTD"/>
+                                                <constraint firstItem="sVN-85-RxM" firstAttribute="centerY" secondItem="04e-Md-7Gv" secondAttribute="centerY" id="pZk-Se-LzR"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                            <tableViewSection headerTitle="DNS" id="8xO-lB-ku6">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" misplaced="YES" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="qch-Ve-xe7">
+                                        <rect key="frame" x="0.0" y="358.5" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="qch-Ve-xe7" id="zFH-V6-01F">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" misplaced="YES" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="5DJ-Bq-YZo">
+                                        <rect key="frame" x="0.0" y="358.50000011920929" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="5DJ-Bq-YZo" id="oX0-r4-gPf">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" misplaced="YES" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="QhV-lm-ceg">
+                                        <rect key="frame" x="0.0" y="358.50000023841858" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="QhV-lm-ceg" id="y2q-OD-BmZ">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" misplaced="YES" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="uum-8j-kZY">
+                                        <rect key="frame" x="0.0" y="358.50000035762787" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="uum-8j-kZY" id="gVA-zf-h0n">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" misplaced="YES" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="89z-E0-5d8">
+                                        <rect key="frame" x="0.0" y="358.50000047683716" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="89z-E0-5d8" id="TTJ-iL-yIh">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" misplaced="YES" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="dIM-zf-loR">
+                                        <rect key="frame" x="0.0" y="358.50000059604645" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="dIM-zf-loR" id="jyw-Mi-dPO">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" misplaced="YES" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="zn7-pU-xVV">
+                                        <rect key="frame" x="0.0" y="358.50000071525574" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="zn7-pU-xVV" id="k7l-UU-3MB">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="yrH-pG-S25">
+                                        <rect key="frame" x="0.0" y="358.50000083446503" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="yrH-pG-S25" id="JJN-dY-S6A">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="o30-vo-oYa">
+                                        <rect key="frame" x="0.0" y="358.50000095367432" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="o30-vo-oYa" id="hYh-3E-9Jq">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="OHe-MV-nB0">
+                                        <rect key="frame" x="0.0" y="358.50000107288361" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="OHe-MV-nB0" id="OsG-4x-URI">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="3E9-Hj-fyh">
+                                        <rect key="frame" x="0.0" y="358.5000011920929" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="3E9-Hj-fyh" id="uvl-qn-wsl">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="jhR-2r-Pqv">
+                                        <rect key="frame" x="0.0" y="358.50000131130219" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="jhR-2r-Pqv" id="Ww8-ky-8u0">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="nbI-cf-H3E">
+                                        <rect key="frame" x="0.0" y="358.50000143051147" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="nbI-cf-H3E" id="8im-TO-xSS">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="Efh-d8-21D">
+                                        <rect key="frame" x="0.0" y="358.50000154972076" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Efh-d8-21D" id="3a2-nE-WeG">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="hbR-qJ-Etk">
+                                        <rect key="frame" x="0.0" y="358.50000166893005" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="hbR-qJ-Etk" id="CLu-VT-f0e">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="T1n-P4-wfV">
+                                        <rect key="frame" x="0.0" y="358.50000178813934" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="T1n-P4-wfV" id="YzM-Gf-aiQ">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="y30-0k-ufQ">
+                                        <rect key="frame" x="0.0" y="358.50000190734863" width="375" height="1.1920928955078125e-07"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="y30-0k-ufQ" id="6xK-bV-wwg">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="1.1920928955078125e-07"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                            <tableViewSection headerTitle="STATISTICS" id="Xl0-cU-DDR">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="tCL-SZ-Y4Z">
+                                        <rect key="frame" x="0.0" y="397.50000202655792" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="tCL-SZ-Y4Z" id="H1x-rp-QzS">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Data Sent" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Wlj-g6-WuJ">
+                                                    <rect key="frame" x="23" y="11.5" width="77" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XEA-WC-w7P">
+                                                    <rect key="frame" x="352" y="22" width="0.0" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="XEA-WC-w7P" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="H1x-rp-QzS" secondAttribute="leadingMargin" id="5BD-7Q-gM3"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="XEA-WC-w7P" secondAttribute="trailing" constant="7" id="5qa-Zz-nPq"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="Wlj-g6-WuJ" secondAttribute="trailingMargin" id="BM3-IW-Vdh"/>
+                                                <constraint firstItem="XEA-WC-w7P" firstAttribute="centerY" secondItem="H1x-rp-QzS" secondAttribute="centerY" id="HCm-oq-2PH"/>
+                                                <constraint firstItem="Wlj-g6-WuJ" firstAttribute="centerY" secondItem="H1x-rp-QzS" secondAttribute="centerY" id="S4X-Ze-565"/>
+                                                <constraint firstItem="Wlj-g6-WuJ" firstAttribute="leading" secondItem="H1x-rp-QzS" secondAttribute="leadingMargin" constant="7" id="SMW-H8-fJW"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="kyt-Sv-rs5">
+                                        <rect key="frame" x="0.0" y="441.50000202655792" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="kyt-Sv-rs5" id="d96-V6-mlc">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Data Received" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="oet-ex-ZoA">
+                                                    <rect key="frame" x="23" y="11.5" width="112" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3fD-rX-Z83">
+                                                    <rect key="frame" x="352" y="22" width="0.0" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="3fD-rX-Z83" firstAttribute="centerY" secondItem="d96-V6-mlc" secondAttribute="centerY" id="1Xw-NF-7hp"/>
+                                                <constraint firstItem="oet-ex-ZoA" firstAttribute="centerY" secondItem="d96-V6-mlc" secondAttribute="centerY" id="887-Ni-xbA"/>
+                                                <constraint firstItem="3fD-rX-Z83" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="d96-V6-mlc" secondAttribute="leadingMargin" id="SIf-G1-j1J"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="oet-ex-ZoA" secondAttribute="trailingMargin" id="Wzf-GW-D5h"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="3fD-rX-Z83" secondAttribute="trailing" constant="7" id="f1E-Mx-W2R"/>
+                                                <constraint firstItem="oet-ex-ZoA" firstAttribute="leading" secondItem="d96-V6-mlc" secondAttribute="leadingMargin" constant="7" id="qg3-lx-yi8"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                        </sections>
+                        <connections>
+                            <outlet property="dataSource" destination="r5T-k1-WRt" id="pdF-sb-uXw"/>
+                            <outlet property="delegate" destination="r5T-k1-WRt" id="UuC-Ac-APz"/>
+                        </connections>
+                    </tableView>
+                    <navigationItem key="navigationItem" title="Status" id="Ewy-ma-UbL"/>
+                    <connections>
+                        <outlet property="dataReceivedLabel" destination="3fD-rX-Z83" id="NR3-O1-f5U"/>
+                        <outlet property="dataSentLabel" destination="XEA-WC-w7P" id="x9M-eN-H1Y"/>
+                        <outlet property="ipAddressLabel" destination="Qof-NW-hNB" id="f3w-bW-NBW"/>
+                        <outlet property="modeLabel" destination="9vS-xT-Gre" id="xtl-Kh-8pl"/>
+                        <outlet property="mtuLabel" destination="f8E-ob-VIF" id="9xS-9h-SgB"/>
+                        <outlet property="serverLabel" destination="feC-60-gST" id="8e1-gc-HfI"/>
+                        <outlet property="stateLabel" destination="pOD-Lz-clG" id="els-Ay-HiT"/>
+                        <outlet property="timeLabel" destination="OUx-0G-8Uc" id="EDl-pf-t3c"/>
+                    </connections>
+                </tableViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="QvO-OP-14y" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="117.59999999999999" y="3813.6431784107949"/>
+        </scene>
+        <!--Settings-->
+        <scene sceneID="ebE-B2-7Pa">
+            <objects>
+                <tableViewController id="kNN-aP-IXV" customClass="SettingsViewController" sceneMemberID="viewController">
+                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" bounces="NO" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="1" sectionFooterHeight="1" id="GmA-Kc-OCx">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
+                        <color key="separatorColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <sections>
+                            <tableViewSection id="PlT-e5-bDi">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="lJo-Ae-HjF">
+                                        <rect key="frame" x="0.0" y="1" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="lJo-Ae-HjF" id="hGY-F4-NCT">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Username" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="KtQ-Qv-Lo0">
+                                                    <rect key="frame" x="23" y="11.5" width="80.5" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7NZ-oF-ooj">
+                                                    <rect key="frame" x="352" y="22" width="0.0" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="KtQ-Qv-Lo0" firstAttribute="leading" secondItem="hGY-F4-NCT" secondAttribute="leadingMargin" constant="7" id="ETS-Z6-hhh"/>
+                                                <constraint firstItem="7NZ-oF-ooj" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="hGY-F4-NCT" secondAttribute="leadingMargin" id="NdW-QW-uxn"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="7NZ-oF-ooj" secondAttribute="trailing" constant="7" id="jcD-cd-bGX"/>
+                                                <constraint firstItem="KtQ-Qv-Lo0" firstAttribute="centerY" secondItem="hGY-F4-NCT" secondAttribute="centerY" id="vST-qP-JjP"/>
+                                                <constraint firstItem="7NZ-oF-ooj" firstAttribute="centerY" secondItem="hGY-F4-NCT" secondAttribute="centerY" id="xf4-sm-pV1"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="KtQ-Qv-Lo0" secondAttribute="trailingMargin" id="ybu-jS-OC6"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="haL-xJ-ru1">
+                                        <rect key="frame" x="0.0" y="45" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="haL-xJ-ru1" id="uMc-1g-bZf">
+                                            <rect key="frame" x="0.0" y="0.0" width="348" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Password" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DXU-9a-S4o">
+                                                    <rect key="frame" x="23" y="11.5" width="76" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="DXU-9a-S4o" firstAttribute="leading" secondItem="uMc-1g-bZf" secondAttribute="leadingMargin" constant="7" id="HVb-Zv-sqm"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="DXU-9a-S4o" secondAttribute="trailingMargin" id="Q7M-M4-0ke"/>
+                                                <constraint firstItem="DXU-9a-S4o" firstAttribute="centerY" secondItem="uMc-1g-bZf" secondAttribute="centerY" id="nk0-oV-x9A"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                            <tableViewSection id="XyK-bc-y4a">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="20k-ei-0TV">
+                                        <rect key="frame" x="0.0" y="91" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="20k-ei-0TV" id="JRp-wI-728">
+                                            <rect key="frame" x="0.0" y="0.0" width="348" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Remote Desktop" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qNz-AI-x3B">
+                                                    <rect key="frame" x="23" y="12.5" width="130" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="qNz-AI-x3B" firstAttribute="leading" secondItem="JRp-wI-728" secondAttribute="leadingMargin" constant="7" id="Nyh-A9-jDZ"/>
+                                                <constraint firstItem="qNz-AI-x3B" firstAttribute="centerY" secondItem="JRp-wI-728" secondAttribute="centerY" constant="1" id="cQc-qb-Vj3"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="qNz-AI-x3B" secondAttribute="trailingMargin" id="lkN-n8-3bY"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                            <tableViewSection id="ep1-rJ-hIx">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="2pt-EB-Pge">
+                                        <rect key="frame" x="0.0" y="137" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="2pt-EB-Pge" id="m36-Jj-BAX">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Device ID" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tR4-hQ-XRC">
+                                                    <rect key="frame" x="23" y="11.5" width="110" height="21"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="110" id="4hM-Zp-h6t"/>
+                                                    </constraints>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="In1-of-yQS" customClass="ANCopyLabel">
+                                                    <rect key="frame" x="120" y="22" width="232" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="In1-of-yQS" firstAttribute="leading" secondItem="m36-Jj-BAX" secondAttribute="leading" constant="120" id="ADj-dU-rYV"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="In1-of-yQS" secondAttribute="trailing" constant="7" id="NWN-Zx-InT"/>
+                                                <constraint firstItem="tR4-hQ-XRC" firstAttribute="centerY" secondItem="m36-Jj-BAX" secondAttribute="centerY" id="Q2l-5a-6V7"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="In1-of-yQS" secondAttribute="trailing" constant="7" id="gVk-SV-uDh"/>
+                                                <constraint firstItem="tR4-hQ-XRC" firstAttribute="leading" secondItem="m36-Jj-BAX" secondAttribute="leadingMargin" constant="7" id="jOp-m4-za4"/>
+                                                <constraint firstItem="In1-of-yQS" firstAttribute="centerY" secondItem="m36-Jj-BAX" secondAttribute="centerY" id="mqI-PB-scY"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                            <tableViewSection id="Rpm-xC-Uzg">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="pIk-wc-0sv">
+                                        <rect key="frame" x="0.0" y="183" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="pIk-wc-0sv" id="SkF-EH-B3E">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="FaceID" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3M7-p1-f2w" userLabel="FaceID">
+                                                    <rect key="frame" x="23" y="11.5" width="110" height="21"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="110" id="h3p-25-zON"/>
+                                                    </constraints>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pXx-Wm-I5u" customClass="ANCopyLabel">
+                                                    <rect key="frame" x="120" y="22" width="232" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="RDB-GI-KFD">
+                                                    <rect key="frame" x="312" y="7" width="49" height="31"/>
+                                                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                                </switch>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="pXx-Wm-I5u" firstAttribute="leading" secondItem="SkF-EH-B3E" secondAttribute="leading" constant="120" id="7dR-Id-fif"/>
+                                                <constraint firstItem="3M7-p1-f2w" firstAttribute="leading" secondItem="SkF-EH-B3E" secondAttribute="leadingMargin" constant="7" id="QeK-ne-C2e"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="pXx-Wm-I5u" secondAttribute="trailing" constant="7" id="Xp7-5B-OJr"/>
+                                                <constraint firstItem="pXx-Wm-I5u" firstAttribute="centerY" secondItem="SkF-EH-B3E" secondAttribute="centerY" id="brV-vQ-yn1"/>
+                                                <constraint firstItem="3M7-p1-f2w" firstAttribute="centerY" secondItem="SkF-EH-B3E" secondAttribute="centerY" id="rKo-po-lbz"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="pXx-Wm-I5u" secondAttribute="trailing" constant="7" id="uBo-YD-fo3"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                            <tableViewSection id="Ji5-0k-Yc8">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="KyX-5T-x3H">
+                                        <rect key="frame" x="0.0" y="229" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KyX-5T-x3H" id="epP-Xr-tCZ">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Gesture login" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="AIf-cu-NLD" userLabel="Gesture login">
+                                                    <rect key="frame" x="23" y="11.5" width="180" height="21"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="180" id="prX-mL-QP5"/>
+                                                    </constraints>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iJs-xF-qM6" customClass="ANCopyLabel">
+                                                    <rect key="frame" x="120" y="22" width="232" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6vQ-1v-zsT">
+                                                    <rect key="frame" x="312" y="7" width="49" height="31"/>
+                                                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                                </switch>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="AIf-cu-NLD" firstAttribute="centerY" secondItem="epP-Xr-tCZ" secondAttribute="centerY" id="5Eo-ft-WNn"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="iJs-xF-qM6" secondAttribute="trailing" constant="7" id="NOE-hg-IqK"/>
+                                                <constraint firstAttribute="trailingMargin" secondItem="iJs-xF-qM6" secondAttribute="trailing" constant="7" id="QRM-36-581"/>
+                                                <constraint firstItem="AIf-cu-NLD" firstAttribute="leading" secondItem="epP-Xr-tCZ" secondAttribute="leadingMargin" constant="7" id="Yfc-CM-iZG"/>
+                                                <constraint firstItem="iJs-xF-qM6" firstAttribute="centerY" secondItem="epP-Xr-tCZ" secondAttribute="centerY" id="g70-0r-AEi"/>
+                                                <constraint firstItem="iJs-xF-qM6" firstAttribute="leading" secondItem="epP-Xr-tCZ" secondAttribute="leading" constant="120" id="mMo-pG-4a4"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                            <tableViewSection id="CBg-Nn-YPB">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="2la-JM-I6m">
+                                        <rect key="frame" x="0.0" y="183" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="2la-JM-I6m" id="fne-MG-6Rv">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Logout" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5Qf-YN-ltX">
+                                                    <rect key="frame" x="160" y="12" width="55" height="20"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="5Qf-YN-ltX" firstAttribute="centerX" secondItem="fne-MG-6Rv" secondAttribute="centerX" id="DOf-lL-tO3"/>
+                                                <constraint firstItem="5Qf-YN-ltX" firstAttribute="centerY" secondItem="fne-MG-6Rv" secondAttribute="centerY" id="IdE-Jj-Dlj"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                        </sections>
+                        <connections>
+                            <outlet property="dataSource" destination="kNN-aP-IXV" id="Kwh-42-7a1"/>
+                            <outlet property="delegate" destination="kNN-aP-IXV" id="BuM-Cl-TBO"/>
+                        </connections>
+                    </tableView>
+                    <navigationItem key="navigationItem" title="Settings" id="44I-4p-BZJ"/>
+                    <connections>
+                        <outlet property="deviceIDCell" destination="2pt-EB-Pge" id="v2i-Tf-yNa"/>
+                        <outlet property="deviceIDLabel" destination="In1-of-yQS" id="8aB-L6-Vtf"/>
+                        <outlet property="faceIDLable" destination="3M7-p1-f2w" id="aEP-SO-0df"/>
+                        <outlet property="faceIDSwitch" destination="RDB-GI-KFD" id="coa-c3-Pn9"/>
+                        <outlet property="gestureSwitch" destination="6vQ-1v-zsT" id="RJF-CM-XcM"/>
+                        <outlet property="passwordCell" destination="haL-xJ-ru1" id="vnk-nd-19F"/>
+                        <outlet property="usernameLabel" destination="7NZ-oF-ooj" id="U36-XH-nRB"/>
+                        <segue destination="MGw-hc-Bqe" kind="show" identifier="SettingsToChangePassword" id="bsi-4V-JG6"/>
+                        <segue destination="ths-LD-SZi" kind="show" identifier="SettingsToRemoteDesktop" id="WIg-WZ-5a5"/>
+                    </connections>
+                </tableViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="lB7-uT-NTe" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="1288.8" y="3813.6431784107949"/>
+        </scene>
+        <!--Remote Desktop-->
+        <scene sceneID="WoW-l4-2Fe">
+            <objects>
+                <tableViewController title="Remote Desktop" id="ths-LD-SZi" customClass="RemoteDesktopSettingsViewController" sceneMemberID="viewController">
+                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="PRC-v9-4lh">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="calibratedRGB"/>
+                        <sections>
+                            <tableViewSection id="RBy-MA-3Yx">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="ZsV-dQ-obU">
+                                        <rect key="frame" x="0.0" y="18" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ZsV-dQ-obU" id="bI2-DB-UhM">
+                                            <rect key="frame" x="0.0" y="0.0" width="348" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Audio Mode" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zJ0-qT-F6l">
+                                                    <rect key="frame" x="23" y="11.5" width="94" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Dyb-56-nYR">
+                                                    <rect key="frame" x="340" y="22" width="0.0" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="Dyb-56-nYR" firstAttribute="centerY" secondItem="bI2-DB-UhM" secondAttribute="centerY" id="0e6-7r-iZ5"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="zJ0-qT-F6l" secondAttribute="trailingMargin" id="5CT-2g-o27"/>
+                                                <constraint firstItem="Dyb-56-nYR" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="bI2-DB-UhM" secondAttribute="leadingMargin" id="BdG-GT-AEq"/>
+                                                <constraint firstItem="zJ0-qT-F6l" firstAttribute="centerY" secondItem="bI2-DB-UhM" secondAttribute="centerY" id="Mvf-Cp-jdt"/>
+                                                <constraint firstItem="Dyb-56-nYR" firstAttribute="trailing" secondItem="bI2-DB-UhM" secondAttribute="trailingMargin" id="buS-JU-Dwh"/>
+                                                <constraint firstItem="zJ0-qT-F6l" firstAttribute="leading" secondItem="bI2-DB-UhM" secondAttribute="leadingMargin" constant="7" id="wGa-nZ-mHP"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                            <tableViewSection headerTitle="" id="py7-w9-d3r">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="9Jw-UU-Ccz">
+                                        <rect key="frame" x="0.0" y="102" width="375" height="44"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="9Jw-UU-Ccz" id="pDo-CD-27p">
+                                            <rect key="frame" x="0.0" y="0.0" width="348" height="44"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Vendor" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BXu-8Q-X33">
+                                                    <rect key="frame" x="23" y="11.5" width="57" height="21"/>
+                                                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
+                                                    <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="RXY-dP-obT">
+                                                    <rect key="frame" x="340" y="22" width="0.0" height="0.0"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                    <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="RXY-dP-obT" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="pDo-CD-27p" secondAttribute="leadingMargin" id="0qf-D9-Ez0"/>
+                                                <constraint firstItem="RXY-dP-obT" firstAttribute="centerY" secondItem="pDo-CD-27p" secondAttribute="centerY" id="F5J-yN-a1V"/>
+                                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="BXu-8Q-X33" secondAttribute="trailingMargin" id="UIf-gw-mqu"/>
+                                                <constraint firstItem="BXu-8Q-X33" firstAttribute="leading" secondItem="pDo-CD-27p" secondAttribute="leadingMargin" constant="7" id="iJx-Ar-GFa"/>
+                                                <constraint firstItem="RXY-dP-obT" firstAttribute="trailing" secondItem="pDo-CD-27p" secondAttribute="trailingMargin" id="rDP-xC-V9C"/>
+                                                <constraint firstItem="BXu-8Q-X33" firstAttribute="centerY" secondItem="pDo-CD-27p" secondAttribute="centerY" id="seA-b6-5oS"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                        </sections>
+                        <connections>
+                            <outlet property="dataSource" destination="ths-LD-SZi" id="YaT-n1-bEW"/>
+                            <outlet property="delegate" destination="ths-LD-SZi" id="2CJ-77-5Gg"/>
+                        </connections>
+                    </tableView>
+                    <connections>
+                        <outlet property="audioModeLabel" destination="Dyb-56-nYR" id="0Wd-8Q-Hqk"/>
+                        <outlet property="audioModelCell" destination="ZsV-dQ-obU" id="dwc-UM-z31"/>
+                        <outlet property="vendorCell" destination="9Jw-UU-Ccz" id="wAE-TC-uF1"/>
+                        <outlet property="vendorLabel" destination="RXY-dP-obT" id="M6Q-x5-PmZ"/>
+                    </connections>
+                </tableViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="RjJ-tL-UHT" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="2014" y="4590"/>
+        </scene>
+        <!--Change Password-->
+        <scene sceneID="KmO-tX-lcl">
+            <objects>
+                <tableViewController storyboardIdentifier="ChangePasswordViewControllerID" useStoryboardIdentifierAsRestorationIdentifier="YES" id="MGw-hc-Bqe" customClass="ChangePasswordViewController" sceneMemberID="viewController">
+                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" bounces="NO" dataMode="static" style="grouped" separatorStyle="default" allowsSelection="NO" rowHeight="66" sectionHeaderHeight="18" sectionFooterHeight="18" id="lON-LZ-doF">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="calibratedRGB"/>
+                        <color key="separatorColor" red="0.88627450980392153" green="0.88627450980392153" blue="0.88627450980392153" alpha="1" colorSpace="calibratedRGB"/>
+                        <sections>
+                            <tableViewSection id="QsC-jf-jh7">
+                                <cells>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="Dku-Kq-Q0S">
+                                        <rect key="frame" x="0.0" y="18" width="375" height="66"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Dku-Kq-Q0S" id="4WU-4e-kel">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="66"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="New Password" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="MyJ-Bk-1xO">
+                                                    <rect key="frame" x="47" y="0.0" width="320" height="65.5"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits" returnKeyType="next" secureTextEntry="YES"/>
+                                                    <connections>
+                                                        <outlet property="delegate" destination="MGw-hc-Bqe" id="Swq-iG-Prp"/>
+                                                    </connections>
+                                                </textField>
+                                                <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginPassword" translatesAutoresizingMaskIntoConstraints="NO" id="xPQ-N7-5il">
+                                                    <rect key="frame" x="23" y="25" width="16" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="height" constant="16" id="GTq-5e-ThX"/>
+                                                        <constraint firstAttribute="width" constant="16" id="jNZ-4a-Buc"/>
+                                                    </constraints>
+                                                </imageView>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="MyJ-Bk-1xO" firstAttribute="leading" secondItem="xPQ-N7-5il" secondAttribute="trailing" constant="8" id="0EI-AQ-k2a"/>
+                                                <constraint firstItem="MyJ-Bk-1xO" firstAttribute="top" secondItem="4WU-4e-kel" secondAttribute="top" id="4y8-D9-897"/>
+                                                <constraint firstItem="xPQ-N7-5il" firstAttribute="centerY" secondItem="4WU-4e-kel" secondAttribute="centerY" id="GC0-hn-TYo"/>
+                                                <constraint firstAttribute="bottom" secondItem="MyJ-Bk-1xO" secondAttribute="bottom" constant="0.5" id="KUU-I0-rTS"/>
+                                                <constraint firstItem="xPQ-N7-5il" firstAttribute="leading" secondItem="4WU-4e-kel" secondAttribute="leadingMargin" constant="7" id="Wa4-fF-h11"/>
+                                                <constraint firstAttribute="trailing" secondItem="MyJ-Bk-1xO" secondAttribute="trailing" constant="8" id="mX3-yB-PR5"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="RCt-Au-72G">
+                                        <rect key="frame" x="0.0" y="84" width="375" height="66"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="RCt-Au-72G" id="vx9-6q-Zvk">
+                                            <rect key="frame" x="0.0" y="0.0" width="375" height="66"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Confirm New Password" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="LAE-e1-UaQ">
+                                                    <rect key="frame" x="47" y="0.0" width="320" height="65.5"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                    <textInputTraits key="textInputTraits" returnKeyType="done" secureTextEntry="YES"/>
+                                                    <connections>
+                                                        <outlet property="delegate" destination="MGw-hc-Bqe" id="vzZ-X2-tFR"/>
+                                                    </connections>
+                                                </textField>
+                                                <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LoginPassword" translatesAutoresizingMaskIntoConstraints="NO" id="FXV-tO-RYZ">
+                                                    <rect key="frame" x="23" y="25" width="16" height="16"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="width" constant="16" id="N2Q-LG-2BZ"/>
+                                                        <constraint firstAttribute="height" constant="16" id="ZBV-Vv-Cua"/>
+                                                    </constraints>
+                                                </imageView>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="FXV-tO-RYZ" firstAttribute="leading" secondItem="vx9-6q-Zvk" secondAttribute="leadingMargin" constant="7" id="6V1-8t-2rG"/>
+                                                <constraint firstItem="LAE-e1-UaQ" firstAttribute="leading" secondItem="FXV-tO-RYZ" secondAttribute="trailing" constant="8" id="Ee0-Xj-FfF"/>
+                                                <constraint firstAttribute="bottom" secondItem="LAE-e1-UaQ" secondAttribute="bottom" constant="0.5" id="YM7-mg-j6Z"/>
+                                                <constraint firstAttribute="trailing" secondItem="LAE-e1-UaQ" secondAttribute="trailing" constant="8" id="aHS-pw-Diq"/>
+                                                <constraint firstItem="LAE-e1-UaQ" firstAttribute="top" secondItem="vx9-6q-Zvk" secondAttribute="top" id="ejq-mq-bHg"/>
+                                                <constraint firstItem="FXV-tO-RYZ" firstAttribute="centerY" secondItem="vx9-6q-Zvk" secondAttribute="centerY" id="shX-wW-jkR"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                    </tableViewCell>
+                                </cells>
+                            </tableViewSection>
+                        </sections>
+                        <connections>
+                            <outlet property="dataSource" destination="MGw-hc-Bqe" id="y1c-fZ-VoF"/>
+                            <outlet property="delegate" destination="MGw-hc-Bqe" id="bgQ-Ze-Csn"/>
+                        </connections>
+                    </tableView>
+                    <navigationItem key="navigationItem" title="Change Password" id="5ap-sa-C8K">
+                        <barButtonItem key="leftBarButtonItem" title="Cancel" id="uzA-KT-Dzt">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            <connections>
+                                <action selector="cancelLogin:" destination="MGw-hc-Bqe" id="qsV-nO-xZx"/>
+                            </connections>
+                        </barButtonItem>
+                        <barButtonItem key="rightBarButtonItem" title="Change" id="yYu-r2-zyv">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            <connections>
+                                <action selector="changeButtonClicked:" destination="MGw-hc-Bqe" id="ZL5-UD-Tab"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                    <connections>
+                        <outlet property="confirmPasswordTextField" destination="LAE-e1-UaQ" id="ye8-5T-j6D"/>
+                        <outlet property="passwordTextField" destination="MyJ-Bk-1xO" id="QPq-BS-WJe"/>
+                    </connections>
+                </tableViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="wYf-Pe-R1d" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="2204" y="3813.6431784107949"/>
+        </scene>
+        <!--Settings-->
+        <scene sceneID="Dg1-T5-lYa">
+            <objects>
+                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="ji1-Yh-QLz" sceneMemberID="viewController">
+                    <tabBarItem key="tabBarItem" title="Settings" image="ResourceSettingsUnselected" selectedImage="ResourceSettingsSelected" id="wPf-sp-tCf"/>
+                    <toolbarItems/>
+                    <navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="11d-Ho-0vl">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                        <color key="barTintColor" red="0.90588235294117647" green="0.0" blue="0.070588235294117646" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <textAttributes key="titleTextAttributes">
+                            <fontDescription key="fontDescription" type="boldSystem" pointSize="18"/>
+                            <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        </textAttributes>
+                    </navigationBar>
+                    <nil name="viewControllers"/>
+                    <connections>
+                        <segue destination="kNN-aP-IXV" kind="relationship" relationship="rootViewController" id="Iq3-dP-ekZ"/>
+                    </connections>
+                </navigationController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="7hS-TJ-kiS" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="1289" y="3027"/>
+        </scene>
+        <!--WebAuth-->
+        <scene sceneID="woL-bQ-uNE">
+            <objects>
+                <viewController storyboardIdentifier="WebAuthViewControllerID" id="wTa-nS-3rH" customClass="WebAuthViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="REt-Jk-8fG"/>
+                        <viewControllerLayoutGuide type="bottom" id="Lc3-Mo-Chl"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="tHL-gU-Ifv">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <webView contentMode="scaleToFill" scalesPageToFit="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5pc-jk-dd9">
+                                <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                                <color key="backgroundColor" red="0.36078431370000003" green="0.38823529410000002" blue="0.4039215686" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <connections>
+                                    <outlet property="delegate" destination="wTa-nS-3rH" id="b6k-ub-N7T"/>
+                                </connections>
+                            </webView>
+                            <activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="1rf-mF-zdP">
+                                <rect key="frame" x="177.5" y="301.5" width="20" height="20"/>
+                            </activityIndicatorView>
+                        </subviews>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                        <constraints>
+                            <constraint firstItem="5pc-jk-dd9" firstAttribute="top" secondItem="REt-Jk-8fG" secondAttribute="bottom" id="8Rx-eO-ZPw"/>
+                            <constraint firstItem="1rf-mF-zdP" firstAttribute="centerX" secondItem="tHL-gU-Ifv" secondAttribute="centerX" id="N1H-bf-8ch"/>
+                            <constraint firstItem="5pc-jk-dd9" firstAttribute="top" secondItem="REt-Jk-8fG" secondAttribute="bottom" id="aYi-xr-5yI"/>
+                            <constraint firstItem="Lc3-Mo-Chl" firstAttribute="top" secondItem="5pc-jk-dd9" secondAttribute="bottom" id="bKz-4y-EOF"/>
+                            <constraint firstAttribute="trailing" secondItem="5pc-jk-dd9" secondAttribute="trailing" id="bjx-61-DoN"/>
+                            <constraint firstItem="1rf-mF-zdP" firstAttribute="centerY" secondItem="tHL-gU-Ifv" secondAttribute="centerY" id="iKO-dz-jHH"/>
+                            <constraint firstItem="5pc-jk-dd9" firstAttribute="leading" secondItem="tHL-gU-Ifv" secondAttribute="leading" id="rbM-ZI-BLl"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" title="WebAuth" id="Ndw-U2-Kyh">
+                        <barButtonItem key="leftBarButtonItem" title="Close" id="Aa6-VI-DlU">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            <connections>
+                                <action selector="cancelButtonClicked:" destination="wTa-nS-3rH" id="yBz-xC-iY0"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                    <connections>
+                        <outlet property="activityIndicator" destination="1rf-mF-zdP" id="x7w-WK-66f"/>
+                        <outlet property="webView" destination="5pc-jk-dd9" id="HmM-EV-oNH"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="CgL-Ao-Ib1" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="5440.8000000000002" y="1806.7466266866568"/>
+        </scene>
+        <!--Web View Controller-->
+        <scene sceneID="fvV-Ct-MEk">
+            <objects>
+                <viewController storyboardIdentifier="webViewController" id="Pj0-zq-9zu" customClass="ANWebViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="tCf-tr-Dak"/>
+                        <viewControllerLayoutGuide type="bottom" id="vDl-no-dbd"/>
+                    </layoutGuides>
+                    <view key="view" multipleTouchEnabled="YES" contentMode="scaleToFill" id="7Bc-Q5-I0g">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                        <subviews>
+                            <webView contentMode="scaleToFill" scalesPageToFit="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kwA-oW-glo">
+                                <rect key="frame" x="0.0" y="44" width="375" height="579"/>
+                            </webView>
+                            <toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" translucent="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qTD-pI-Mvx">
+                                <rect key="frame" x="0.0" y="623" width="375" height="44"/>
+                                <items>
+                                    <barButtonItem width="11" style="plain" systemItem="fixedSpace" id="dN1-9x-6Cp"/>
+                                    <barButtonItem image="browserBack.png" style="plain" id="4Ly-aa-L2c">
+                                        <inset key="imageInsets" minX="0.0" minY="2.5" maxX="-1" maxY="-2"/>
+                                        <connections>
+                                            <action selector="goBack:" destination="Pj0-zq-9zu" id="b8I-cV-Tdw"/>
+                                        </connections>
+                                    </barButtonItem>
+                                    <barButtonItem style="plain" systemItem="flexibleSpace" id="CWi-b2-9Im"/>
+                                    <barButtonItem image="browserForward.png" style="plain" id="hhs-TN-Vsn">
+                                        <inset key="imageInsets" minX="0.0" minY="2.5" maxX="-1" maxY="-2"/>
+                                        <connections>
+                                            <action selector="goForward:" destination="Pj0-zq-9zu" id="jFk-JM-9hJ"/>
+                                        </connections>
+                                    </barButtonItem>
+                                    <barButtonItem style="plain" systemItem="flexibleSpace" id="hT9-jC-VfJ"/>
+                                    <barButtonItem image="NavTab.png" style="plain" id="FbZ-aN-cuc">
+                                        <inset key="imageInsets" minX="0.0" minY="3" maxX="0.0" maxY="-3"/>
+                                        <connections>
+                                            <action selector="openExposeController:" destination="Pj0-zq-9zu" id="zaG-Dn-2sd"/>
+                                        </connections>
+                                    </barButtonItem>
+                                    <barButtonItem width="9" style="plain" systemItem="fixedSpace" id="OaZ-BO-Gge"/>
+                                </items>
+                            </toolbar>
+                            <navigationBar contentMode="scaleToFill" translucent="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bYV-bn-kYy">
+                                <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                                <color key="backgroundColor" red="0.89411764709999997" green="0.43921568630000002" blue="0.1137254902" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <color key="tintColor" red="0.89411764709999997" green="0.43921568630000002" blue="0.1137254902" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <color key="barTintColor" red="0.90588235294117647" green="0.0" blue="0.070588235294117646" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <textAttributes key="titleTextAttributes">
+                                    <fontDescription key="fontDescription" type="boldSystem" pointSize="18"/>
+                                    <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                </textAttributes>
+                                <items>
+                                    <navigationItem id="uEA-in-mD0"/>
+                                </items>
+                            </navigationBar>
+                        </subviews>
+                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <constraints>
+                            <constraint firstItem="bYV-bn-kYy" firstAttribute="bottom" secondItem="kwA-oW-glo" secondAttribute="top" id="7cn-gd-edD"/>
+                            <constraint firstItem="bYV-bn-kYy" firstAttribute="leading" secondItem="qTD-pI-Mvx" secondAttribute="leading" id="7v1-xI-Eif"/>
+                            <constraint firstItem="bYV-bn-kYy" firstAttribute="trailing" secondItem="qTD-pI-Mvx" secondAttribute="trailing" id="Rlr-9h-V6B"/>
+                            <constraint firstItem="bYV-bn-kYy" firstAttribute="top" secondItem="tCf-tr-Dak" secondAttribute="bottom" symbolic="YES" id="XLr-zv-1qm"/>
+                            <constraint firstItem="bYV-bn-kYy" firstAttribute="leading" secondItem="7Bc-Q5-I0g" secondAttribute="leading" id="aS6-Lc-PrJ"/>
+                            <constraint firstItem="bYV-bn-kYy" firstAttribute="leading" secondItem="kwA-oW-glo" secondAttribute="leading" id="aab-Ud-HO3"/>
+                            <constraint firstAttribute="trailing" secondItem="bYV-bn-kYy" secondAttribute="trailing" id="cdc-Rb-EMY"/>
+                            <constraint firstAttribute="bottom" secondItem="qTD-pI-Mvx" secondAttribute="bottom" id="clj-1y-cwr"/>
+                            <constraint firstItem="bYV-bn-kYy" firstAttribute="trailing" secondItem="kwA-oW-glo" secondAttribute="trailing" id="oOg-QS-8Dh"/>
+                            <constraint firstItem="qTD-pI-Mvx" firstAttribute="bottom" secondItem="kwA-oW-glo" secondAttribute="bottom" constant="44" id="oXd-g5-AeC"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" id="rht-pr-CKf"/>
+                    <connections>
+                        <outlet property="btnBack" destination="4Ly-aa-L2c" id="h1e-Wt-ffj"/>
+                        <outlet property="btnForward" destination="hhs-TN-Vsn" id="q6E-hA-tKv"/>
+                        <outlet property="btnOpenExpose" destination="FbZ-aN-cuc" id="Hqx-pm-HgQ"/>
+                        <outlet property="toolbar" destination="qTD-pI-Mvx" id="VfK-ED-aT3"/>
+                        <outlet property="webview" destination="kwA-oW-glo" id="8qk-Sq-vJG"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="Sfq-sT-cmb" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="-1876" y="3814"/>
+        </scene>
+        <!--Navigation Controller-->
+        <scene sceneID="5Hy-oP-LZV">
+            <objects>
+                <navigationController automaticallyAdjustsScrollViewInsets="NO" modalPresentationStyle="fullScreen" id="l9d-Rt-vCd" sceneMemberID="viewController">
+                    <toolbarItems/>
+                    <navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="nKi-CN-vD5">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        <color key="barTintColor" red="0.90588235294117647" green="0.0" blue="0.070588235294117646" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    </navigationBar>
+                    <nil name="viewControllers"/>
+                    <connections>
+                        <segue destination="ge6-AP-0um" kind="relationship" relationship="rootViewController" id="5Ga-N9-rMf"/>
+                    </connections>
+                </navigationController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="uO0-H0-LFh" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="4501.6000000000004" y="689.5052473763119"/>
+        </scene>
+        <!--Syfer Lock Login View Controller-->
+        <scene sceneID="A4g-We-toO">
+            <objects>
+                <viewController storyboardIdentifier="toSyferLockLogin" useStoryboardIdentifierAsRestorationIdentifier="YES" id="Own-rK-e3P" customClass="SyferLockLoginViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="Q4L-nK-dUR"/>
+                        <viewControllerLayoutGuide type="bottom" id="e8z-q7-em7"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="8E7-Lq-6o9">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="623"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ewU-UW-M2d">
+                                <rect key="frame" x="12" y="585" width="351" height="30"/>
+                                <color key="backgroundColor" red="0.90588235294117647" green="0.0" blue="0.070588235294117646" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <state key="normal" title="Login">
+                                    <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                </state>
+                                <connections>
+                                    <action selector="loginButtonTapped:" destination="Own-rK-e3P" eventType="touchUpInside" id="El5-VL-bqj"/>
+                                </connections>
+                            </button>
+                            <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" bounces="NO" scrollEnabled="NO" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="jwZ-uK-xoQ">
+                                <rect key="frame" x="16" y="8" width="343" height="527"/>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                                <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="qdB-nW-vwe">
+                                    <size key="itemSize" width="50" height="50"/>
+                                    <size key="headerReferenceSize" width="0.0" height="0.0"/>
+                                    <size key="footerReferenceSize" width="0.0" height="0.0"/>
+                                    <inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                </collectionViewFlowLayout>
+                                <cells/>
+                            </collectionView>
+                            <activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="Dhk-bB-ppf">
+                                <rect key="frame" x="177.5" y="590" width="20" height="20"/>
+                            </activityIndicatorView>
+                            <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="7cr-Yb-azO">
+                                <rect key="frame" x="136" y="543" width="227" height="34"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                <textInputTraits key="textInputTraits" keyboardType="numbersAndPunctuation" returnKeyType="done" secureTextEntry="YES"/>
+                            </textField>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Enter GridPIN" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mvS-kK-HYj">
+                                <rect key="frame" x="12" y="547" width="104" height="20.5"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                        </subviews>
+                        <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803915" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <gestureRecognizers/>
+                        <constraints>
+                            <constraint firstItem="jwZ-uK-xoQ" firstAttribute="top" secondItem="Q4L-nK-dUR" secondAttribute="bottom" constant="8" id="5Bc-4N-rx6"/>
+                            <constraint firstItem="ewU-UW-M2d" firstAttribute="leading" secondItem="mvS-kK-HYj" secondAttribute="leading" id="5nw-dG-41u"/>
+                            <constraint firstItem="jwZ-uK-xoQ" firstAttribute="trailing" secondItem="8E7-Lq-6o9" secondAttribute="trailingMargin" id="6CZ-38-N6w"/>
+                            <constraint firstItem="ewU-UW-M2d" firstAttribute="trailing" secondItem="7cr-Yb-azO" secondAttribute="trailing" id="CAD-PO-ThV"/>
+                            <constraint firstItem="Dhk-bB-ppf" firstAttribute="centerX" secondItem="8E7-Lq-6o9" secondAttribute="centerX" id="E0q-zc-x4S"/>
+                            <constraint firstItem="Dhk-bB-ppf" firstAttribute="top" secondItem="7cr-Yb-azO" secondAttribute="bottom" constant="13" id="IKG-OE-w51"/>
+                            <constraint firstItem="e8z-q7-em7" firstAttribute="top" secondItem="ewU-UW-M2d" secondAttribute="bottom" constant="8" id="KXZ-NO-F1o"/>
+                            <constraint firstAttribute="trailingMargin" secondItem="ewU-UW-M2d" secondAttribute="trailing" constant="-4" id="SFf-vX-avp"/>
+                            <constraint firstItem="7cr-Yb-azO" firstAttribute="top" secondItem="jwZ-uK-xoQ" secondAttribute="bottom" constant="8" id="WLP-00-Mgp"/>
+                            <constraint firstItem="e8z-q7-em7" firstAttribute="top" secondItem="ewU-UW-M2d" secondAttribute="bottom" constant="8" id="WON-Hd-91m"/>
+                            <constraint firstItem="jwZ-uK-xoQ" firstAttribute="leading" secondItem="8E7-Lq-6o9" secondAttribute="leadingMargin" id="ZrN-Vz-Wg0"/>
+                            <constraint firstItem="mvS-kK-HYj" firstAttribute="top" secondItem="jwZ-uK-xoQ" secondAttribute="bottom" constant="12" id="giF-RB-M81"/>
+                            <constraint firstItem="ewU-UW-M2d" firstAttribute="leading" secondItem="8E7-Lq-6o9" secondAttribute="leadingMargin" constant="-4" id="j56-UP-Cgp"/>
+                            <constraint firstItem="ewU-UW-M2d" firstAttribute="top" secondItem="7cr-Yb-azO" secondAttribute="bottom" constant="8" id="kN1-8l-Tid"/>
+                            <constraint firstItem="7cr-Yb-azO" firstAttribute="leading" secondItem="mvS-kK-HYj" secondAttribute="trailing" constant="20" id="ltH-Dc-mh7"/>
+                            <constraint firstItem="7cr-Yb-azO" firstAttribute="top" secondItem="jwZ-uK-xoQ" secondAttribute="bottom" constant="8" id="rpr-MW-C4Z"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" id="H3u-cn-ZJs">
+                        <barButtonItem key="leftBarButtonItem" title="Cancel" id="axq-BG-27D">
+                            <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                            <connections>
+                                <action selector="cancelButtonTapped:" destination="Own-rK-e3P" id="rLZ-IC-h0Z"/>
+                            </connections>
+                        </barButtonItem>
+                    </navigationItem>
+                    <connections>
+                        <outlet property="cancelBarButton" destination="axq-BG-27D" id="Bne-zL-7Wr"/>
+                        <outlet property="collectionView" destination="jwZ-uK-xoQ" id="m8a-dT-1Hw"/>
+                        <outlet property="gridPINLabel" destination="mvS-kK-HYj" id="f1e-c6-Seq"/>
+                        <outlet property="loginActivity" destination="Dhk-bB-ppf" id="4SP-qF-c3b"/>
+                        <outlet property="loginButton" destination="ewU-UW-M2d" id="eYg-Es-cZd"/>
+                        <outlet property="passwordTextField" destination="7cr-Yb-azO" id="bxL-cN-RA3"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="6mD-He-deo" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="5441" y="2624"/>
+        </scene>
+        <!--Navigation Controller-->
+        <scene sceneID="Z58-lh-SrP">
+            <objects>
+                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="AQs-MT-X4V" sceneMemberID="viewController">
+                    <toolbarItems/>
+                    <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" translucent="NO" id="nkF-48-VZm">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <color key="barTintColor" red="0.90588235294117647" green="0.0" blue="0.070588235294117646" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <textAttributes key="titleTextAttributes">
+                            <fontDescription key="fontDescription" type="boldSystem" pointSize="18"/>
+                            <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        </textAttributes>
+                    </navigationBar>
+                    <nil name="viewControllers"/>
+                    <connections>
+                        <segue destination="wTa-nS-3rH" kind="relationship" relationship="rootViewController" id="sz0-NX-E94"/>
+                    </connections>
+                </navigationController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="dvW-Gd-WfJ" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="4513" y="1807"/>
+        </scene>
+    </scenes>
+    <inferredMetricsTieBreakers>
+        <segue reference="bpD-LK-kUE"/>
+        <segue reference="Iyn-qq-u9T"/>
+    </inferredMetricsTieBreakers>
+    <resources>
+        <image name="CertificateDelete" width="14" height="14"/>
+        <image name="CertificateUnselected" width="22" height="22"/>
+        <image name="GatewayAppIcon" width="76" height="76"/>
+        <image name="GatewayDelete" width="17" height="17"/>
+        <image name="GatewayItemAdd" width="20" height="20"/>
+        <image name="GatewayItemMore" width="20" height="17"/>
+        <image name="LoginDropArrow" width="15.5" height="9"/>
+        <image name="LoginExit" width="17" height="17"/>
+        <image name="LoginMethodName" width="16" height="14.5"/>
+        <image name="LoginPassword" width="13.5" height="15"/>
+        <image name="LoginSelected" width="16" height="15"/>
+        <image name="LoginUsername" width="15" height="15"/>
+        <image name="NavTab.png" width="20" height="19"/>
+        <image name="ResourceConnectSuccess" width="16" height="16"/>
+        <image name="ResourceEmpty" width="128" height="102.5"/>
+        <image name="ResourceExit" width="20" height="21"/>
+        <image name="ResourceGatewaySelected" width="22" height="20"/>
+        <image name="ResourceGatewayUnselected" width="22" height="20"/>
+        <image name="ResourceSettingsSelected" width="22" height="22"/>
+        <image name="ResourceSettingsUnselected" width="22" height="22"/>
+        <image name="ResourceStatusSelected" width="22" height="22"/>
+        <image name="ResourceStatusUnselected" width="22" height="22"/>
+        <image name="browserBack.png" width="16" height="20"/>
+        <image name="browserForward.png" width="16" height="20"/>
+        <systemColor name="groupTableViewBackgroundColor">
+            <color red="0.94901960784313721" green="0.94901960784313721" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+        </systemColor>
+        <systemColor name="tableCellGroupedBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
+    </resources>
+</document>
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ANTabBarController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ANTabBarController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ANTabBarController.h	(working copy)
@@ -0,0 +1,13 @@
+//
+//  ANTabBarController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/27.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface ANTabBarController : UITabBarController
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ANTabBarController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ANTabBarController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ANTabBarController.m	(working copy)
@@ -0,0 +1,35 @@
+//
+//  ANTabBarController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/27.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "ANTabBarController.h"
+
+@interface ANTabBarController ()
+
+@end
+
+@implementation ANTabBarController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    NSDictionary *selectedDict = @{NSForegroundColorAttributeName: MAIN_COLOR};
+    NSDictionary *unselectedDict = @{NSForegroundColorAttributeName: UIColorFromRGBA(0x666666, 1.0)};
+    for (UITabBarItem *item in self.tabBar.items) {
+        [item setTitleTextAttributes:unselectedDict forState:UIControlStateNormal];
+        [item setTitleTextAttributes:selectedDict forState:UIControlStateSelected];
+    }
+    self.tabBar.tintColor = MAIN_COLOR;
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/AboutViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/AboutViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/AboutViewController.h	(working copy)
@@ -0,0 +1,13 @@
+//
+//  AboutViewController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/11.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface AboutViewController : UIViewController
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/AboutViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/AboutViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/AboutViewController.m	(working copy)
@@ -0,0 +1,209 @@
+//
+//  AboutViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/11.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "ANLogger.h"
+#import "AAAManager.h"
+#import "UIDevice+Hardware.h"
+#import "AboutViewController.h"
+#import "GatewayManager.h"
+#import "ANPopupDialog.h"
+#import "Global.h"
+
+static NSInteger const kVersionCellIndex = 0;
+static NSInteger const kCopyrightCellIndex = 1;
+static NSInteger const kDeviceIDCellIndex = 2;
+static NSInteger const kVersionLabelTag = 1;
+static NSInteger const kCopyrightLabelTag = 1;
+static NSInteger const kDeviceIDLabelTag = 1;
+static NSInteger const kCheckUpdateButtonTag = 2;
+
+static NSString * const kVersionCellID = @"VersionCellID";
+static NSString * const kCopyrightCellID = @"CopyrightCellID";
+static NSString * const kDeviceIDCellID = @"DeviceIDCellID";
+
+@interface AboutViewController () <UITableViewDataSource>
+
+@property (weak, nonatomic) IBOutlet UIImageView *imageView;
+@property (weak, nonatomic) IBOutlet UITableView *tableView;
+@property (nonatomic) BOOL needUpdate;
+@property (strong, nonatomic) NSString *lastClientVersion;
+
+@end
+
+@implementation AboutViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    [self initImageView];
+}
+
+- (void)viewDidLayoutSubviews {
+    // Move copyright label upwards for iPhone5s/iPhoneSE.
+    if ([[UIDevice currentDevice] isIphone5]) {
+        NSIndexPath *copyrightIndexPath = [NSIndexPath indexPathForRow:kCopyrightCellIndex inSection:0];
+        UITableViewCell *copyrightCell = [self.tableView cellForRowAtIndexPath:copyrightIndexPath];
+        if (copyrightCell) {
+            UILabel *copyrightLabel = [copyrightCell viewWithTag:kCopyrightLabelTag];
+            if (copyrightLabel) {
+                CGRect originalFrame = copyrightLabel.frame;
+                copyrightLabel.frame = CGRectMake(originalFrame.origin.x, originalFrame.origin.y-4, originalFrame.size.width, originalFrame.size.height);
+            }
+        }
+    }
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (void)initImageView {
+    self.imageView.layer.masksToBounds = YES;
+    self.imageView.layer.cornerRadius = 5;
+}
+
+- (NSString *)loadVersionInfo {
+    NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
+    return [infoDictionary objectForKey:@"CFBundleShortVersionString"];
+}
+
+- (NSString *)loadBuildInfo {
+    NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
+    return [infoDictionary objectForKey:@"CFBundleVersion"];
+}
+
+- (NSString *)loadDeviceID {
+    return [AAAManager sharedInstance].deviceID;
+}
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return 1;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return 3;
+}
+
+- (void)checkUpdateButtonClicked:(id)sender {
+    if (_needUpdate) {
+        //__weak typeof(self) weakSelf = self;
+        PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:_lastClientVersion
+                                                                      message:NSLocalizedString(@"A new version is detected. Do you want to install?", nil)
+                                                                confirmAction:^{
+            ANInfo(@"user confirm update");
+            GatewayManager *gatewayManager = [GatewayManager sharedInstance];
+            NSString *downloadURL = [gatewayManager getClientDownloadURL];
+            if ([downloadURL length] <= 0) {
+                downloadURL = @"http://app.arraynetworks.com.cn/motionproplus";
+            }
+            OpenURL([NSURL URLWithString:downloadURL]);
+                                                                }
+                                                                 cancelAction:^{
+            ANInfo(@"user cancel update");
+        }];
+        [self presentViewController:popup animated:YES completion:nil];
+    } else {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:_lastClientVersion message:NSLocalizedString(@"The current version is the latest version.", nil)];
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell *cell = nil;
+    if (indexPath.row == kVersionCellIndex) {
+        cell = [self.tableView dequeueReusableCellWithIdentifier:kVersionCellID];
+        UILabel *versionLabel = [cell viewWithTag:kVersionLabelTag];
+        if (versionLabel != nil) {
+            NSString *version = [self loadVersionInfo];
+            NSString *build = [self loadBuildInfo];
+            versionLabel.text = [NSString stringWithFormat:@"%@    Build %@", version, build];
+            
+            GatewayManager *gatewayManager = [GatewayManager sharedInstance];
+            _lastClientVersion = [gatewayManager getLastClientVersion];
+            ANInfo(@"local motionpro version:%@, last motionpro version=%@.", version, _lastClientVersion);
+            _needUpdate = NO;
+            if ([_lastClientVersion compare:version options:NSNumericSearch] == NSOrderedDescending) {
+                ANInfo(@"motionpro need update.");
+                _needUpdate = YES;
+            }
+            
+            UIButton *checkUpdateButton = (UIButton *)[cell viewWithTag:kCheckUpdateButtonTag];
+            if ([_lastClientVersion length] <= 0) {
+                checkUpdateButton.hidden = YES;
+            } else {
+                checkUpdateButton.hidden = NO;
+            }
+            
+            [checkUpdateButton addTarget:self action:@selector(checkUpdateButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
+        }
+    } else if (indexPath.row == kCopyrightCellIndex) {
+        cell = [self.tableView dequeueReusableCellWithIdentifier:kCopyrightCellID];
+        UILabel *copyrightLabel = [cell viewWithTag:kCopyrightLabelTag];
+        if (copyrightLabel != nil) {
+            NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
+            formatter.dateFormat = @"YYYY";
+            NSString *year = [formatter stringFromDate:[NSDate date]];
+            copyrightLabel.text = [NSString stringWithFormat:@"©2014-%@ Array Networks Inc. All rights reserved.", year];
+        }
+    } else if (indexPath.row == kDeviceIDCellIndex) {
+        cell = [self.tableView dequeueReusableCellWithIdentifier:kDeviceIDCellID];
+        UILabel *deviceIDLabel = [cell viewWithTag:kDeviceIDLabelTag];
+        if (deviceIDLabel) {
+            deviceIDLabel.text = [self loadDeviceID];
+        }
+    }
+    
+    return cell;
+}
+
+#pragma mark - UITableViewDelegate
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    [tableView deselectRowAtIndexPath:indexPath animated:YES];
+    
+    if (indexPath.row == kDeviceIDCellIndex && indexPath.section == 0) {
+        [self showCopyMenu];
+    }
+}
+
+// Copy menu for deviceID
+- (BOOL)canBecomeFirstResponder {  // To show menu.
+    return YES;
+}
+
+- (void)showCopyMenu {
+    NSIndexPath *deviceIDCellIndexPath = [NSIndexPath indexPathForRow:kDeviceIDCellIndex inSection:0];
+    UITableViewCell *deviceIDCell = [self.tableView cellForRowAtIndexPath:deviceIDCellIndexPath];
+    if (deviceIDCell) {
+        UILabel *deviceIDLabel = [deviceIDCell viewWithTag:kDeviceIDLabelTag];
+        if (deviceIDLabel) {
+            [self becomeFirstResponder];
+            
+            UIMenuController *controller = [UIMenuController sharedMenuController];
+            UIMenuItem *copyItem = [[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Copy", nil) action:@selector(customCopy:)];
+            [controller setMenuItems:[NSArray arrayWithObjects:copyItem, nil]];
+            [controller setTargetRect:deviceIDCell.contentView.frame inView:deviceIDCell.contentView];
+            [controller setMenuVisible:YES animated:YES];
+        }
+    }
+}
+
+- (void)customCopy:(id)sender {
+    NSIndexPath *deviceIDCellIndexPath = [NSIndexPath indexPathForRow:kDeviceIDCellIndex inSection:0];
+    UITableViewCell *deviceIDCell = [self.tableView cellForRowAtIndexPath:deviceIDCellIndexPath];
+    if (deviceIDCell) {
+        UILabel *deviceIDLabel = [deviceIDCell viewWithTag:kDeviceIDLabelTag];
+        UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
+        pasteboard.string = deviceIDLabel.text;
+        
+        ANDebug(@"Pasted string: %@", pasteboard.string);
+    }
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/AccessModeSelectViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/AccessModeSelectViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/AccessModeSelectViewController.h	(working copy)
@@ -0,0 +1,23 @@
+//
+//  AcsModeViewController.h
+//  MotionProPlus
+//
+//  Created by wangxy on 2019/7/23.
+//  Copyright © 2019 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@protocol AcsModeSelectControllerDelegate <NSObject>
+
+- (void)didFinishSelect:(NSString *)selectAcsDesc;
+
+@end
+
+
+@interface AccessModeSelectViewController : UITableViewController
+
+@property (weak, nonatomic) id<AcsModeSelectControllerDelegate> delegate;
+@property (nonatomic, strong) NSString *selectedAcsModeString;
+@end
+
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/AccessModeSelectViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/AccessModeSelectViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/AccessModeSelectViewController.m	(working copy)
@@ -0,0 +1,169 @@
+//
+//  AcsModeViewController.m
+//  MotionProPlus
+//
+//  Created by wangxy on 2019/7/23.
+//  Copyright © 2019 wangxy. All rights reserved.
+//
+#import "Global.h"
+#import "ANLogger.h"
+#import "AccessModeSelectViewController.h"
+#import "AccessModeSelectCell.h"
+#import "AAAManager.h"
+
+
+static NSString * const kAcsModeStoryBoardID = @"AcsModeViewControllerID";
+static NSString * const AccessModeSelectCellID = @"AccessModeSelectCellID";
+
+@interface AccessModeSelectViewController ()
+
+@property (nonatomic, strong) NSArray *acsDescList;
+@property (nonatomic, strong) NSString *selectAcsDesc;
+
+@end
+
+@implementation AccessModeSelectViewController
+
+@synthesize selectedAcsModeString;
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    
+    [self registerCells];
+    [self initAccessModeInfo];
+}
+
+- (void)registerCells {
+    [self.tableView registerClass:[AccessModeSelectCell class] forCellReuseIdentifier: AccessModeSelectCellID];
+}
+
+- (void)initAccessModeInfo {
+    self.acsDescList = [AAAManager sharedInstance].acsModeDesc;
+    
+    BOOL bSelectAllMode = NO;
+    if (self.selectedAcsModeString == nil) {
+        bSelectAllMode = YES;
+    }
+    NSArray *cells = [self cellsForTableView:self.tableView];
+    for (AccessModeSelectCell *cell in cells) {
+        if (bSelectAllMode) {
+            [cell showSelectView:NO];
+            [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+        } else {
+            if ([self.selectedAcsModeString isEqualToString:[cell getCellText]]) {
+                [cell showSelectView:YES];
+                [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+            } else {
+                [cell showSelectView:NO];
+                [cell setCellImage:ACCESS_MODE_IMAGE_INACTIVE_NAME];
+            }
+        }
+    }
+}
+
+- (IBAction)cancelButtonClicked:(id)sender {
+    [self dismissViewControllerAnimated:YES completion:nil];
+}
+
+- (IBAction)saveButtonClicked:(id)sender {
+    NSArray *cells = [self cellsForTableView:self.tableView];
+    NSString *acsSelectedDesc = nil;
+    for (AccessModeSelectCell *cell in cells) {
+        if ([cell isSelectCell]) {
+            acsSelectedDesc = [cell getCellText];
+        }
+    }
+    
+    __weak typeof(self) weakSelf = self;
+    [self dismissViewControllerAnimated:YES completion:^{
+        [weakSelf.delegate didFinishSelect:acsSelectedDesc];
+    }];
+}
+
+- (NSArray *)cellsForTableView:(UITableView *)tableView
+{
+    NSInteger sections = tableView.numberOfSections;
+    NSMutableArray *cells = [[NSMutableArray alloc]  init];
+    for (int section = 0; section < sections; section++) {
+        NSInteger rows =  [tableView numberOfRowsInSection:section];
+        for (int row = 0; row < rows; row++) {
+            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
+            UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
+            if (cell == nil) {
+                continue;
+            }
+            [cells addObject:cell];
+        }
+    }
+    return cells;
+}
+
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return 1;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return self.acsDescList.count;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    NSInteger row = indexPath.row;
+    NSString *acsDesc = [self.acsDescList objectAtIndex:row];
+    
+    AccessModeSelectCell *accessModeCell = [[AccessModeSelectCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:AccessModeSelectCellID];
+
+    
+    [accessModeCell configureCellWithMessage:acsDesc isDescList:YES];
+    
+    return accessModeCell;
+}
+
+#pragma mark - UITableViewDelegate
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    return self.acsDescList.count + 1;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    [tableView deselectRowAtIndexPath:indexPath animated:YES];
+    
+    AccessModeSelectCell *cell = (AccessModeSelectCell *)[tableView cellForRowAtIndexPath:indexPath];
+    self.selectAcsDesc = [cell getCellText];
+    ANInfo(@"select acs desc=%@", self.selectAcsDesc);
+    
+    NSArray *cells = [self cellsForTableView:tableView];
+    for (AccessModeSelectCell *cell in cells) {
+        if (cell == (AccessModeSelectCell *)[tableView cellForRowAtIndexPath:indexPath]) {
+            [cell showSelectView:YES];
+            [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+        } else {
+            [cell showSelectView:NO];
+            [cell setCellImage:ACCESS_MODE_IMAGE_INACTIVE_NAME];
+        }
+    }
+}
+
+- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
+{
+    if ([self.selectAcsDesc length] <= 0 && [self.selectedAcsModeString length] <= 0) {
+        return;
+    }
+    AccessModeSelectCell* acsCell = (AccessModeSelectCell *)(cell);
+    if ([acsCell.getCellText isEqualToString:self.selectAcsDesc] || [acsCell.getCellText isEqualToString:self.selectedAcsModeString]) {
+        [acsCell showSelectView:YES];
+        [acsCell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+    } else {
+        [acsCell showSelectView:NO];
+        [acsCell setCellImage:ACCESS_MODE_IMAGE_INACTIVE_NAME];
+    }
+}
+
+
+@end
+
+
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificateInstallViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificateInstallViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificateInstallViewController.h	(working copy)
@@ -0,0 +1,15 @@
+//
+//  CertificateInstallViewController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/23.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+NSString * const kAppGroupDesc = @"group.net.arraynetworks.MotionProPlus";
+
+@interface CertificateInstallViewController : UIViewController
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificateInstallViewController.h.InfosecEnterprise
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificateInstallViewController.h.InfosecEnterprise	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificateInstallViewController.h.InfosecEnterprise	(working copy)
@@ -0,0 +1,15 @@
+//
+//  CertificateInstallViewController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/23.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+NSString * const kAppGroupDesc = @"group.net.infosec.groupenterprise";
+
+@interface CertificateInstallViewController : UIViewController
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificateInstallViewController.h.InfosecStore
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificateInstallViewController.h.InfosecStore	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificateInstallViewController.h.InfosecStore	(working copy)
@@ -0,0 +1,15 @@
+//
+//  CertificateInstallViewController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/23.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+NSString * const kAppGroupDesc = @"group.net.infosec.MotionPro";
+
+@interface CertificateInstallViewController : UIViewController
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificateInstallViewController.h.MotionPro
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificateInstallViewController.h.MotionPro	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificateInstallViewController.h.MotionPro	(working copy)
@@ -0,0 +1,15 @@
+//
+//  CertificateInstallViewController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/23.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+NSString * const kAppGroupDesc = @"group.net.arraynetworks.MotionPro";
+
+@interface CertificateInstallViewController : UIViewController
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificateInstallViewController.h.MotionProEnterprise
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificateInstallViewController.h.MotionProEnterprise	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificateInstallViewController.h.MotionProEnterprise	(working copy)
@@ -0,0 +1,15 @@
+//
+//  CertificateInstallViewController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/23.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+NSString * const kAppGroupDesc = @"group.net.arraynetworks.groupenterprise";
+
+@interface CertificateInstallViewController : UIViewController
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificateInstallViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificateInstallViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificateInstallViewController.m	(working copy)
@@ -0,0 +1,459 @@
+//
+//  CertificateInstallViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/23.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "ANLogger.h"
+#import "ANPopupDialog.h"
+#import "CertificateManager.h"
+#import "UIViewController+HideKeyboard.h"
+#import "CertificateInstallViewController.h"
+#import "SelectCell.h"
+#import "ANImageButton.h"
+#import "ActionSheetPicker.h"
+
+
+@interface CertificateInstallViewController ()
+
+@property (weak, nonatomic) IBOutlet UITextField *addressTextField;
+@property (weak, nonatomic) IBOutlet UIButton *installButton;
+
+@property (weak, nonatomic) IBOutlet UITableView *localCertTableView;
+@property (weak, nonatomic) IBOutlet ANImageButton *urlSelectButton;
+@property (weak, nonatomic) IBOutlet ANImageButton *localSelectButton;
+
+@property (nonatomic, strong) UIAlertController *passCheck;
+@property (nonatomic, strong) UIAlertController *nameCheck;
+@property (nonatomic, strong) UIAlertController *retryView;
+
+@property (nonatomic, strong) NSString *currentAddCertPath;
+@property (nonatomic, strong) NSArray *localCertNameList;
+@property (nonatomic, strong) NSString *certNameSelected;
+
+@property (nonatomic, strong) NSMutableData *cert;
+@property (nonatomic, strong) NSURLConnection *connection;
+@property (nonatomic, strong) NSHTTPURLResponse *resp;
+
+@property (nonatomic) BOOL isURLSelected;
+
+@end
+
+@implementation CertificateInstallViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    [self enableHideKeyboard];
+    [self initButtonAppearance];
+    
+    self.cert = [[NSMutableData alloc] initWithCapacity:10];
+    
+    [self.localCertTableView registerNib:[UINib nibWithNibName:@"SelectCell" bundle:nil] forCellReuseIdentifier:kSelectCellID];
+    self.localCertTableView.tableHeaderView = [[UIView alloc]initWithFrame:CGRectMake(0,0,0,0.01)];
+    self.isURLSelected = YES;
+    [self setSelectType:YES];
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    self.addressTextField.text = [self lastUrlString];
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (void)initButtonAppearance {
+    self.installButton.layer.cornerRadius = 2.5;
+    self.installButton.layer.shadowOffset = CGSizeMake(5.0, 5.0);
+    self.installButton.layer.shadowColor = MAIN_COLOR.CGColor;
+    self.installButton.layer.shadowOpacity = 0.25;
+}
+
+- (IBAction)closeButtonClicked:(id)sender {
+    [self closeConnection];
+    
+    [self dismissViewControllerAnimated:YES completion:nil];
+}
+
+- (IBAction)urlSelecteButtonClicked:(id)sender {
+    if (![self isURLSelected]) {
+        self.isURLSelected = YES;
+        [self setSelectType:YES];
+    }
+}
+
+- (IBAction)localSelecteButtonClicked:(id)sender {
+    if ([self isURLSelected]) {
+        self.isURLSelected = NO;
+        [self setSelectType:NO];
+    }
+}
+
+- (void)configCertLabel:(NSString *)name {
+}
+
+- (IBAction)installButtonClicked:(id)sender {
+    if ([self isURLSelected]) {
+        [self.addressTextField resignFirstResponder];
+        
+        [self closeConnection];
+        
+        NSString *urlString = [self.addressTextField.text stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
+        NSURL *url = [NSURL URLWithString:urlString];
+        [self saveLastUrlString:self.addressTextField.text];
+        
+        if (![url.scheme isEqualToString:@"http"] && ![url.scheme isEqualToString:@"https"] && ![url.scheme isEqualToString:@"ftp"]) {
+            PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+                                                                          message:NSLocalizedString(@"The url you input is incorrect. Please input another one.", nil)];
+            [self presentViewController:dialog animated:YES completion:nil];
+            
+            return;
+        }
+        
+        NSURLRequest *request = [NSURLRequest requestWithURL:url];
+        self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
+        
+        [self.connection start];
+        [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
+    } else {
+        if ([self.certNameSelected length] <= 0) {
+            PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+                                                                          message:NSLocalizedString(@"There is no certificate. Please import a new one.", nil)];
+            [self presentViewController:dialog animated:YES completion:nil];
+            
+            return;
+        }
+        NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupDesc];
+        NSData *data = [userDefaults valueForKey:self.certNameSelected];
+        if (data == nil) {
+            PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+                                                                          message:NSLocalizedString(@"The import fails due to the missing certificate content.", nil)];
+            [self presentViewController:dialog animated:YES completion:nil];
+            
+            return;
+        }
+        
+        [self.cert appendData:data];
+        [self installCertificate];
+    }
+}
+
+- (void)getLocalCertMsg {
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupDesc];
+    NSString *localListString = [userDefaults valueForKey:@"cert_list"];
+    self.localCertNameList = [localListString componentsSeparatedByCharactersInSet:
+                     [NSCharacterSet characterSetWithCharactersInString:@","]];
+    ANInfo(@"Import Certificate from share extension, current cert list[%@].", self.localCertNameList);
+}
+
+- (void)setSelectType:(BOOL)isSelectURL {
+    UIImage *imageSelected = [UIImage imageNamed:@"CertificateSelected"];
+    UIImage *imageUnSelected = [UIImage imageNamed:@"CertificateUnselected"];
+    if (isSelectURL) {
+        [self.urlSelectButton setImage:imageSelected forState:UIControlStateNormal];
+        [self.urlSelectButton setImage:imageSelected forState:UIControlStateHighlighted];
+        [self.localSelectButton setImage:imageUnSelected forState:UIControlStateNormal];
+        [self.localSelectButton setImage:imageUnSelected forState:UIControlStateHighlighted];
+        self.localCertTableView.userInteractionEnabled = NO;
+        self.localCertTableView.alpha=0.4;
+        self.addressTextField.userInteractionEnabled = YES;
+        self.addressTextField.alpha=1;
+    } else {
+        [self.urlSelectButton setImage:imageUnSelected forState:UIControlStateNormal];
+        [self.urlSelectButton setImage:imageUnSelected forState:UIControlStateHighlighted];
+        [self.localSelectButton setImage:imageSelected forState:UIControlStateNormal];
+        [self.localSelectButton setImage:imageSelected forState:UIControlStateHighlighted];
+        self.localCertTableView.userInteractionEnabled = YES;
+        self.localCertTableView.alpha=1;
+        self.addressTextField.userInteractionEnabled = NO;
+        self.addressTextField.alpha=0.4;
+    }
+}
+
+- (void)closeConnection {
+    if (self.connection) {
+        [self.connection cancel];
+        self.connection = nil;
+    }
+}
+
+- (void)saveLastUrlString:(NSString *)string {
+    NSString *url = string;
+    if (url) {
+        [[NSUserDefaults standardUserDefaults] setObject:url forKey:@"lasturl"];
+        [[NSUserDefaults standardUserDefaults] synchronize];
+    }
+}
+
+- (NSString *)lastUrlString {
+    NSString * url = [[NSUserDefaults standardUserDefaults] objectForKey:@"lasturl"];
+    return url;
+}
+
+#pragma mark - NSURLConnectionDataDelegate
+- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
+    [self.cert setLength:0];
+    if ([response isMemberOfClass:[NSHTTPURLResponse class]]) {
+        self.resp = (NSHTTPURLResponse *)response;
+    }
+}
+
+- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
+    [self.cert appendData:data];
+}
+
+- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
+    ANError(@"Download cert failed with error %@", error);
+    
+    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
+    
+    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@""
+                                                                  message:NSLocalizedString(@"Can't connect to the server", nil)];
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
+    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
+    if (self.resp && self.resp.statusCode != 200) {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@""
+                                                                      message:NSLocalizedString(@"File not found. Please make sure the url is right.", nil)];
+        [self presentViewController:dialog animated:YES completion:nil];
+        
+        self.resp = nil;
+        
+        return;
+    }
+    
+    [self installCertificate];
+}
+
+- (void)installCertificate {
+    __weak typeof(self) weakSelf = self;
+    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
+                                                           style:UIAlertActionStyleCancel
+                                                         handler:^(UIAlertAction * _Nonnull action) {
+                                                             weakSelf.passCheck = nil;
+                                                             weakSelf.nameCheck = nil;
+                                                         }];
+    UIAlertAction *OKAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
+                                                       style:UIAlertActionStyleDefault
+                                                     handler:^(UIAlertAction * _Nonnull action) {
+                                                         UITextField *field = [weakSelf.passCheck.textFields objectAtIndex:0];
+                                                         if ([self alertView:weakSelf.passCheck check:field.text]) {
+                                                             [self alertView:weakSelf.passCheck dismissOnSuccess:YES];
+                                                             return;
+                                                         } else {
+                                                             NSString *message = NSLocalizedString(@"Password wrong", nil);
+                                                             weakSelf.passCheck.title = message;
+                                                             
+                                                             [weakSelf presentViewController:weakSelf.passCheck animated:YES completion:nil];
+                                                         }
+                                                     }];
+    self.passCheck = [self alertInputView:NSLocalizedString(@"Password", nil)
+                                    style:UIAlertViewStyleSecureTextInput
+                                  actions:@[cancelAction, OKAction]];
+    
+    NSString *fullpath;
+    NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
+    fmt.dateFormat = @"yyyy-MM-dd_HH_mm_ss";
+    fullpath = [fmt stringFromDate:[NSDate date]];
+    
+    fullpath = [[[CertificateManager sharedInstance] certsDirectory] stringByAppendingPathComponent:fullpath];
+    fullpath = [fullpath stringByAppendingPathExtension:@"p12"];
+    
+    [self.cert writeToFile:fullpath atomically:YES];
+    self.currentAddCertPath = fullpath;
+    
+    [self presentViewController:self.passCheck animated:YES completion:nil];
+}
+
+- (void)alertView:(UIAlertController *)alert dismissOnSuccess:(BOOL)success {
+    // Success is equal to NO means user cancel
+    if (success) {
+        if(alert == self.passCheck) {
+            //show the check name alert
+            __weak typeof(self) weakSelf = self;
+            UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
+                                                                   style:UIAlertActionStyleCancel
+                                                                 handler:nil];
+            UIAlertAction *OKAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
+                                                               style:UIAlertActionStyleDefault
+                                                             handler:^(UIAlertAction * _Nonnull action) {
+                                                                 UITextField *field = [weakSelf.nameCheck.textFields objectAtIndex:0];
+                                                                 if ([self alertView:weakSelf.nameCheck check:field.text]) {
+                                                                     [self alertView:weakSelf.nameCheck dismissOnSuccess:YES];
+                                                                     return;
+                                                                 } else {
+                                                                     NSString *message = nil;
+                                                                     NSString *name = weakSelf.nameCheck.textFields[0].text;
+                                                                     if (name.length == 0) {
+                                                                         message = NSLocalizedString(@"Name can not be empty", nil);
+                                                                     } else {
+                                                                         message = NSLocalizedString(@"Name already exists", nil);
+                                                                     }
+                                                                     weakSelf.nameCheck.title = message;
+                                                                     
+                                                                     [weakSelf presentViewController:weakSelf.nameCheck animated:YES completion:nil];
+                                                                 }
+                                                             }];
+            self.nameCheck = [self alertInputView:NSLocalizedString(@"Certificate name",nil)
+                                            style:UIAlertViewStylePlainTextInput
+                                          actions:@[cancelAction, OKAction]];
+            
+            [self presentViewController:self.nameCheck animated:YES completion:nil];
+        } else {
+            //add success
+            [[CertificateManager sharedInstance] save];
+            self.passCheck = nil;
+            self.nameCheck = nil;
+            
+            [self dismissViewControllerAnimated:YES completion:nil];
+        }
+    } else {
+        self.passCheck = nil;
+        self.nameCheck = nil;
+    }
+}
+
+- (BOOL)alertView:(UIAlertController *)alert check:(NSString *)string {
+    static Certificate *currentCert;
+    
+    if (alert == self.passCheck) {
+        currentCert = [[Certificate alloc] initWithP12Path:self.currentAddCertPath pass:string];
+        if (currentCert == nil) {
+            return NO;
+        } else {
+            return YES;
+        }
+    } else if (alert == self.nameCheck) {
+        string = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
+        
+        BOOL isExisted = [[CertificateManager sharedInstance].certificates objectForKey:string] != nil;
+        if (string.length != 0 && !isExisted && currentCert != nil) {
+            [[CertificateManager sharedInstance].certificates setObject:currentCert forKey:string];
+            return YES;
+        }
+        
+    }
+    
+    return NO;
+}
+
+- (UIAlertController *)alertInputView:(NSString *)title style:(UIAlertViewStyle)style actions:(NSArray *)actions {
+    UIAlertController *controller = [UIAlertController alertControllerWithTitle:title
+                                                                        message:nil
+                                                                 preferredStyle:UIAlertControllerStyleAlert];
+    
+    if (style == UIAlertViewStylePlainTextInput) {
+        [controller addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+           textField.placeholder = NSLocalizedString(@"Please input certificate name", nil);
+        }];
+    } else if (style == UIAlertViewStyleSecureTextInput) {
+        [controller addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+            textField.placeholder = NSLocalizedString(@"Please input certificate password", nil);
+            textField.secureTextEntry = YES;
+        }];
+    }
+    
+    for (UIAlertAction *action in actions) {
+        [controller addAction:action];
+    }
+    
+    return controller;
+}
+
+// trust https site
+- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
+    [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
+}
+
+- (NSArray *)cellsForTableView:(UITableView *)tableView
+{
+    NSInteger sections = tableView.numberOfSections;
+    NSMutableArray *cells = [[NSMutableArray alloc]  init];
+    for (int section = 0; section < sections; section++) {
+        NSInteger rows =  [tableView numberOfRowsInSection:section];
+        for (int row = 0; row < rows; row++) {
+            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
+            [cells addObject:[tableView cellForRowAtIndexPath:indexPath]];
+        }
+    }
+    return cells;
+}
+
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return 1;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return 1;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    SelectCell *cell = [self.localCertTableView dequeueReusableCellWithIdentifier:kSelectCellID];
+    if (!cell) {
+        cell = [[SelectCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kSelectCellID];
+    }
+    NSString *desc = NSLocalizedString(@"Select Local Certificate", nil);
+    if ([self.localCertNameList count] > 1) {
+        self.certNameSelected = [self.localCertNameList objectAtIndex:0];
+        [cell configureCellWithMessage:desc Info:[self.localCertNameList objectAtIndex:0]];
+    } else {
+        [cell configureCellWithMessage:desc Info:nil];
+    }
+    
+    
+    return cell;
+}
+
+#pragma mark - UITableViewDelegate
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    [self getLocalCertMsg];
+    [self.localCertTableView deselectRowAtIndexPath:indexPath animated:YES];
+    if ([self.localCertNameList count] <= 0) {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+                                                                      message:NSLocalizedString(@"There is no certificate. Please import a new one.", nil)];
+        [self presentViewController:dialog animated:YES completion:nil];
+        
+        return;
+    }
+    
+    NSArray *cells = [self cellsForTableView:self.localCertTableView];
+    if ([cells count] == 1) {
+        SelectCell *cell = (SelectCell *)[cells objectAtIndex:0];
+        
+        [ActionSheetStringPicker showPickerWithTitle:nil
+                                                rows:self.localCertNameList
+                                    initialSelection:0
+                                           doneBlock:^(ActionSheetStringPicker *picker, NSInteger selectedIndex, id selectedValue) {
+                                               cell.infoText.text = selectedValue;
+                                               cell.descText.text = nil;
+                                               self.certNameSelected = selectedValue;
+                                           }
+                                         cancelBlock:^(ActionSheetStringPicker *picker) {
+                                             
+                                         }
+                                              origin:cell];
+    }
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    return 0;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
+    return 44;
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificatesViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificatesViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificatesViewController.h	(working copy)
@@ -0,0 +1,22 @@
+//
+//  CertificatesViewController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/23.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@protocol CertificateChangeDelegate <NSObject>
+
+- (void)certificateDidSelectedWithName:(NSString *)name;
+
+@end
+
+@interface CertificatesViewController : UITableViewController
+
+@property (nonatomic, copy) NSString *selectedCertName;
+@property (nonatomic, weak) id<CertificateChangeDelegate> delegate;
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificatesViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificatesViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CertificatesViewController.m	(working copy)
@@ -0,0 +1,175 @@
+//
+//  CertificatesViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/23.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "ANLogger.h"
+#import "ANPopupDialog.h"
+#import "CertificateNameCell.h"
+#import "CertificateManager.h"
+#import "CertificatesViewController.h"
+
+typedef NS_ENUM(NSInteger, CertificateRowIndex) {
+    kCertificateRowIndexName,
+    kCertificateRowIndexSubject,
+    kCertificateRowIndexIssuer,
+    kCertificateRowIndexExpires
+};
+
+static NSInteger const kTotalRowsInSection = 4;
+
+static NSInteger const kLabelTag = 1;
+
+static NSString * const kNameCellID = @"CertificateNameID";
+static NSString * const kSubjectCellID = @"CertificateSubjectID";
+static NSString * const kIssuerCellID = @"CertificateIssuerID";
+static NSString * const kExpiresCellID = @"CertificateExpireID";
+
+@interface CertificatesViewController () <CertificateCellDelegate>
+
+@property (nonatomic, strong) NSArray *certNames;
+
+@end
+
+@implementation CertificatesViewController
+
+@synthesize certNames = _certNames;
+
+- (void)dealloc {
+    self.certNames = nil;
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [self.tableView reloadData];
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (NSArray *)certNames {
+    NSArray *allKeys = [[CertificateManager sharedInstance].certificates allKeys];
+    
+    _certNames = [allKeys sortedArrayUsingComparator:^(NSString * str1, NSString * str2) {
+        return [str1 compare:str2];
+    }];
+    
+    return _certNames;
+}
+
+#pragma mark - Table view data source
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return self.certNames.count;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return kTotalRowsInSection;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    NSInteger section = indexPath.section;
+    NSInteger row = indexPath.row;
+    UITableViewCell *cell = nil;
+    NSString *certName = [self.certNames objectAtIndex:section];
+    Certificate *cert = [[CertificateManager sharedInstance] certificateWithName:certName];
+    
+    switch (row) {
+        case kCertificateRowIndexName: {
+            cell = [self.tableView dequeueReusableCellWithIdentifier:kNameCellID];
+            CertificateNameCell *nameCell = (CertificateNameCell *)cell;
+            nameCell.nameLabel.text = certName;
+            nameCell.delegate = self;
+            if ([self.selectedCertName isEqualToString:certName]) {
+                [nameCell setAsSelected];
+            } else {
+                [nameCell setAsUnselected];
+            }
+            break;
+        }
+        case kCertificateRowIndexSubject: {
+            cell = [self.tableView dequeueReusableCellWithIdentifier:kSubjectCellID];
+            UILabel *label = [cell viewWithTag:kLabelTag];
+            label.text = cert.subjectCN;
+            break;
+        }
+        case kCertificateRowIndexIssuer: {
+            cell = [self.tableView dequeueReusableCellWithIdentifier:kIssuerCellID];
+            UILabel *label = [cell viewWithTag:kLabelTag];
+            label.text = cert.issuer;
+            break;
+        }
+        case kCertificateRowIndexExpires: {
+            cell = [self.tableView dequeueReusableCellWithIdentifier:kExpiresCellID];
+            UILabel *label = [cell viewWithTag:kLabelTag];
+            label.text = cert.expireTime;
+            break;
+        }
+            
+        default:
+            ANError(@"Invalid row index of (%zi) received, can't alloc valid cell.", row);
+            
+            cell = [[UITableViewCell alloc] init];  // Prevent from crash.
+            break;
+    }
+    
+    return cell;
+}
+
+#pragma mark - UITableViewDelegate
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    return 15.0;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+#pragma mark - CertificateCellDelegate
+- (void)selectedButtonDidClickedWithCell:(UITableViewCell *)cell isSelected:(BOOL)isSelected {
+    if (isSelected) {
+        for (UITableViewCell *aCell in self.tableView.visibleCells) {
+            if ([aCell isKindOfClass:[CertificateNameCell class]] && aCell != cell) {
+                CertificateNameCell *nameCell = (CertificateNameCell *)aCell;
+                [nameCell setAsUnselected];
+            }
+        }
+        
+        self.selectedCertName = ((CertificateNameCell *)cell).nameLabel.text;
+    } else {
+        self.selectedCertName = @"";
+    }
+    
+    [self.delegate certificateDidSelectedWithName:self.selectedCertName];
+}
+
+- (void)deleteButtonDidClickedWithCell:(UITableViewCell *)cell {
+    CertificateNameCell *nameCell = (CertificateNameCell *)cell;
+    
+    NSIndexPath *indexPath = [self.tableView indexPathForCell:nameCell];
+    if (!indexPath) {
+        ANError(@"Certificate cell named '%@' has not been found.", nameCell.nameLabel.text);
+        return;
+    }
+    
+    if ([nameCell.nameLabel.text isEqualToString:self.selectedCertName]) {
+        self.selectedCertName = @"";
+        [self.delegate certificateDidSelectedWithName:self.selectedCertName];
+    }
+    
+    [[CertificateManager sharedInstance] removeCertForName:nameCell.nameLabel.text];
+    
+    NSMutableIndexSet *indexSet = [[NSMutableIndexSet alloc] init];
+    [indexSet addIndex:indexPath.section];
+    [self.tableView deleteSections:indexSet withRowAnimation:UITableViewRowAnimationFade];
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ChallengeViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ChallengeViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ChallengeViewController.h	(working copy)
@@ -0,0 +1,13 @@
+//
+//  ChallengeViewController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/28.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface ChallengeViewController : UIViewController
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ChallengeViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ChallengeViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ChallengeViewController.m	(working copy)
@@ -0,0 +1,163 @@
+//
+//  ChallengeViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/28.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "AAAManager.h"
+#import "UIViewController+Activity.h"
+#import "UIViewController+HideKeyboard.h"
+#import "ChallengeViewController.h"
+
+#define TOTAL_SECTIONS      1
+#define TOTAL_ROWS          1
+
+static NSString * const kPasswordCellID = @"ChallengePasswordCell";
+static NSInteger const kTextFieldCellTag = 1;
+static NSInteger kPasswordCellSection = 0;
+static NSInteger kPasswordCellRow = 0;
+
+@interface ChallengeViewController () <UITableViewDataSource, UITableViewDelegate>
+
+@property (weak, nonatomic) IBOutlet UIButton *loginButton;
+@property (weak, nonatomic) IBOutlet UITableView *tableView;
+
+@end
+
+@implementation ChallengeViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    [self enableHideKeyboard];
+    [self initButtonAppearance];
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (void)initButtonAppearance {
+    self.loginButton.layer.cornerRadius = 2.5;
+    self.loginButton.layer.shadowOffset = CGSizeMake(5.0, 5.0);
+    self.loginButton.layer.shadowColor = MAIN_COLOR.CGColor;
+    self.loginButton.layer.shadowOpacity = 0.25;
+}
+
+- (void)login {
+    AAAManager *manager = [AAAManager sharedInstance];
+    VPNAccount *account = manager.account;
+    account.dynamicCode = [self getPasswordTextField].text;
+    
+    [manager continueVPNThreadWithAccount:account];
+    
+    [self showLoginActivity:YES];
+}
+
+- (UITextField *)getPasswordTextField {
+    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:kPasswordCellRow inSection:kPasswordCellSection];
+    UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
+    
+    return (UITextField *)[cell viewWithTag:kTextFieldCellTag];
+}
+
+- (IBAction)loginButtonClicked:(id)sender {
+    [self login];
+}
+
+- (IBAction)cancelButtonClicked:(id)sender {
+    [self showLoginActivity:NO];
+    
+    [[AAAManager sharedInstance] cancelLoginTapped];
+    
+    if (self.navigationController.viewControllers.count > 1) {
+        [self.navigationController popViewControllerAnimated:YES];
+    }else{
+        [self dismissViewControllerAnimated:YES completion:nil];
+    }
+}
+
++ (NSString *)parseInformation {
+    static NSDictionary *_msgs;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        _msgs = @{
+                  @"\\n   Enter your new PIN, conta": @"Enter your new PIN, containing 4 to 8 chars.",
+                  @"\\n                 Please re-e": @"Please re-enter new PIN:",
+                  @"\\nPINs do not match. Please tr": @"PINs do not match. Please try again.",
+                  @"\\n\\nPIN rejected. Please try a": @"PIN rejected. Please try again.",
+                  @"\\n\\nWait for the code on your ": @"Wait for the code on your card to change, then log in with the new PIN. Enter PASSCODE:",
+                  @"\\nAccess Denied\\n\\n\\nEnter PAS": @"Access Denied. Enter PASSCODE:",
+                  };
+    });
+    
+    vpn_challenge_info_t *info = [AAAManager sharedInstance].challenge_info;
+    if (!info) {
+        return nil;
+    }
+    
+    NSString *information = [NSString stringWithUTF8String:info->info];
+    NSLog(@"information: %@", information);
+    
+    if (!information || information.length <= 0) return nil;
+    
+    if (information.length < 30) return information;
+    
+    NSString *token = [information substringToIndex:30];
+    NSString *finalString = _msgs[token];
+    
+    if (!finalString) return information;
+    
+    return finalString;
+}
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return TOTAL_SECTIONS;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return TOTAL_ROWS;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell *cell = nil;
+    NSInteger section = indexPath.section;
+    NSInteger row = indexPath.row;
+    if (section == kPasswordCellSection && row == kPasswordCellRow) {
+        cell = [self.tableView dequeueReusableCellWithIdentifier:kPasswordCellID];
+    } else {
+        cell = [[UITableViewCell alloc] init];
+    }
+    
+    return cell;
+}
+
+#pragma mark - UITableViewDelegate
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    return 30.0;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+- (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
+    UITableViewHeaderFooterView *headerView = [[UITableViewHeaderFooterView alloc] init];
+    return headerView;
+}
+
+- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section {
+    if (section != 0) return;
+    
+    if ([view isKindOfClass:[UITableViewHeaderFooterView class]]) {
+        UITableViewHeaderFooterView *tableViewHeaderFooterView = (UITableViewHeaderFooterView *) view;
+        tableViewHeaderFooterView.textLabel.text = [[self class] parseInformation];
+    }
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ChangePasswordViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ChangePasswordViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ChangePasswordViewController.h	(working copy)
@@ -0,0 +1,13 @@
+//
+//  ChangePasswordViewController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/16.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface ChangePasswordViewController : UITableViewController
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ChangePasswordViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ChangePasswordViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ChangePasswordViewController.m	(working copy)
@@ -0,0 +1,112 @@
+//
+//  ChangePasswordViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/16.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "AAAManager.h"
+#import "ANPopupDialog.h"
+#import "UIViewController+HideKeyboard.h"
+#import "ChangePasswordViewController.h"
+
+#define TOTAL_SECTIONS  1
+#define TOTAL_ROWS      2
+
+typedef NS_ENUM(NSInteger, ChangePasswordCellIndex) {
+    kChangePasswordCellIndexMethod,
+    kChangePasswordCellIndexNewPassword,
+    kChangePasswordCellIndexConfirmPassword
+};
+
+@interface ChangePasswordViewController ()
+
+@property (weak, nonatomic) IBOutlet UITextField *passwordTextField;
+@property (weak, nonatomic) IBOutlet UITextField *confirmPasswordTextField;
+
+@end
+
+@implementation ChangePasswordViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    
+    [self enableHideKeyboard];
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (IBAction)changeButtonClicked:(id)sender {
+    if ([self.passwordTextField.text isEqualToString:@""] || [self.confirmPasswordTextField.text isEqualToString:@""]) {
+        NSString *message = NSLocalizedString(@"Please input password!", nil);
+        [self promptMessage:message];
+        return;
+    } else if (![self.passwordTextField.text isEqualToString:self.confirmPasswordTextField.text]) {
+        NSString *message = NSLocalizedString(@"Please check your password!", nil);
+        [self promptMessage:message];
+        return;
+    } else if ([self.confirmPasswordTextField.text length] > 32) {
+        NSString *message = NSLocalizedString(@"Password length should be less than 32 characters!", nil);
+        [self promptMessage:message];
+        return;
+    }
+    
+    
+    AAAManager *manager = [AAAManager sharedInstance];
+    VPNAccount *account = manager.account;
+    account.passWord = self.passwordTextField.text;
+    
+    [manager continueVPNThreadWithAccount:account];
+    
+    [self.navigationController popViewControllerAnimated:YES];
+}
+
+- (IBAction)cancelLogin:(id)sender {
+    [[AAAManager sharedInstance] cancelLogin];
+    
+    [self.navigationController popViewControllerAnimated:YES];
+}
+
+- (void)promptMessage:(NSString *)message {
+    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@"" message:message];
+    
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+#pragma mark - Table view data source
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return TOTAL_SECTIONS;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return TOTAL_ROWS;
+}
+
+#pragma mark - UITableViewDelegate
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    return 15.0;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+#pragma mark - UITextFieldDelegate
+- (BOOL)textFieldShouldReturn:(UITextField *)textField {
+    if (textField == self.passwordTextField) {
+        [self.passwordTextField resignFirstResponder];
+        [self.confirmPasswordTextField becomeFirstResponder];
+    } else if (textField == self.confirmPasswordTextField) {
+        [self.confirmPasswordTextField resignFirstResponder];
+    }
+    
+    return YES;
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/ClientVerificationBase.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/ClientVerificationBase.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/ClientVerificationBase.h	(working copy)
@@ -0,0 +1,19 @@
+//
+//  ClientVerificationBase.h
+//  MobileNow
+//
+//  Created by Bryan Yuan on 12/13/12.
+//  Copyright (c) 2012 MobileNow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "ANLogger.h"
+
+@interface ClientVerificationBase : NSObject
+
+@property (nonatomic, retain) NSMutableArray *objectsMutableArray;
+@property (nonatomic, retain) ClientVerificationBase *currentObject;
+- (void)pushCurrentObject;
+- (BOOL)takeAction;
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/ClientVerificationBase.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/ClientVerificationBase.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/ClientVerificationBase.m	(working copy)
@@ -0,0 +1,49 @@
+//
+//  ClientVerificationBase.m
+//  MobileNow
+//
+//  Created by Bryan Yuan on 12/13/12.
+//  Copyright (c) 2012 MobileNow. All rights reserved.
+//
+
+#import "ANLogger.h"
+#import "ClientVerificationBase.h"
+
+@implementation ClientVerificationBase
+
+@synthesize currentObject = _currentObject;
+@synthesize objectsMutableArray = _objectsMutableArray;
+
+- (NSMutableArray *)objectsMutableArray {
+    if (_objectsMutableArray == nil) {
+        _objectsMutableArray = [[NSMutableArray alloc] initWithCapacity:0];
+    }
+    
+    return _objectsMutableArray;
+}
+
+- (void)pushObject:(id)aObject {
+    if (aObject == nil) {
+        return;
+    }
+    
+    [self.objectsMutableArray addObject:aObject];
+}
+
+- (void)pushCurrentObject {
+    [self pushObject:self.currentObject];
+}
+
+- (BOOL)takeAction {
+    ANDebug(@"%@ %@", self, NSStringFromSelector(_cmd));
+    
+    __block BOOL ret;
+    [self.objectsMutableArray enumerateObjectsUsingBlock:^(ClientVerificationBase *obj, NSUInteger idx, BOOL *stop) {
+        *stop = ![obj takeAction];
+        ret = !(*stop);
+    }];
+    
+    return ret;
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/Condition.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/Condition.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/Condition.h	(working copy)
@@ -0,0 +1,17 @@
+//
+//  Condition.h
+//  MobileNow
+//
+//  Created by Bryan Yuan on 12/12/12.
+//  Copyright (c) 2012 MobileNow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "ClientVerificationBase.h"
+#import "ConditionEval.h"
+
+@interface Condition : ClientVerificationBase
+
+@property (nonatomic, retain) ConditionEval *eval;
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/Condition.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/Condition.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/Condition.m	(working copy)
@@ -0,0 +1,46 @@
+//
+//  Condition.m
+//  MobileNow
+//
+//  Created by Bryan Yuan on 12/12/12.
+//  Copyright (c) 2012 MobileNow. All rights reserved.
+//
+
+#import "Condition.h"
+#import "ConditionCase.h"
+
+@implementation Condition
+
+- (BOOL)takeAction {
+    ANDebug(@"%@: %@", self, NSStringFromSelector(_cmd));
+    
+    ConditionCase *conditionCase = [self conditionCaseMatchEval];
+    [conditionCase takeAction];
+    
+    return YES;
+}
+
+- (ConditionCase *)conditionCaseMatchEval {
+    // find the ConditionCase that its value equals Condition.eval, otherwise find the default one
+    int idx = 0, idxDefault = -1;
+    BOOL isMacthed;
+    for (ConditionCase *conditionCase in self.objectsMutableArray) {
+        if ([self.eval isMatchValue:conditionCase.caseValue]) {
+            isMacthed = YES;
+            return conditionCase;
+        } else {
+            if ([conditionCase isDefaultCase]) {
+                idxDefault = idx;
+            }
+        }
+        idx++;
+    }
+    
+    if (idxDefault != -1) {
+        return [self.objectsMutableArray objectAtIndex:idxDefault];
+    } else {
+        return nil;
+    }
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/ConditionCase.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/ConditionCase.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/ConditionCase.h	(working copy)
@@ -0,0 +1,19 @@
+//
+//  ConditionCase.h
+//  MobileNow
+//
+//  Created by Bryan Yuan on 12/13/12.
+//  Copyright (c) 2012 MobileNow. All rights reserved.
+//
+
+#import "ClientVerificationBase.h"
+
+@interface ConditionCase : ClientVerificationBase
+
+@property (nonatomic, retain) NSDictionary *attrDict;
+@property (nonatomic, readonly) NSString *caseValue;
+@property (nonatomic, readonly) BOOL isDefaultCase;
+
+-(id) initWithDict:(NSDictionary *)dict;
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/ConditionCase.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/ConditionCase.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/ConditionCase.m	(working copy)
@@ -0,0 +1,42 @@
+//
+//  ConditionCase.m
+//  MobileNow
+//
+//  Created by Bryan Yuan on 12/13/12.
+//  Copyright (c) 2012 MobileNow. All rights reserved.
+//
+
+#import "ConditionCase.h"
+#import "RuleAction.h"
+
+@implementation ConditionCase
+
+#define RULE_COND_CASE_ATTR_VALUE       @"Value"
+#define RULE_COND_CASE_ATTR_DEFAULT     @"Default"
+
+@synthesize attrDict = _attrDict;
+
+- (NSString *)caseValue {
+    return [self.attrDict objectForKey:RULE_COND_CASE_ATTR_VALUE];
+}
+
+- (BOOL)isDefaultCase {
+    NSString *defaultValue = [self.attrDict objectForKey:RULE_COND_CASE_ATTR_DEFAULT];
+    return [[defaultValue lowercaseString] isEqualToString:@"true"];
+}
+
+- (BOOL)takeAction {
+    ANInfo(@"foreach RuleAction, take action");
+    
+    return [super takeAction];
+}
+
+- (id)initWithDict:(NSDictionary *)dict {
+    self = [super init];
+    if (self) {
+        self.attrDict = dict;
+    }
+    
+    return self;
+}
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/ConditionEval.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/ConditionEval.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/ConditionEval.h	(working copy)
@@ -0,0 +1,60 @@
+//
+//  ConditionEval.h
+//  MobileNow
+//
+//  Created by Bryan Yuan on 12/21/12.
+//  Copyright (c) 2012 MobileNow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@interface ConditionEval : NSObject
+
+@property (nonatomic, retain) NSString *paramContent;
+@property (nonatomic, retain) NSString *insideValue;
+
+- (BOOL)isMatchValue:(NSString *)value;
+
+@end
+
+@interface ConditionEvalOSType : ConditionEval
+@end
+
+@interface ConditionEvalParam : ConditionEval
+@end
+
+@interface ConditionEvalOSVersion : ConditionEval
+@end
+
+@interface ConditionEvalTimeOfDay : ConditionEval
+@end
+
+@interface ConditionEvalMemberOf : ConditionEval
+@end
+
+@interface ConditionEvalNetworkType : ConditionEval
+@end
+
+@interface ConditionEvalWifiSSID : ConditionEval
+@end
+
+@interface ConditionEvalDeviceIDState : ConditionEval
+@end
+
+@interface ConditionEvalPasscodeOn : ConditionEval
+@end
+
+@interface ConditionEvalAppInstalled : ConditionEval
+@end
+
+@interface ConditionEvalManufacturer : ConditionEval
+@end
+
+@interface ConditionEvalNonSignedApps : ConditionEval
+@end
+
+@interface ConditionEvalIOSType : ConditionEval
+@end
+
+@interface ConditionEvalJailbroken : ConditionEval
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/ConditionEval.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/ConditionEval.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/ConditionEval.m	(working copy)
@@ -0,0 +1,159 @@
+//
+//  ConditionEval.m
+//  MobileNow
+//
+//  Created by Bryan Yuan on 12/21/12.
+//  Copyright (c) 2012 MobileNow. All rights reserved.
+//
+
+#import "ConditionEval.h"
+#import "Reachability.h"
+#import <UIKit/UIKit.h>
+#import <SystemConfiguration/CaptiveNetwork.h>
+
+@implementation ConditionEval
+
+@synthesize paramContent = _paramContent;
+@synthesize insideValue = _insideValue;
+
+- (BOOL)isMatchValue:(NSString *)value {
+    if ([[value lowercaseString] isEqualToString:self.insideValue]) {
+        return YES;
+    }
+    
+    return NO;
+}
+
+@end
+
+@implementation ConditionEvalOSType
+
+- (NSString *)insideValue {
+    return @"ios";
+}
+
+@end
+
+@implementation ConditionEvalParam
+
+- (NSString *)insideValue {
+    return self.paramContent;
+}
+
+@end
+
+@implementation ConditionEvalOSVersion
+
+-(NSString *)insideValue {
+    NSString *iOSVersion = [[UIDevice currentDevice] systemVersion];
+    return iOSVersion;
+}
+
+@end
+
+@implementation ConditionEvalTimeOfDay
+@end
+
+@implementation ConditionEvalMemberOf
+@end
+
+@implementation ConditionEvalNetworkType
+
+- (NSString *)insideValue {
+    NetworkStatus reachabilityWiFiStatus = [[Reachability reachabilityForLocalWiFi] currentReachabilityStatus];
+    if (reachabilityWiFiStatus == ReachableViaWiFi) {
+        return @"wifi";
+    } else {
+        NetworkStatus reachabilityCellStatus = [[Reachability reachabilityForInternetConnection] currentReachabilityStatus];
+        if (reachabilityCellStatus == ReachableViaWWAN) {
+            return @"cell";
+        }
+    }
+    
+    return @"unknow";
+}
+
+- (BOOL)isMatchValue:(NSString *)value {
+    if ([[value lowercaseString] isEqualToString:self.insideValue]) {
+        return YES;
+    }
+    
+    return NO;
+}
+
+@end
+
+@implementation ConditionEvalWifiSSID
+
+- (NSString *)insideValue {
+    CFArrayRef myArray1 = CNCopySupportedInterfaces();
+    CFDictionaryRef myDict = CNCopyCurrentNetworkInfo(CFArrayGetValueAtIndex(myArray1, 0));
+    NSDictionary *SSIDDict = (__bridge NSDictionary *)myDict;
+    NSString *ssid = (NSString *)[SSIDDict objectForKey:@"SSID"];
+    return ssid;
+}
+
+@end
+
+@implementation ConditionEvalDeviceIDState
+@end
+
+@implementation ConditionEvalPasscodeOn
+@end
+
+@implementation ConditionEvalAppInstalled
+
+- (NSString *)insideValue {
+    BOOL canOpenApp = [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@://", self.paramContent]]];
+    if (canOpenApp) {
+        return @"true";
+    } else {
+        return @"false";
+    }
+
+    return @"false";
+}
+
+@end
+
+@implementation ConditionEvalManufacturer
+
+- (NSString *)insideValue {
+    return @"apple";
+}
+
+@end
+
+@implementation ConditionEvalNonSignedApps
+@end
+
+@implementation ConditionEvalIOSType
+
+- (NSString *)insideValue {
+    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
+        return @"ipad";
+    } else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
+        return @"iphone";
+    } else
+        return @"unknow";
+}
+
+@end
+
+@implementation ConditionEvalJailbroken
+
+- (BOOL)isDeviceJailbroken {
+    return [[NSFileManager defaultManager] fileExistsAtPath: @"/bin/bash"];
+}
+
+- (NSString *)insideValue {
+    if ([self isDeviceJailbroken]) {
+        return @"true";
+    } else
+        return @"false";
+}
+
+@end
+
+
+
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/Rule.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/Rule.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/Rule.h	(working copy)
@@ -0,0 +1,32 @@
+//
+//  Rule.h
+//  MobileNow
+//
+//  Created by Bryan Yuan on 12/10/12.
+//  Copyright (c) 2012 MobileNow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "RuleTrigger.h"
+#import "Condition.h"
+#import "ClientVerificationBase.h"
+
+enum {
+    RULE_TRIGGER_NUMBER_NONE = -1,
+    RULE_TRIGGER_NUMBER_PRELOGIN,
+    RULE_TRIGGER_NUMBER_POSTLOGIN,
+    RULE_TRIGGER_NUMBER_TIMMER
+};
+
+@interface Rule : ClientVerificationBase
+
+@property (nonatomic, retain) RuleTrigger *trigger;
+@property (nonatomic, retain) NSString *name;
+
+- (BOOL)isTimerRule;
+- (BOOL)isPreRule;
+- (BOOL)isPostRule;
+
+- (BOOL)stopTimer;
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/Rule.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/Rule.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/Rule.m	(working copy)
@@ -0,0 +1,98 @@
+//
+//  Rule.m
+//  MobileNow
+//
+//  Created by Bryan Yuan on 12/10/12.
+//  Copyright (c) 2012 MobileNow. All rights reserved.
+//
+
+#import "ANLogger.h"
+#import "Rule.h"
+#import "RulesManager.h"
+
+@interface Rule ()
+
+@property (nonatomic, retain) NSTimer *ruleTimer;
+
+@end
+
+@implementation Rule
+
+@synthesize trigger = _trigger;
+@synthesize name = _name;
+
+- (BOOL)isTimerRule {
+    if ([self.trigger isMemberOfClass:[RuleTriggerTimer class]]) {
+        return YES;
+    }
+    
+    return NO;
+}
+
+- (BOOL)isPreRule {
+    if ([self.trigger isMemberOfClass:[RuleTriggerPreLogin class]]) {
+        return YES;
+    }
+    
+    return NO;
+}
+
+- (BOOL)isPostRule {
+    if ([self.trigger isMemberOfClass:[RuleTriggerPostLogin class]]) {
+        return YES;
+    }
+    
+    return NO;
+}
+
+- (BOOL)takeAction {
+    ANDebug(@"%@ %@", self, NSStringFromSelector(_cmd));
+    ANDebug(@"%@", self.objectsMutableArray);
+
+    if ([self isTimerRule]) {
+        RuleTriggerTimer *trigTimer = (RuleTriggerTimer *)self.trigger;
+        NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:[trigTimer startTime]];
+        NSTimeInterval timeInterval = [trigTimer timeInterval];
+        
+        ANDebug(@"%@ %f", fireDate, timeInterval);
+        
+        self.ruleTimer = [[NSTimer alloc] initWithFireDate:fireDate
+                                                  interval:timeInterval
+                                                    target:self
+                                                  selector:@selector(handleTimerRule)
+                                                  userInfo:nil repeats:YES];
+        
+        [[NSRunLoop mainRunLoop] addTimer:self.ruleTimer forMode:NSDefaultRunLoopMode];
+        
+        ANInfo(@"Clientverification timer start");
+        
+        return YES;
+    } else {
+        ANInfo(@"Clientverification start");
+        return [super takeAction];
+    }
+}
+
+- (void)handleTimerRule {
+    ANDebug(@"%@", NSStringFromSelector(_cmd));
+    
+    [[RulesManager sharedInstance] cleanTimerRuleInteraction];
+    
+    [self.objectsMutableArray enumerateObjectsUsingBlock:^(Condition *obj, NSUInteger idx, BOOL *stop) {
+        *stop = ![obj takeAction];
+    }];
+    
+    usleep(50000);
+    
+    [[RulesManager sharedInstance] didTrigTimer];
+}
+
+- (BOOL)stopTimer {
+    if (self.ruleTimer != nil) {
+        [self.ruleTimer invalidate];
+    }
+    
+    return YES;
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RuleAction.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RuleAction.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RuleAction.h	(working copy)
@@ -0,0 +1,64 @@
+//
+//  RuleAction.h
+//  MobileNow
+//
+//  Created by Bryan Yuan on 12/13/12.
+//  Copyright (c) 2012 MobileNow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+#import "ClientVerificationBase.h"
+
+@protocol RuleActionUserInteractionProtocol <NSObject>
+
+#define KEYPATH_RAUIP_IS_READY      @"isReady"
+
+@property (nonatomic, assign) BOOL isReady;
+@property (nonatomic, strong) UIAlertView *alert;
+
+-(BOOL) performAction;
+
+@end
+
+@interface RuleAction : ClientVerificationBase
+
+@property (nonatomic, retain) NSString *message;
+@property (nonatomic, retain) NSDictionary *attrDict;
+
+@property (nonatomic, assign) BOOL isTimerRuleAction;
+
+- (id)initWithDict:(NSDictionary *)dict;
+- (id)initWithDict:(NSDictionary *)dict isTimerType:(BOOL)isTimerType;
+- (id)initWithTimerType:(BOOL)isTimerType;
+
+@end
+
+@interface RuleActionLog : RuleAction
+@end
+
+@interface RuleActionTermsess : RuleAction
+@end
+
+@interface RuleActionAlertUser : RuleAction <RuleActionUserInteractionProtocol>
+@end
+
+@interface RuleActionPromptUser : RuleAction <RuleActionUserInteractionProtocol>
+@end
+
+@interface RuleActionUserInput : RuleAction <RuleActionUserInteractionProtocol>
+@end
+
+@interface RuleActionSetParam : RuleAction
+@end
+
+@interface RuleActionEndRule : RuleAction
+@end
+
+@interface RuleActionTriggerRule : RuleAction
+@end
+
+@interface RuleActionAssignGroup : RuleAction
+@end
+
+
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RuleAction.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RuleAction.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RuleAction.m	(working copy)
@@ -0,0 +1,315 @@
+//
+//  RuleAction.m
+//  MobileNow
+//
+//  Created by Bryan Yuan on 12/13/12.
+//  Copyright (c) 2012 MobileNow. All rights reserved.
+//
+
+#import "arrayapi.h"
+#import "ANLogger.h"
+#import "RuleAction.h"
+#import "RulesManager.h"
+
+#define ANLOG_DEBUG     0
+#define ANLOG_INFO      1
+#define ANLOG_WARNING   2
+#define ANLOG_ERROR     3
+
+#define ARRAYVPN_AUDIT_LOG_ID_CV2_LOGACTION              1001
+#define ARRAYVPN_AUDIT_LOG_ID_CV2_PROMPTUSERACTION       1002
+
+@implementation RuleAction
+
+@synthesize message = _message;
+@synthesize attrDict = _attrDict;
+@synthesize isTimerRuleAction = _isTimerRuleAction;
+
+- (id)initWithDict:(NSDictionary *)dict {
+    self = [super init];
+    if (self) {
+        self.attrDict = dict;
+        self.isTimerRuleAction = NO;
+    }
+    
+    return self;
+}
+
+- (id)initWithDict:(NSDictionary *)dict isTimerType:(BOOL)isTimerType {
+    self = [super init];
+    if (self) {
+        self.attrDict = dict;
+        self.isTimerRuleAction = isTimerType;
+    }
+    
+    return self;
+}
+
+- (id)initWithTimerType:(BOOL)isTimerType {
+    self = [super init];
+    if (self) {
+        self.isTimerRuleAction = isTimerType;
+    }
+    
+    return self;
+}
+@end
+
+@implementation RuleActionLog
+
+#define RULE_ACTION_LOG_ATTR_PRIORITY   @"Priority"
+#define RULE_ACTION_LOG_LEVEL_WARNING   @"Warning"
+#define RULE_ACTION_LOG_LEVEL_ERROR     @"Critical"
+
+- (BOOL)takeAction {
+    // send log with priority
+    ANDebug(@"%@: %@", self, NSStringFromSelector(_cmd));
+    
+    NSString *logString = [NSString stringWithFormat:@"Client Verification: %@", self.message];
+    NSString *priority = [self.attrDict objectForKey:RULE_ACTION_LOG_ATTR_PRIORITY];
+    
+    int level = AUDIT_INFO;
+    int mpLevel = ANLOG_INFO;
+    
+    if (NSOrderedSame == [priority compare:RULE_ACTION_LOG_LEVEL_WARNING] ) {
+        level = AUDIT_WARNING;
+        mpLevel = ANLOG_WARNING;
+    } else if (NSOrderedSame == [priority compare:RULE_ACTION_LOG_LEVEL_ERROR]) {
+        level = AUDIT_CRIT;
+        mpLevel = ANLOG_ERROR;
+    }
+    
+    array_vpn_audit_log(level, ARRAYVPN_AUDIT_LOG_ID_CV2_LOGACTION, (char *)[logString UTF8String]);
+    
+    switch (mpLevel) {
+        case ANLOG_DEBUG:
+            ANDebug(@"%@", logString);
+            break;
+        case ANLOG_INFO:
+            ANInfo(@"%@", logString);
+            break;
+        case ANLOG_WARNING:
+            ANWarn(@"%@", logString);
+            break;
+        case ANLOG_ERROR:
+            ANError(@"%@", logString);
+            break;
+            
+        default:
+            break;
+    }
+    
+    return YES;
+}
+
+@end
+
+@implementation RuleActionTermsess
+
+- (BOOL)takeAction {
+    ANDebug(@"%@: %@", self, NSStringFromSelector(_cmd));
+    
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{
+        [[RulesManager sharedInstance] runIntoEndSessionRule:self.isTimerRuleAction];
+    });
+    
+    ANInfo(@"clientverification end session");
+    
+    return YES;
+}
+
+@end
+
+@implementation RuleActionAlertUser
+
+@synthesize alert = _alert;
+@synthesize isReady;
+
+- (BOOL)takeAction {
+    ANDebug(@"%@: %@", self, NSStringFromSelector(_cmd));
+    
+    [[RulesManager sharedInstance] addRuleActionIntoUserInteractionArray:self];
+    
+    ANInfo(@"clientverification alert users");
+    
+    return YES;
+}
+
+- (BOOL)performAction {
+    __weak typeof(self) weakSelf = self;
+    dispatch_sync(dispatch_get_main_queue(), ^{
+        weakSelf.alert = [[UIAlertView alloc] initWithTitle:@"" message:self.message delegate:nil cancelButtonTitle:NSLocalizedString(@"OK",nil) otherButtonTitles:nil, nil];
+        weakSelf.alert.delegate = self;
+        [weakSelf.alert show];
+    });
+    
+    return YES;
+}
+
+#pragma mark - UIAlertView Delegate
+- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
+    ANInfo(@"isReady: %@", NSStringFromSelector(_cmd));
+    self.isReady = YES;
+}
+
+- (void)dealloc {
+    _alert.delegate = nil;
+}
+
+@end
+
+@interface RuleActionPromptUser () <UIAlertViewDelegate>
+#define RULE_ACTION_PROMPTUSER_ATTR_OPT_1       @"Option1"
+#define RULE_ACTION_PROMPTUSER_ATTR_OPT_2       @"Option2"
+#define RULE_ACTION_PROMPTUSER_ATTR_LOGTXT      @"LogTxt"
+#define RULE_ACTION_PROMPTUSER_ATTR_PARAM       @"Param"
+@end
+
+@implementation RuleActionPromptUser
+
+@synthesize isReady;
+@synthesize alert = _alert;
+
+- (BOOL)takeAction {
+    ANDebug(@"%@: %@", self, NSStringFromSelector(_cmd));
+    
+    [[RulesManager sharedInstance] addRuleActionIntoUserInteractionArray:self];
+    ANInfo(@"clientverification prompt user action");
+    
+    return YES;
+}
+
+- (BOOL)performAction {
+    NSString *titleOfButton1 = [self.attrDict objectForKey:RULE_ACTION_PROMPTUSER_ATTR_OPT_1];
+    NSString *titleOfButton2 = [self.attrDict objectForKey:RULE_ACTION_PROMPTUSER_ATTR_OPT_2];
+    
+    __weak typeof(self) weakSelf = self;
+    dispatch_sync(dispatch_get_main_queue(), ^{
+        weakSelf.alert = [[UIAlertView alloc] initWithTitle:@"" message:self.message delegate:self cancelButtonTitle:titleOfButton1 otherButtonTitles:titleOfButton2, nil];
+        [weakSelf.alert show];
+    });
+    
+    return YES;
+}
+
+- (void)dealloc {
+    _alert.delegate = nil;
+}
+
+#pragma mark - UIAlertView Delegate
+- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
+    ANDebug(@"isReady: %@", NSStringFromSelector(_cmd));
+    
+    NSString *titleOfButton1 = [self.attrDict objectForKey:RULE_ACTION_PROMPTUSER_ATTR_OPT_1];
+    NSString *titleOfButton2 = [self.attrDict objectForKey:RULE_ACTION_PROMPTUSER_ATTR_OPT_2];
+    NSString *logTxt = [self.attrDict objectForKey:RULE_ACTION_PROMPTUSER_ATTR_LOGTXT];
+    NSString *selectedTitle;
+    if (buttonIndex == 0) {
+        selectedTitle = titleOfButton1;
+    } else {
+        selectedTitle = titleOfButton2;
+    }
+    
+    NSString *logString = [NSString stringWithFormat:@"Client Verification: %@ %@", logTxt, selectedTitle];
+    array_vpn_audit_log(AUDIT_INFO, ARRAYVPN_AUDIT_LOG_ID_CV2_PROMPTUSERACTION, (char *)[logString UTF8String]);
+    
+    ANInfo(@"%@ %@", logTxt, selectedTitle);
+    
+    self.isReady = YES;
+}
+
+@end
+
+@interface RuleActionUserInput () <UIAlertViewDelegate>
+@end
+
+@implementation RuleActionUserInput
+
+@synthesize isReady;
+@synthesize alert = _alert;
+
+- (BOOL)takeAction {
+    ANDebug(@"%@: %@", self, NSStringFromSelector(_cmd));
+    
+    [[RulesManager sharedInstance] addRuleActionIntoUserInteractionArray:self];
+    
+    ANInfo(@"Client verification user input action");
+    
+    return YES;
+}
+
+- (BOOL)performAction {
+    __weak typeof(self) weakSelf = self;
+    dispatch_async(dispatch_get_main_queue(), ^{
+        weakSelf.alert = [[UIAlertView alloc] initWithTitle:self.message message:nil delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil];
+        weakSelf.alert.alertViewStyle = UIAlertViewStylePlainTextInput;
+        weakSelf.alert.delegate = self;
+        [weakSelf.alert show];
+    });
+    
+    return YES;
+}
+
+- (void)dealloc {
+    _alert.delegate = nil;
+}
+
+#pragma mark - UIAlertView Delegate
+- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
+    ANDebug(@"isReady: %@", NSStringFromSelector(_cmd));
+    self.isReady = YES;
+}
+
+@end
+
+@implementation RuleActionSetParam
+
+- (BOOL)takeAction {
+    // set param
+    ANDebug(@"%@: %@", self, NSStringFromSelector(_cmd));
+    return YES;
+}
+
+@end
+
+@implementation RuleActionEndRule
+
+- (BOOL)takeAction {
+    ANDebug(@"%@: %@", self, NSStringFromSelector(_cmd));
+    
+    ANInfo(@"Client verification end rule");
+    
+    return NO;
+}
+
+@end
+
+@implementation RuleActionTriggerRule
+
+- (BOOL)takeAction {
+    ANDebug(@"%@: %@", self, NSStringFromSelector(_cmd));
+    
+    if (self.message != nil) {
+        dispatch_async(dispatch_get_global_queue(0, 0), ^{
+            [[RulesManager sharedInstance] kickoffRuleWithName:self.message];
+        });
+    }
+    
+    ANInfo(@"Client verification trigger another rule %@", self.message);
+    
+    return YES;
+}
+
+@end
+
+@implementation RuleActionAssignGroup
+
+- (BOOL)takeAction {
+    ANDebug(@"%@: %@", self, NSStringFromSelector(_cmd));
+    
+    ANInfo(@"Client verification assign group action");
+    
+    return YES;
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RuleActionInteractionHandler.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RuleActionInteractionHandler.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RuleActionInteractionHandler.h	(working copy)
@@ -0,0 +1,17 @@
+//
+//  RuleActionInteractionHandler.h
+//  MobileNow
+//
+//  Created by Bryan Yuan on 1/16/13.
+//  Copyright (c) 2013 MobileNow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "RuleAction.h"
+
+@interface RuleActionInteractionHandler : NSObject
+
+- (void)pushRuleAction:(RuleAction *) ruleAction;
+- (void)takeAction;
+- (void)cleanContext;
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RuleActionInteractionHandler.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RuleActionInteractionHandler.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RuleActionInteractionHandler.m	(working copy)
@@ -0,0 +1,101 @@
+//
+//  RuleActionInteractionHandler.m
+//  MobileNow
+//
+//  Created by Bryan Yuan on 1/16/13.
+//  Copyright (c) 2013 MobileNow. All rights reserved.
+//
+
+#import "RuleActionInteractionHandler.h"
+
+@interface RuleActionInteractionHandler ()
+
+@property (nonatomic, strong) NSMutableArray *rulesMutableArray;
+@property (nonatomic, assign) NSInteger currentRuleIndex;
+
+@end
+
+@implementation RuleActionInteractionHandler
+
+@synthesize rulesMutableArray = _rulesMutableArray;
+
+- (NSMutableArray *)rulesMutableArray {
+    @synchronized(self) {
+        if (_rulesMutableArray == nil) {
+            _rulesMutableArray = [[NSMutableArray alloc] initWithCapacity:0];
+        }
+        
+        return _rulesMutableArray;
+    }
+}
+
+- (void)pushRuleAction:(RuleAction *) ruleAction {
+    [self.rulesMutableArray addObject:ruleAction];
+}
+
+- (void)takeAction {
+    if (self.currentRuleIndex >= self.rulesMutableArray.count) {
+        ANError(@"NULL UI ruleAction");
+        return;
+    }
+    
+    RuleAction *ruleAction = (RuleAction *)[self.rulesMutableArray objectAtIndex:self.currentRuleIndex];
+    if (ruleAction == nil) {
+        ANError(@"no UI ruleAction");
+        return;
+    }
+    
+    ANDebug(@"perform No.%zi ruleAction", self.currentRuleIndex);
+    
+    [ruleAction addObserver:self forKeyPath:KEYPATH_RAUIP_IS_READY options:NSKeyValueObservingOptionNew context:NULL];
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{
+        if ([ruleAction respondsToSelector:@selector(performAction)]) {
+            [ruleAction performSelector:@selector(performAction)];
+        }
+    });
+}
+
+- (void)cleanContext {
+    @synchronized(self) {
+        self.currentRuleIndex = 0;
+        
+        int i = 0;
+        RuleAction *ruleAction;
+        
+        @try {
+            for (i = 0; i<[self.rulesMutableArray count]; i++) {
+                ruleAction = [self.rulesMutableArray objectAtIndex:i];
+                [ruleAction removeObserver:self forKeyPath:KEYPATH_RAUIP_IS_READY];
+                ruleAction = nil;
+            }
+        }
+        @catch (NSException *exception) {
+            
+        }
+        @finally {
+            
+        }
+        [self.rulesMutableArray removeAllObjects];
+    }
+}
+
+#pragma mark - KVO Delegate
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
+    if ([keyPath isEqualToString:KEYPATH_RAUIP_IS_READY]) {
+        self.currentRuleIndex++;
+        ANDebug(@"currentRuleIndex++: %zi", self.currentRuleIndex);
+        [self takeAction];
+        @try {
+            [object removeObserver:self forKeyPath:KEYPATH_RAUIP_IS_READY];
+        }
+        @catch (NSException *exception) {
+            
+        }
+        @finally {
+            
+        }
+    }
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RuleTrigger.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RuleTrigger.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RuleTrigger.h	(working copy)
@@ -0,0 +1,27 @@
+//
+//  RuleTrigger.h
+//  MobileNow
+//
+//  Created by Bryan Yuan on 12/22/12.
+//  Copyright (c) 2012 MobileNow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@interface RuleTrigger : NSObject
+
+@end
+
+@interface RuleTriggerPreLogin : RuleTrigger
+@end
+
+@interface RuleTriggerPostLogin : RuleTrigger
+@end
+
+@interface RuleTriggerTimer : RuleTrigger
+
+-(id)initWithDict:(NSDictionary *)dict;
+-(NSInteger) startTime;
+-(NSInteger) timeInterval;
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RuleTrigger.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RuleTrigger.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RuleTrigger.m	(working copy)
@@ -0,0 +1,61 @@
+//
+//  RuleTrigger.m
+//  MobileNow
+//
+//  Created by Bryan Yuan on 12/22/12.
+//  Copyright (c) 2012 MobileNow. All rights reserved.
+//
+
+#import "RuleTrigger.h"
+
+@implementation RuleTrigger
+
+@end
+
+@implementation RuleTriggerPreLogin
+@end
+
+@implementation RuleTriggerPostLogin
+@end
+
+@interface RuleTriggerTimer ()
+
+#define RULE_TRIGGER_TIMER_ATTR_STARTTIME       @"Starttime"
+#define RULE_TRIGGER_TIMER_ATTR_INTERVAL        @"Interval"
+
+@property (nonatomic, copy) NSDictionary *attrDict;
+
+@end
+
+@implementation RuleTriggerTimer
+
+- (id)initWithDict:(NSDictionary *)dict {
+    self = [super init];
+    if (self) {
+        self.attrDict = dict;
+    }
+    
+    return self;
+}
+
+- (NSInteger)startTime {
+    NSString *startTimeString = [self.attrDict objectForKey:RULE_TRIGGER_TIMER_ATTR_STARTTIME];
+    NSInteger startTimeInt = [startTimeString integerValue];
+    if (startTimeInt >= 0) {
+        return startTimeInt;
+    }
+    
+    return NSIntegerMax;
+}
+
+- (NSInteger)timeInterval {
+    NSString *timeIntervalString = [self.attrDict objectForKey:RULE_TRIGGER_TIMER_ATTR_INTERVAL];
+    NSInteger timeIntervalInt = [timeIntervalString integerValue];
+    if (timeIntervalInt > 0) {
+        return timeIntervalInt;
+    }
+    
+    return NSIntegerMax;
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RulesManager.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RulesManager.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RulesManager.h	(working copy)
@@ -0,0 +1,55 @@
+//
+//  RulesManager.h
+//  MobileNow
+//
+//  Created by Bryan Yuan on 12/10/12.
+//  Copyright (c) 2012 MobileNow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "RuleAction.h"
+#import "RuleActionInteractionHandler.h"
+
+#define KEYPATH_RM_IS_PARSE_DONE        @"isParseDone"
+
+typedef enum  {
+    RULE_TYPE_UNKNOW,
+    RULE_TYPE_PRE,
+    RULE_TYPE_POST
+} RULE_TYPE;
+
+@protocol TimerRuleDelegate <NSObject>
+
+- (void)shouldSignOut;
+
+@end
+
+@interface RulesManager : NSObject
+
+@property (nonatomic, assign) RULE_TYPE currentRuleType;
+@property (nonatomic, assign) BOOL isParseDone;
+@property (nonatomic, assign) BOOL didEndSession;
+
+@property (nonatomic, retain) RuleActionInteractionHandler *interactionHandler;
+@property (nonatomic, retain) RuleActionInteractionHandler *timerInteractionHandler;
+
+@property (nonatomic, weak) id<TimerRuleDelegate> delegate;
+
++ (RulesManager *)sharedInstance;
+
+- (void)parsePreRulesXML:(NSString *)rulesXMLString;
+- (void)parsePostRulesXML:(NSString *)rulesXMLString;
+
+- (void)kickoffTimerRules;
+- (void)stopTimerRules;
+- (void)didTrigTimer;
+
+- (void)kickoffSpecificRule:(NSString *)ruleName;
+
+- (void)kickoffRuleWithName:(NSString *)ruleName;
+- (void)runIntoEndSessionRule:(BOOL)isTimerRule;
+- (void)addRuleActionIntoUserInteractionArray:(RuleAction *)ruleAction;
+- (void)cleanTimerRuleInteraction;
+- (void)stopAllRules;
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RulesManager.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RulesManager.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ClientVerification/RulesManager.m	(working copy)
@@ -0,0 +1,594 @@
+//
+//  RulesManager.m
+//  MobileNow
+//
+//  Created by Bryan Yuan on 12/10/12.
+//  Copyright (c) 2012 MobileNow. All rights reserved.
+//
+
+#import "Rule.h"
+#import "RuleAction.h"
+#import "RulesManager.h"
+#import "ConditionCase.h"
+#import "ConditionEval.h"
+
+#define RULES                           @"Rules"
+#define RULES_RULE                      @"Rule"
+#define RULE_ATTR_NAME                  @"Name"
+
+#define RULE_TRIGGERS                   @"Triggers"
+#define RULE_TRIGGER_PRELOGIN           @"prelogin"
+#define RULE_TRIGGER_POSTLOGIN          @"postlogin"
+#define RULE_TRIGGER_TIMER              @"timer"
+
+#define RULE_BODY                       @"Body"
+
+#define RULE_CONDITION                  @"Condition"
+#define RULE_COND_EVAL                  @"Eval"
+#define RULE_COND_EVAL_OSTYPE           @"ostype"
+#define RULE_COND_EVAL_OSVER            @"osver"
+#define RULE_COND_EVAL_TIMEOFDAY        @"timeofday"
+#define RULE_COND_EVAL_MEMBEROF         @"memberof"
+#define RULE_COND_EVAL_NETWORKTYPE      @"networktype"
+#define RULE_COND_EVAL_WIFISSID         @"wifissid"
+#define RULE_COND_EVAL_PARAM            @"param"
+#define RULE_COND_EVAL_DEVIDSTATE       @"devidstate"
+#define RULE_COND_EVAL_PASSCODEON       @"passcodeon"
+#define RULE_COND_EVAL_APPINSTALLED     @"appinstalled"
+#define RULE_COND_EVAL_MANUFACTURER     @"manufacturer"
+#define RULE_COND_EVAL_NONSIGNEDAPPS    @"nonsignedapps"
+#define RULE_COND_EVAL_WINSC            @"winsc"
+#define RULE_COND_EVAL_WINSERVICEPACK   @"winservicepack"
+#define RULE_COND_EVAL_IOSTYPE          @"iostype"
+#define RULE_COND_EVAL_JAILBROKEN       @"jailbroken"
+
+#define RULE_COND_CASE                  @"Case"
+
+#define RULE_ACTION_LOG                 @"log"
+#define RULE_ACTION_TERMSESS            @"termsess"
+#define RULE_ACTION_ALERTUSER           @"alertuser"
+#define RULE_ACTION_PROMPTUSER          @"promptuser"
+#define RULE_ACTION_USERINPUT           @"userinput"
+#define RULE_ACTION_SETPARAM            @"setparam"
+#define RULE_ACTION_ENDRULE             @"endrule"
+#define RULE_ACTION_TRIGGERRULE         @"triggerrule"
+#define RULE_ACTION_ASSIGNGROUP         @"assigngroup"
+#define RULE_ACTION_WINSCLOG            @"winsclog"
+
+@interface RulesManager () <NSXMLParserDelegate>
+
+@property (nonatomic, retain) NSMutableArray *rulesMutableArray;
+@property (nonatomic, retain) NSMutableArray *preRulesArray;
+@property (nonatomic, retain) NSMutableArray *postRulesArray;
+@property (nonatomic, retain) NSMutableArray *timerRulesArray;
+/* some rules might don't have a trigger, they go here */
+@property (nonatomic, retain) NSMutableArray *otherRulesArray;
+
+
+@property (nonatomic, retain) Rule *currentRule;
+
+@property (nonatomic, assign) BOOL isTimerRule;
+
+@property (nonatomic, assign) BOOL accumulatingParsedCharacterData;
+@property (nonatomic, retain) NSMutableString *currentParsedCharacterData;
+
+@end
+
+@implementation RulesManager 
+
+@synthesize isParseDone = _isParseDone;
+
+@synthesize rulesMutableArray = _rulesMutableArray;
+@synthesize preRulesArray = _preRulesArray;
+@synthesize postRulesArray = _postRulesArray;
+@synthesize timerRulesArray = _timerRulesArray;
+@synthesize otherRulesArray = _otherRulesArray;
+@synthesize currentRule = _currentRule;
+
+@synthesize isTimerRule = _isTimerRule;
+
+@synthesize accumulatingParsedCharacterData = _accumulatingParsedCharacterData;
+@synthesize currentParsedCharacterData = _currentParsedCharacterData;
+
++ (RulesManager *)sharedInstance {
+    static RulesManager * instance;
+    @synchronized([RulesManager class]) {
+        if(instance == nil){
+            instance = [[RulesManager alloc] init];
+        }
+    }
+    
+    return instance;
+}
+
+- (void)kickoffRuleWithName:(NSString *)ruleName {
+    [self kickoffSpecificRule:ruleName];
+}
+
+- (void)runIntoEndSessionRule:(BOOL)isTimerRule {
+    if (isTimerRule) {
+        [self runIntoEndSessionRuleInTimer];
+    } else {
+        self.didEndSession = YES;
+    }
+}
+
+- (void)runIntoEndSessionRuleInTimer {
+    __weak typeof(self) weakSelf = self;
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{
+        [weakSelf notifyTermsess];
+    });
+}
+
+- (void)cleanTimerRuleInteraction {
+    [self.timerInteractionHandler cleanContext];
+}
+
+- (void)stopAllRules {
+    [self.interactionHandler cleanContext];
+    [self.timerInteractionHandler cleanContext];
+    [self stopTimerRules];
+}
+
+- (void)addRuleActionIntoUserInteractionArray:(RuleAction *)ruleAction {
+    if (ruleAction.isTimerRuleAction) {
+        [self.timerInteractionHandler pushRuleAction:ruleAction];
+    } else {
+        [self.interactionHandler pushRuleAction:ruleAction];
+    }
+}
+
+- (void)didTrigTimer {
+    [self.timerInteractionHandler takeAction];
+}
+
+- (void)notifyTermsess {
+    __weak typeof(self) weakSelf = self;
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [weakSelf.delegate shouldSignOut];
+    });
+}
+
+- (void)setIsParseDone:(BOOL)isParseDone {
+    if (isParseDone && !_isParseDone) {
+        [self takeAction];
+    }
+    
+    _isParseDone = isParseDone;
+}
+
+- (RuleActionInteractionHandler *)interactionHandler {
+    if (_interactionHandler == nil) {
+        _interactionHandler = [[RuleActionInteractionHandler alloc] init];
+    }
+    
+    return _interactionHandler;
+}
+
+- (RuleActionInteractionHandler *)timerInteractionHandler {
+    if (_timerInteractionHandler == nil) {
+        _timerInteractionHandler = [[RuleActionInteractionHandler alloc] init];
+    }
+    
+    return _timerInteractionHandler;
+}
+
+- (NSMutableString *) currentParsedCharacterData {
+    if (_currentParsedCharacterData == nil) {
+        _currentParsedCharacterData = [[NSMutableString alloc] initWithCapacity:0];
+    }
+    
+    return _currentParsedCharacterData;
+}
+
+- (NSMutableArray *)rulesMutableArray {
+    if (_rulesMutableArray == nil) {
+        _rulesMutableArray = [[NSMutableArray alloc] initWithCapacity:0];
+    }
+    
+    return _rulesMutableArray;
+}
+
+- (NSMutableArray *)timerRulesArray {
+    if (_timerRulesArray == nil) {
+        _timerRulesArray = [[NSMutableArray alloc] initWithCapacity:0];
+    }
+    
+    return _timerRulesArray;
+}
+
+- (NSMutableArray *)preRulesArray {
+    if (_preRulesArray == nil) {
+        _preRulesArray = [[NSMutableArray alloc] initWithCapacity:0];
+    }
+    
+    return _preRulesArray;
+}
+
+- (NSMutableArray *)postRulesArray {
+    if (_postRulesArray == nil) {
+        _postRulesArray = [[NSMutableArray alloc] initWithCapacity:0];
+    }
+    
+    return _postRulesArray;
+}
+
+- (NSMutableArray *)otherRulesArray {
+    if (_otherRulesArray == nil) {
+        _otherRulesArray = [[NSMutableArray alloc] initWithCapacity:0];
+    }
+    
+    return _otherRulesArray;
+}
+
+- (void)addRule:(Rule *)rule {
+    /* look for the duplicated rule */
+    for (Rule *r in self.rulesMutableArray) {
+        if ([r.name isEqualToString:rule.name]) {
+            return;
+        }
+    }
+    
+    [self.rulesMutableArray addObject:self.currentRule];
+}
+
+- (void)classifyRulesArray:(NSArray *)rulesArray {
+    for (Rule *rule in rulesArray) {
+        if ([rule isTimerRule]) {
+            [self.timerRulesArray addObject:rule];
+        } else if ([rule isPreRule]) {
+            [self.preRulesArray addObject:rule];
+        } else if ([rule isPostRule]) {
+            [self.postRulesArray addObject:rule];
+        } else {
+            [self.otherRulesArray addObject:rule];
+        }
+    }
+}
+
+- (BOOL)takeAction {
+    void (^takeActionBlock)(Rule *obj, NSUInteger idx, BOOL *stop) = ^(Rule *obj, NSUInteger idx, BOOL *stop) {
+        *stop = ![obj takeAction];
+    };
+    
+    [self classifyRulesArray:self.rulesMutableArray];
+    
+    ANDebug(@"rulesMutableArray: %@", self.rulesMutableArray);
+    
+    self.rulesMutableArray = nil;
+    
+    if (self.currentRuleType == RULE_TYPE_PRE) {
+        [self.preRulesArray enumerateObjectsUsingBlock:takeActionBlock];
+    } else if (self.currentRuleType == RULE_TYPE_POST) {
+        [self.postRulesArray enumerateObjectsUsingBlock:takeActionBlock];
+    }
+    
+    return YES;
+}
+
+- (void)kickoffTimerRules {
+    [self.timerRulesArray enumerateObjectsUsingBlock:^(Rule *obj, NSUInteger idx, BOOL *stop) {
+        *stop = ![obj takeAction];
+    }];
+}
+
+- (void)stopTimerRules {
+    [self.timerRulesArray enumerateObjectsUsingBlock:^(Rule *obj, NSUInteger idx, BOOL *stop) {
+        *stop = ![obj stopTimer];
+    }];
+}
+
+- (void)kickoffPreRules {
+    [self takeAction];
+}
+
+- (void)kickoffPostRules {
+    [self takeAction];
+}
+
+- (void)kickoffSpecificRule:(NSString *)ruleName {
+    void (^takeActionBlock)(Rule *obj, NSUInteger idx, BOOL *stop) = ^(Rule *obj, NSUInteger idx, BOOL *stop) {
+        if ([obj.name isEqualToString:ruleName]) {
+            [obj takeAction];
+            *stop = YES;
+        }
+    };
+    
+    if (self.currentRuleType == RULE_TYPE_PRE) {
+        // execute rule with name <ruleName>
+        [self.preRulesArray enumerateObjectsUsingBlock:takeActionBlock];
+    } else if (self.currentRuleType == RULE_TYPE_POST) {
+        [self.postRulesArray enumerateObjectsUsingBlock:takeActionBlock];
+    }
+    
+    [self.otherRulesArray enumerateObjectsUsingBlock:takeActionBlock];
+}
+
+- (void)cleanRules {
+    [self.rulesMutableArray removeAllObjects];
+    [self.preRulesArray removeAllObjects];
+    [self.postRulesArray removeAllObjects];
+    [self.otherRulesArray removeAllObjects];
+    [self.timerRulesArray removeAllObjects];
+}
+
+- (void)parseRulesXML:(NSString *)rulesXMLString {
+    self.isParseDone = NO;
+    
+    NSXMLParser *parser = [[NSXMLParser alloc] initWithData:[rulesXMLString dataUsingEncoding:NSUTF8StringEncoding]];
+    [parser setDelegate:self];
+    [parser parse];
+}
+
+- (void)parsePreRulesXML:(NSString *)rulesXMLString {
+    [self.interactionHandler cleanContext];
+    [self cleanRules];
+    
+    self.currentRuleType = RULE_TYPE_PRE;
+    [self parseRulesXML:rulesXMLString];
+}
+
+- (void)parsePostRulesXML:(NSString *)rulesXMLString {
+    [self.interactionHandler cleanContext];
+    [self.timerInteractionHandler cleanContext];
+    [self cleanRules];
+    
+    self.currentRuleType = RULE_TYPE_POST;
+    [self parseRulesXML:rulesXMLString];
+}
+
+#pragma - ClientVerification Logic
+
+- (void)initialCurrentCondition:(Condition *)aCondition {
+    if (aCondition == nil) {
+        self.currentRule.currentObject = [[Condition alloc] init];
+    } else {
+        self.currentRule.currentObject = aCondition;
+    }
+}
+
+- (void)pushCurrentCondition {
+    [self.currentRule pushCurrentObject];
+    ANDebug(@"currentRule: %@ : %@", self.currentRule, self.currentRule.objectsMutableArray);
+}
+
+- (Condition *)currentCondition {
+    return (Condition *)self.currentRule.currentObject;
+}
+
+- (void)initialCurrentConditionCase:(ConditionCase *)conditionCase {
+    Condition *currentCondition = [self currentCondition];
+    
+    if (conditionCase == nil) {
+        currentCondition.currentObject = [[ConditionCase alloc] init];
+    } else {
+        currentCondition.currentObject = conditionCase;
+    }
+}
+
+- (void)pushCurrentConditionCase {
+    Condition *currentCondition = [self currentCondition];
+    [currentCondition pushCurrentObject];
+}
+
+- (ConditionCase *)currentConditionCase {
+    return (ConditionCase *)[self currentCondition].currentObject;
+}
+
+- (void)initialCurrentRuleAction:(RuleAction *)ruleAction {
+    ConditionCase *currentConditionCase = [self currentConditionCase];
+    
+    if (ruleAction == nil) {
+        currentConditionCase.currentObject = [[RuleAction alloc] init];
+    } else {
+        currentConditionCase.currentObject = ruleAction;
+    }
+}
+
+- (void)pushCurrentRuleAction {
+    ConditionCase *currentConditionCase = [self currentConditionCase];
+    [currentConditionCase pushCurrentObject];
+}
+
+- (RuleAction *)currentRuleAction {
+    return (RuleAction *)[self currentConditionCase].currentObject;
+}
+
+#pragma mark - XML handler logic
+- (void)enableCollectingXMLData {
+    self.accumulatingParsedCharacterData = YES;
+    self.currentParsedCharacterData = nil;
+}
+
+- (void)disableCollectingXMLData {
+    self.accumulatingParsedCharacterData = NO;
+}
+
+#pragma mark - NSXMLParser delegate methods
+
+- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
+    attributes:(NSDictionary *)attributeDict {
+    if ([elementName isEqualToString:RULES]) {
+        self.rulesMutableArray = nil;
+    } else if ([elementName isEqualToString:RULES_RULE]) {
+        // initial current rule, set it's name attribute
+        self.currentRule = [[Rule alloc] init];
+        
+        self.currentRule.name = [attributeDict objectForKey:RULE_ATTR_NAME];
+    } else if ([elementName isEqualToString:RULE_TRIGGERS]) {
+        self.isTimerRule = NO;
+    } else if ([elementName isEqualToString:RULE_TRIGGER_PRELOGIN]) {
+        self.currentRule.trigger = [[RuleTriggerPreLogin alloc] init];
+    } else if ([elementName isEqualToString:RULE_TRIGGER_POSTLOGIN]) {
+        self.currentRule.trigger = [[RuleTriggerPostLogin alloc] init];
+    } else if ([elementName isEqualToString:RULE_TRIGGER_TIMER]) {
+        self.currentRule.trigger = [[RuleTriggerTimer alloc] initWithDict:attributeDict];
+        self.isTimerRule = YES;
+    } else if ([elementName isEqualToString:RULE_BODY]) {
+        
+    } else if ([elementName isEqualToString:RULE_CONDITION]) {
+        // initial a condition
+        [self initialCurrentCondition:nil];
+    } else if ([elementName isEqualToString:RULE_COND_EVAL]) {
+        
+    } else if ([elementName isEqualToString:RULE_COND_EVAL_OSTYPE]) {
+        // set condition type
+        [self currentCondition].eval = [[ConditionEvalOSType alloc] init];
+    } else if ([elementName isEqualToString:RULE_COND_EVAL_OSVER]) {
+        // set condition type
+        [self currentCondition].eval = [[ConditionEvalOSVersion alloc] init];
+        ANInfo(@"iOSVersion: %@", [[UIDevice currentDevice] systemVersion]);
+    } else if ([elementName isEqualToString:RULE_COND_EVAL_TIMEOFDAY]) {
+        // set condition type
+        [self currentCondition].eval = [[ConditionEvalTimeOfDay alloc] init];
+    } else if ([elementName isEqualToString:RULE_COND_EVAL_MEMBEROF]) {
+        // set condition type
+        [self currentCondition].eval = [[ConditionEvalMemberOf alloc] init];
+        [self enableCollectingXMLData];
+    } else if ([elementName isEqualToString:RULE_COND_EVAL_NETWORKTYPE]) {
+        // set condition type
+        [self currentCondition].eval = [[ConditionEvalNetworkType alloc] init];
+    } else if ([elementName isEqualToString:RULE_COND_EVAL_WIFISSID]) {
+        // set condition type
+        [self currentCondition].eval = [[ConditionEvalWifiSSID alloc] init];
+    } else if ([elementName isEqualToString:RULE_COND_EVAL_PARAM]) {
+        // set condition type
+        [self currentCondition].eval = [[ConditionEvalParam alloc] init];
+        [self enableCollectingXMLData];
+    } else if ([elementName isEqualToString:RULE_COND_EVAL_DEVIDSTATE]) {
+        // set condition type
+        [self currentCondition].eval = [[ConditionEvalDeviceIDState alloc] init];
+    } else if ([elementName isEqualToString:RULE_COND_EVAL_PASSCODEON]) {
+        // set condition type
+        [self currentCondition].eval = [[ConditionEvalPasscodeOn alloc] init];
+    } else if ([elementName isEqualToString:RULE_COND_EVAL_APPINSTALLED]) {
+        // set condition type
+        [self currentCondition].eval = [[ConditionEvalAppInstalled alloc] init];
+        [self enableCollectingXMLData];
+    } else if ([elementName isEqualToString:RULE_COND_EVAL_MANUFACTURER]) {
+        // set condition type
+        [self currentCondition].eval = [[ConditionEvalManufacturer alloc] init];
+    } else if ([elementName isEqualToString:RULE_COND_EVAL_NONSIGNEDAPPS]) {
+        // set condition type
+        [self currentCondition].eval = [[ConditionEvalNonSignedApps alloc] init];
+    } else if ([elementName isEqualToString:RULE_COND_EVAL_IOSTYPE]) {
+        // set condition type
+        [self currentCondition].eval = [[ConditionEvalIOSType alloc] init];
+    } else if ([elementName isEqualToString:RULE_COND_EVAL_JAILBROKEN]) {
+        // set condition type
+        [self currentCondition].eval = [[ConditionEvalJailbroken alloc] init];
+    }
+    
+    else if ([elementName isEqualToString:RULE_COND_CASE]) {
+        // EVAL -- several CASEs, switch to particular CASE according to the Value Attr of Case
+        // initial a CASE
+        ConditionCase *conditionCase = [[ConditionCase alloc] initWithDict:attributeDict];
+        
+        [self initialCurrentConditionCase:conditionCase];
+        
+    } else if ([elementName isEqualToString:RULE_ACTION_LOG]) {
+        // initial current action
+        [self initialCurrentRuleAction:[[RuleActionLog alloc] initWithDict:attributeDict]];
+        [self enableCollectingXMLData];
+    } else if ([elementName isEqualToString:RULE_ACTION_TERMSESS]) {
+        [self initialCurrentRuleAction:[[RuleActionTermsess alloc] initWithTimerType:self.isTimerRule]];
+    } else if ([elementName isEqualToString:RULE_ACTION_ALERTUSER]) {
+        [self initialCurrentRuleAction:[[RuleActionAlertUser alloc] initWithTimerType:self.isTimerRule]];
+        
+        [self enableCollectingXMLData];
+    } else if ([elementName isEqualToString:RULE_ACTION_PROMPTUSER]) {
+        [self initialCurrentRuleAction:[[RuleActionPromptUser alloc] initWithDict:attributeDict isTimerType:self.isTimerRule]];
+        
+        [self enableCollectingXMLData];
+    } else if ([elementName isEqualToString:RULE_ACTION_USERINPUT]) {
+        [self initialCurrentRuleAction:[[RuleActionUserInput alloc] initWithDict:attributeDict isTimerType:self.isTimerRule]];
+        [self enableCollectingXMLData];
+    } else if ([elementName isEqualToString:RULE_ACTION_SETPARAM]) {
+        [self initialCurrentRuleAction:[[RuleActionSetParam alloc] initWithDict:attributeDict]];
+        [self enableCollectingXMLData];
+    } else if ([elementName isEqualToString:RULE_ACTION_ENDRULE]) {
+        [self initialCurrentRuleAction:[[RuleActionEndRule alloc] initWithTimerType:self.isTimerRule]];
+    } else if ([elementName isEqualToString:RULE_ACTION_TRIGGERRULE]) {
+        [self initialCurrentRuleAction:[[RuleActionTriggerRule alloc] init]];
+        [self enableCollectingXMLData];
+    } else if ([elementName isEqualToString:RULE_ACTION_ASSIGNGROUP]) {
+        [self initialCurrentRuleAction:[[RuleActionAssignGroup alloc] init]];
+    }
+    
+}
+
+- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
+    if ([elementName isEqualToString:RULES]) {
+        ANInfo(@"rulesMutableArray: %@", self.rulesMutableArray);
+    } else if ([elementName isEqualToString:RULES_RULE]) {
+        // put current rule into Array
+        [self addRule:self.currentRule];
+    } else if ([elementName isEqualToString:RULE_TRIGGER_TIMER]) {
+        
+    } else if ([elementName isEqualToString:RULE_CONDITION]) {
+        // push current condition
+        [self pushCurrentCondition];
+    } else if ([elementName isEqualToString:RULE_COND_EVAL_MEMBEROF]) {
+        [self disableCollectingXMLData];
+        [self currentCondition].eval.paramContent = self.currentParsedCharacterData;
+    } else if ([elementName isEqualToString:RULE_COND_EVAL_PARAM]) {
+        [self disableCollectingXMLData];
+        [self currentCondition].eval.paramContent = self.currentParsedCharacterData;
+    } else if ([elementName isEqualToString:RULE_COND_EVAL_APPINSTALLED]) {
+        [self disableCollectingXMLData];
+        [self currentCondition].eval.paramContent = self.currentParsedCharacterData;
+    } else if ([elementName isEqualToString:RULE_COND_CASE]) {
+        // push current CASE
+        [self pushCurrentConditionCase];
+    } else if ([elementName isEqualToString:RULE_ACTION_LOG]) {
+        [self disableCollectingXMLData];
+        [self currentRuleAction].message = self.currentParsedCharacterData;
+        [self pushCurrentRuleAction];
+    } else if ([elementName isEqualToString:RULE_ACTION_TERMSESS]) {
+        [self pushCurrentRuleAction];
+    } else if ([elementName isEqualToString:RULE_ACTION_ALERTUSER]) {
+        [self disableCollectingXMLData];
+        [self currentRuleAction].message = self.currentParsedCharacterData;
+        NSLog(@"Rule message: %@", [self currentRuleAction].message);
+        [self pushCurrentRuleAction];
+    } else if ([elementName isEqualToString:RULE_ACTION_PROMPTUSER]) {
+        [self disableCollectingXMLData];
+        [self currentRuleAction].message = self.currentParsedCharacterData;
+        [self pushCurrentRuleAction];
+    } else if ([elementName isEqualToString:RULE_ACTION_USERINPUT]) {
+        [self disableCollectingXMLData];
+        [self currentRuleAction].message = self.currentParsedCharacterData;
+        [self pushCurrentRuleAction];
+    } else if ([elementName isEqualToString:RULE_ACTION_SETPARAM]) {
+        [self disableCollectingXMLData];
+        [self currentRuleAction].message = self.currentParsedCharacterData;
+        [self pushCurrentRuleAction];
+    } else if ([elementName isEqualToString:RULE_ACTION_ENDRULE]) {
+        [self pushCurrentRuleAction];
+    } else if ([elementName isEqualToString:RULE_ACTION_TRIGGERRULE]) {
+        [self disableCollectingXMLData];
+        [self currentRuleAction].message = self.currentParsedCharacterData;
+        [self pushCurrentRuleAction];
+    } else if ([elementName isEqualToString:RULE_ACTION_ASSIGNGROUP]) {
+        [self pushCurrentRuleAction];
+    } 
+}
+
+- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
+    if (self.accumulatingParsedCharacterData) {
+        // If the current element is one whose content we care about, append 'string'
+        // to the property that holds the content of the current element.
+        if (string != nil) {
+            [self.currentParsedCharacterData appendString:string];
+        }
+    }
+}
+
+- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
+}
+
+- (void)parserDidEndDocument:(NSXMLParser *)parser {
+    self.isParseDone = YES;
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CustomDesktopViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CustomDesktopViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CustomDesktopViewController.h	(working copy)
@@ -0,0 +1,13 @@
+//
+//  CustomDesktopViewController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/9.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface CustomDesktopViewController : UIViewController
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CustomDesktopViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CustomDesktopViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/CustomDesktopViewController.m	(working copy)
@@ -0,0 +1,293 @@
+//
+//  CustomDesktopViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/9.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "AppManager.h"
+#import "GCustomItem.h"
+#import "ANPopupDialog.h"
+#import "FBKVOController.h"
+#import "UIViewController+HideKeyboard.h"
+#import "CustomDesktopViewController.h"
+
+#define TOTAL_SECTIONS      1
+#define TOTAL_ROWS          3
+
+typedef NS_ENUM(NSInteger, CustomDesktopCellIndex) {
+    kCustomDesktopCellHostname = 0,
+    kCustomDesktopCellUsername,
+    kCustomDesktopCellDomain,
+};
+
+static NSString * const kHostnameCellID = @"HostnameCellID";
+static NSString * const kUsernameCellID = @"UsernameCellID";
+static NSString * const kDomainCellID = @"DomainCellID";
+
+static NSInteger kTextFieldTag = 1;
+
+@interface CustomDesktopViewController () <UITableViewDataSource, UITableViewDelegate>
+
+@property (weak, nonatomic) IBOutlet UITableView *tableView;
+@property (weak, nonatomic) IBOutlet UIButton *connectButton;
+
+@property (nonatomic, strong) UIControl *darkView;
+@property (nonatomic, strong) FBKVOController *kvoController;
+@property (nonatomic) BOOL silence;
+
+@property (nonatomic, strong) GCustomItem *item;
+@property (nonatomic) BOOL inProcessing;
+
+@end
+
+@implementation CustomDesktopViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    [self initAppearance];
+    [self enableHideKeyboard];
+    
+    self.kvoController = [FBKVOController controllerWithObserver:self];
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [super viewWillDisappear:animated];
+    
+    self.silence = YES;
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    
+    self.silence = NO;
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (IBAction)connectButtonClicked:(id)sender {
+    NSString *host = [self getHostnameTextField].text;
+    NSString *username = [self getUsernameTextField].text;
+    NSString *domain = [self getDomainTextField].text;
+    
+    if (self.inProcessing) return;
+    
+    if (!host || host.length == 0) {
+        [self showErrorMessage:NSLocalizedString(@"The Host/IP cannot be empty!", nil)];
+        return;
+    }
+    
+    NSRange range = [host rangeOfString:@":"];
+    
+    NSString *port = @"3389";
+    if (range.length > 0) {
+        NSString *hostWithOutPort = [host substringToIndex:range.location];
+        port = [host substringFromIndex:range.location+1];
+        host = hostWithOutPort;
+    }
+    
+    [self connectToHost:host withUsername:username domain:domain port:port];
+}
+
+- (void)connectToHost:(NSString *)host withUsername:(NSString *)username domain:(NSString *)domain port:(NSString *)port {
+    self.inProcessing = YES;
+    
+    self.item = [[GCustomItem alloc] init];
+    self.item.server = host;
+    self.item.ssoUsername = username;
+    self.item.domain = domain;
+    self.item.port = port;
+    
+    [self.item completeInit];
+    
+    [self showShadow:YES];
+    
+    [self.kvoController observe:self.item keyPath:@"status" options:NSKeyValueObservingOptionNew block:^(CustomDesktopViewController *observer, GCustomItem *item, NSDictionary *change) {
+        
+        dispatch_async(dispatch_get_main_queue(), ^{
+            if (observer.silence) {
+                return;
+            }
+            
+            if (item.status == ResourceStatusReady) {
+                [observer.kvoController unobserve:host];
+                
+                NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
+                AppManager *appManager = [AppManager sharedInstance];
+                BOOL cliEnabledNEC = NO;
+                NSString *enabledNEC = appManager.desktopSettings.settings[@"jp-rdp"];
+                if (enabledNEC && [enabledNEC isEqualToString:@"1"])
+                    cliEnabledNEC = YES;
+                if (cliEnabledNEC || [userDefaults integerForKey:@"desktop_client_vendor"] == 1) {
+                    [observer openRDClientNEC:item];
+                } else {
+                    [observer openRDClient:item];
+                }
+            } else if (item.status >= ResourceStatusFailed) {
+                [observer.kvoController unobserve:host];
+                [observer showErrorMessage:NSLocalizedString(@"Cannot connect to remote host", nil)];
+            }
+        });
+        
+    }];
+    
+    [self.item prepare];
+}
+
+- (void)openRDClient:(GCustomItem *)item
+{
+    NSURL *url = item.url;
+    if (!url) {
+        return;
+    }
+    
+    [self done];
+    
+    OpenURL(url);
+}
+
+- (void)openRDClientNEC:(GCustomItem *)item {
+    NSURL *url = item.urlVendorNEC;
+    if (!url) {
+        return;
+    }
+    
+    [self done];
+    
+    if (![[UIApplication sharedApplication] canOpenURL:url]) {
+        NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Application %@ has not been installed, Would you like to search it on App Store?", nil), @"RD"];
+        PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Cannot connect to remote host", nil)
+                                                                       message:message
+                                                                 confirmAction:^{
+                                                                     NSString *string = @"https://itunes.apple.com/jp/app/rd-v1.3/id771611106?mt=8";
+                                                                     OpenURL([NSURL URLWithString:string]);
+                                                                 }
+                                                                  cancelAction:nil];
+        
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+- (void)showErrorMessage:(NSString *)message {
+    [self done];
+    
+    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@"" message:message];
+    
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)done {
+    self.inProcessing = NO;
+    [self showShadow:NO];
+}
+
+- (void)showShadow:(BOOL)aBool {
+    CGRect frame;
+    
+    [self.view endEditing:YES];
+    
+    if (!_darkView) {
+        frame = self.view.bounds;
+        _darkView = [[UIControl alloc] initWithFrame:frame];
+        _darkView.backgroundColor = UIColorFromRGBA(0, 0.7);
+        
+        UIActivityIndicatorView *a = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
+        a.center = _darkView.center;
+        [a startAnimating];
+        [_darkView addSubview:a];
+    }
+    
+    if (aBool) {
+        [_darkView removeFromSuperview];
+        [self.view addSubview:_darkView];
+    } else {
+        [_darkView removeFromSuperview];
+    }
+}
+
+- (UITextField *)getHostnameTextField {
+    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:kCustomDesktopCellHostname inSection:0];
+    return [[self.tableView cellForRowAtIndexPath:indexPath] viewWithTag:kTextFieldTag];
+}
+
+- (UITextField *)getUsernameTextField {
+    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:kCustomDesktopCellUsername inSection:0];
+    return [[self.tableView cellForRowAtIndexPath:indexPath] viewWithTag:kTextFieldTag];
+}
+
+- (UITextField *)getDomainTextField {
+    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:kCustomDesktopCellDomain inSection:0];
+    return [[self.tableView cellForRowAtIndexPath:indexPath] viewWithTag:kTextFieldTag];
+}
+
+- (UITextField *)getTextFieldWithCell:(UITableViewCell *)cell {
+    return [cell viewWithTag:kTextFieldTag];
+}
+
+- (void)initAppearance {
+    self.connectButton.layer.cornerRadius = 2.5;
+    self.connectButton.layer.shadowOpacity = 0.25;
+    self.connectButton.layer.shadowColor = MAIN_COLOR.CGColor;
+    self.connectButton.layer.shadowOffset = CGSizeMake(5.0, 5.0);
+}
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return TOTAL_SECTIONS;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return TOTAL_ROWS;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell *cell = nil;
+    NSString *cellID = nil;
+    NSInteger row = indexPath.row;
+    
+    switch (row) {
+        case kCustomDesktopCellHostname:
+            cellID = kHostnameCellID;
+            break;
+        case kCustomDesktopCellUsername:
+            cellID = kUsernameCellID;
+            break;
+        case kCustomDesktopCellDomain:
+            cellID = kDomainCellID;
+            break;
+            
+        default:
+            break;
+    }
+    
+    if (cellID != nil) {
+        cell = [tableView dequeueReusableCellWithIdentifier:cellID];
+        UITextField *textField = [self getTextFieldWithCell:cell];
+        if (textField != nil) {
+            Ivar ivar =  class_getInstanceVariable([UITextField class], "_placeholderLabel");
+            UILabel *placeholderLabel = object_getIvar(textField, ivar);
+            placeholderLabel.textColor = UIColorFromRGBA(0x999999, 1.0);
+        }
+    } else {
+        cell = [[UITableViewCell alloc] init];  // Prevent from crash.
+    }
+    
+    return cell;
+}
+
+#pragma mark - UITableViewDelegate
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    return 15;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewaySettingsViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewaySettingsViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewaySettingsViewController.h	(working copy)
@@ -0,0 +1,23 @@
+//
+//  GatewaySettingsViewController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/14.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "Global.h"
+
+@protocol GatewaySettingDelegate <NSObject>
+
+- (void)didFinishedEdit:(BOOL)isNew;
+
+@end
+
+@interface GatewaySettingsViewController : UITableViewController <ANViewControllerSwitchProtocol>
+
+@property (strong, nonatomic) Gateway *gateway;
+@property (weak, nonatomic) id<GatewaySettingDelegate> delegate;
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewaySettingsViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewaySettingsViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewaySettingsViewController.m	(working copy)
@@ -0,0 +1,344 @@
+//
+//  GatewaySettingsViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/14.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "ANLogger.h"
+#import "ANPopupDialog.h"
+#import "CertificateManager.h"
+#import "GatewayManager.h"
+#import "PasswordManager.h"
+#import "CertificatesViewController.h"
+#import "UIViewController+HideKeyboard.h"
+#import "GatewaySettingsViewController.h"
+
+typedef enum {
+    kSettingsSectionFirst = 0,
+    kSettingsSectionSecond,
+    kSettingsSectionTotal,
+} SettingsSectionIndex;
+
+static NSInteger rowsInFirstSection = 5;
+static NSInteger rowsInSecondSection = 5;
+
+static NSInteger rowCertificate = 4;
+
+static NSString * const kSegueToCertificates = @"GatewaySettingsToCertificates";
+static NSString * const kSegueToInstallCertificate = @"GatewaySettingsToInstallCertificate";
+static NSString * const kStoryboardCertificatesID = @"CertificateViewControllerID";
+
+@interface GatewaySettingsViewController () <UITableViewDataSource, UITableViewDelegate, CertificateChangeDelegate>
+
+@property (weak, nonatomic) IBOutlet UITextField *titleTextField;
+@property (weak, nonatomic) IBOutlet UITextField *gatewayTextField;
+@property (weak, nonatomic) IBOutlet UITextField *usernameTextField;
+@property (weak, nonatomic) IBOutlet UITextField *portTextField;
+@property (weak, nonatomic) IBOutlet UISwitch *enableSecureTunnelSwitch;
+@property (weak, nonatomic) IBOutlet UISwitch *savePasswordSwitch;
+@property (weak, nonatomic) IBOutlet UISwitch *showLoginDialogSwitch;
+@property (weak, nonatomic) IBOutlet UISwitch *enableWebSSOSwitch;
+@property (weak, nonatomic) IBOutlet UISwitch *enableWebAuthSwitch;
+@property (weak, nonatomic) IBOutlet UISwitch *syferlockAuthSwitch;
+@property (weak, nonatomic) IBOutlet UILabel *certNameLabel;
+
+@end
+
+@implementation GatewaySettingsViewController
+
+- (void)dealloc {
+    self.gateway = nil;
+    self.delegate = nil;
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    
+    [self enableHideKeyboard];
+    [self configureFields];
+    
+    [self setFirstResponderIfNeeded];
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (IBAction)cancelButtonClicked:(id)sender {
+    [self dismissViewControllerAnimated:YES completion:nil];
+}
+
+- (IBAction)saveButtonClicked:(id)sender {
+    BOOL ret = [self saveGateway];
+    if (!ret) {
+        return;
+    }
+    
+    BOOL isNewAdded = self.gateway == nil;
+    [self.delegate didFinishedEdit:isNewAdded];
+    
+    [self dismissViewControllerAnimated:YES completion:nil];
+}
+
+- (IBAction)savePasswordSwitched:(id)sender {
+    self.showLoginDialogSwitch.enabled = self.savePasswordSwitch.on;
+}
+
+- (void)setFirstResponderIfNeeded {
+    if (self.titleTextField.text.length == 0) {
+        [self.titleTextField becomeFirstResponder];
+    }
+}
+
+- (void)configureFields {
+    if (!self.gateway) {
+        return;
+    }
+    
+    self.titleTextField.text = self.gateway.title;
+    self.gatewayTextField.text = self.gateway.url;
+    self.usernameTextField.text = self.gateway.username;
+    self.portTextField.text = self.gateway.port;
+    self.enableWebSSOSwitch.on = self.gateway.isWebSSOEnabled;
+    self.syferlockAuthSwitch.on = self.gateway.isSyferLockEnabled;
+    self.savePasswordSwitch.on = self.gateway.isSavePasswordEnabled;
+    self.showLoginDialogSwitch.on = self.gateway.isShowLoginDialogEnabled;
+    self.enableSecureTunnelSwitch.on = self.gateway.isSecureTunnelEnabled;
+    self.enableWebAuthSwitch.on = self.gateway.isWebAuthEnabled;
+    self.certNameLabel.text = self.gateway.certname;
+    
+    self.showLoginDialogSwitch.enabled = self.savePasswordSwitch.on;
+    
+    if (self.titleTextField.text.length > 0){
+      
+        self.titleTextField.userInteractionEnabled = NO;
+        self.titleTextField.alpha = 0.4;
+    }else{
+      
+        self.titleTextField.userInteractionEnabled = YES;
+        self.titleTextField.alpha = 1;
+    }
+}
+
+typedef enum {
+    CHECK_INPUT_OK,
+    CHECK_INPUT_ERROR_TITLE,
+    CHECK_INPUT_ERROR_URL,
+    CHECK_INPUT_ERROR_USERNAME,
+    CHECK_INPUT_ERROR_PORT,
+} CHECK_INPUT_RESULT;
+
+- (CHECK_INPUT_RESULT)checkInput {
+    CHECK_INPUT_RESULT ret = CHECK_INPUT_OK;
+    
+    NSString *title, *message, *ok;
+    
+    title = NSLocalizedString(@"Error", nil);
+    ok = NSLocalizedString(@"OK", nil);
+    
+    NSNumberFormatter *f = [[NSNumberFormatter alloc] init];
+    [f setNumberStyle:NSNumberFormatterDecimalStyle];
+    NSNumber *port = [f numberFromString:self.portTextField.text];
+    
+    if([self.titleTextField.text isEqual:@""]) {
+        message = NSLocalizedString(@"Display name is required", nil);
+        ret = CHECK_INPUT_ERROR_TITLE;
+        [self.titleTextField becomeFirstResponder];
+    } else if([self.gatewayTextField.text isEqual:@""]) {
+        message =  NSLocalizedString(@"URL is required.",nil);
+        ret = CHECK_INPUT_ERROR_URL;
+        [self.gatewayTextField becomeFirstResponder];
+    } else if([self.portTextField.text isEqual:@""]) {
+        message =  NSLocalizedString(@"Port is required.",nil);
+        ret = CHECK_INPUT_ERROR_PORT;
+        [self.portTextField becomeFirstResponder];
+    } else if(port == nil || [port integerValue] <= 0 || [port integerValue] > 65535) {
+        message = NSLocalizedString(@"Port is invalid.",nil);
+        ret = CHECK_INPUT_ERROR_PORT;
+    } else {
+        BOOL result = ([[GatewayManager sharedInstance] indexOfUrl:self.gatewayTextField.text andport:self.portTextField.text] != NSNotFound);//
+        if (result &&
+            (![self.gatewayTextField.text isEqualToString:self.gateway.url] ||
+            ![self.portTextField.text isEqualToString:self.gateway.port])) {  // self.gateway only exists on gateway editing.
+            message = NSLocalizedString(@"The host already exists", nil);
+            ret = CHECK_INPUT_ERROR_URL;
+        } else {
+            return CHECK_INPUT_OK;
+        }
+    }
+    
+    PopupDialog *popup = [ANPopupDialog singleButtonPopupDialogWithTitle:title message:message];
+    [self presentViewController:popup animated:YES completion:nil];
+    
+    return ret;
+}
+
+- (BOOL)saveGateway {
+    [self.view endEditing:YES];  // Dismiss keyboard.
+    
+    CHECK_INPUT_RESULT result = [self checkInput];
+    if (result != CHECK_INPUT_OK) {
+        return NO;
+    }
+    
+    NSString *username = [self.usernameTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
+    Gateway *newGateway = self.gateway != nil ? self.gateway : [[Gateway alloc] init];
+    newGateway.title = self.titleTextField.text;
+    NSString *trimmedUrl = [self.gatewayTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
+    newGateway.url = trimmedUrl;
+    newGateway.host = [trimmedUrl rangeOfString:@"/"].location == NSNotFound ? trimmedUrl : [[trimmedUrl componentsSeparatedByString:@"/"] firstObject];
+    newGateway.alias = [trimmedUrl rangeOfString:@"/"].location == NSNotFound ? @"" : [[trimmedUrl componentsSeparatedByString:@"/"] lastObject];
+    newGateway.port = [self.portTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
+    if ([self isOldUsernameChanged:newGateway.username newUsername:username] &&
+        !newGateway.isFaceOrTouchIDEnabled &&
+        !newGateway.isGestureEnabled) {  // If configured username changed, remove the saved password.
+        [self removePasswordWithHost:newGateway.host username:newGateway.username port:newGateway.port];
+        [self removePasswordWithHost:newGateway.host username:username port:newGateway.port];  // Clear both the old & the new accounts' passwords.
+    }
+    newGateway.username = username;
+    newGateway.isWebSSOEnabled = self.enableWebSSOSwitch.on;
+    newGateway.isSyferLockEnabled = self.syferlockAuthSwitch.on;
+    newGateway.isSavePasswordEnabled = self.savePasswordSwitch.on;
+    newGateway.isShowLoginDialogEnabled = self.showLoginDialogSwitch.on;
+    newGateway.isSecureTunnelEnabled = self.enableSecureTunnelSwitch.on;
+    newGateway.isWebAuthEnabled = self.enableWebAuthSwitch.on;
+    newGateway.certname = self.certNameLabel.text;
+    
+    [self addOrUpdateGateway:newGateway];
+    
+    return YES;
+}
+
+- (BOOL)isOldUsernameChanged:(NSString *)oldUsername newUsername:(NSString *)newUsername {
+    if (!oldUsername || [oldUsername isEqualToString:@""]) {
+        return NO;
+    }
+    
+    return ![oldUsername isEqualToString:newUsername];
+}
+
+- (void)removePasswordWithHost:(NSString *)host username:(NSString *)username port:(NSString *)port {
+    [PasswordManager removePasswordsOfHost:host username:username port:port];
+}
+
+- (void)addOrUpdateGateway:(Gateway *)gateway {
+    GatewayManager *gatewayManager = [GatewayManager sharedInstance];
+    if (_gateway) {
+        NSInteger index = [gatewayManager indexOfUrl:_gateway.url andport:_gateway.port];
+        [gatewayManager updateGateway:gateway atIndex:index];
+    } else {
+        [gatewayManager addGateway:gateway];
+    }
+}
+
+- (void)jumpToCertificate {
+    if ([CertificateManager sharedInstance].certificates.count == 0) {
+        ANDebug(@"No certificate has been found, try to install.");
+        
+        [self certificateDidSelectedWithName:@""];  // Clear cert name if no cert exists.
+        
+        // Push the CertificatesViewController into stack quietly.
+        UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
+        CertificatesViewController *controller = [mainStoryboard instantiateViewControllerWithIdentifier:kStoryboardCertificatesID];
+        [self.navigationController pushViewController:controller animated:NO];
+        controller.delegate = self;
+        
+        [self performSegueWithIdentifier:kSegueToInstallCertificate sender:nil];
+    } else {
+        NSString *param = nil;
+        NSString *certName = self.certNameLabel.text;
+        
+        if (certName && certName.length > 0) {
+            param = certName;
+        }
+        [self performSegueWithIdentifier:kSegueToCertificates sender:param];
+    }
+}
+
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([segue.identifier isEqualToString:kSegueToCertificates]) {
+        CertificatesViewController *controller = segue.destinationViewController;
+        controller.selectedCertName = self.certNameLabel.text;
+        controller.delegate = self;
+    }
+} 
+
+#pragma mark - CertificateChangeDelegate
+- (void)certificateDidSelectedWithName:(NSString *)name {
+    self.certNameLabel.text = name;
+}
+
+#pragma mark - Table view data source
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return kSettingsSectionTotal;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    NSInteger rows = 0;
+    
+    switch (section) {
+        case kSettingsSectionFirst:
+            rows = rowsInFirstSection;
+            break;
+        case kSettingsSectionSecond:
+            rows = rowsInSecondSection;
+            break;
+            
+        default:
+            break;
+    }
+    
+    return rows;
+}
+
+#pragma mark - UITableViewDelegate
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    if (section == kSettingsSectionFirst) {  // The first section doesn't have contain footerview.
+        return 15;
+    } else {
+        return 14;
+    }
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    NSInteger section = indexPath.section;
+    NSInteger row = indexPath.row;
+    
+    if (section == kSettingsSectionFirst && row == rowCertificate) {
+        [self jumpToCertificate];
+    }
+}
+
+#pragma mark - UITextFieldDelegate
+- (BOOL)textFieldShouldReturn:(UITextField *)textField {
+    if (textField == self.titleTextField) {
+        [self.gatewayTextField becomeFirstResponder];
+    } else if(textField == self.gatewayTextField) {
+        [self.usernameTextField becomeFirstResponder];
+    } else if(textField == self.usernameTextField) {
+        [self.portTextField becomeFirstResponder];
+    } else if(textField == self.portTextField) {
+        [self.portTextField resignFirstResponder];
+    }
+    
+    return YES;
+}
+
+#pragma mark - ANViewControllerSwitchProtocol
+- (void)switchFromSender:(id)sender withOption:(NSDictionary *)option {
+    if (sender) {
+        self.delegate = sender;
+        if (option) {
+            self.gateway = [option valueForKey:@"gateway"];
+        }
+    }
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewayViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewayViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewayViewController.h	(working copy)
@@ -0,0 +1,13 @@
+//
+//  GatewayViewController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/10.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface GatewayViewController : UIViewController
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewayViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewayViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewayViewController.m	(working copy)
@@ -0,0 +1,1172 @@
+//
+//  GatewayViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/10.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "YCXMenu.h"
+#import "ANLogger.h"
+#import "ANPopupDialog.h"
+#import "AutoLoginHandler.h"
+#import "ArrayVPNWrapper.h"
+#import "GatewayModel.h"
+#import "GatewayCell.h"
+#import "UIView+Loading.h"
+#import "LoginViewController.h"
+#import "ResourcesViewController.h"
+#import "RulesManager.h"
+#import "EmptyGatewayCell.h"
+#import "GatewayViewLayout.h"
+#import "GatewayViewController.h"
+#import "GatewaySettingsViewController.h"
+#import "LocalAuthUtil.h"
+#import "PasswordManager.h"
+#import "InformationToSave.h"
+#import "UIDevice+Hardware.h"
+#import "Singleton.h"
+#import "UIViewController+Activity.h"
+#import "SMSViewController.h"
+#import "ZTWebAuthViewController.h"
+
+static NSString * const kSegueToChallenge = @"LoginToChallenge";
+static NSString * const kSegueToSMS = @"LoginToSMS";
+static NSString * const kSegueToChangePassword = @"LoginToChangePassword";
+
+typedef NS_ENUM(NSInteger, MenuIndex) {
+    kMenuIndexLog = 0,
+    kMenuIndexAbout
+};
+
+#define OAUTH_SESSION_URL               @"/prx/000/http/localh/"
+#define CancelConnection               @"CancelConnection"
+#define JumpToLoginIn                  @"jumpToLoginIn"
+
+NSString * const kAppGroupNameGateway = @"group.net.arraynetworks.MotionProPlus";
+NSString * const kArrayVPNTunelErrorMsgGateway = @"net.arraynetworks.sslvpn.errormsg";
+NSString * const koAuthSetCodeGateway = @"net.arraynetworks.oauthsetcode";
+
+static NSString * const kSegueToSettings = @"GatewayToSettings";
+static NSString * const kSegueToLogin = @"GatewayToLogin";
+static NSString * const kSegueToResource = @"GatewayToResource";
+static NSString * const kSegueToAbout = @"GatewayToAbout";
+static NSString * const kSegueToLogSettings = @"GatewayToLogSettings";
+static NSString * const kSegueToWebAuth = @"GatewayToWebAuth";
+
+@interface GatewayViewController () <UIScrollViewDelegate, LoginControllerDelegate, GatewaySettingDelegate, GatewayCellDelegate, GatewayModelDelegate,
+AutoLoginHandlerDelegate, GatewayModelDelegate> {
+    VPNAccount  *_loginAccount;
+    GatewayCell *_loginCell;
+    AutoLoginHandler *_autoLoginHandler;
+}
+
+@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
+@property (weak, nonatomic) IBOutlet UIPageControl *pageControl;
+@property (weak, nonatomic) IBOutlet UIBarButtonItem *addGatewayButton;
+@property (weak, nonatomic) IBOutlet UIBarButtonItem *moreButton;
+
+@property (strong, nonatomic) GatewayModel *model;
+@property (nonatomic, strong) NSString     *webAuthUrl;
+@property (nonatomic, strong) NSString     *callbackUrl;
+@property (nonatomic, strong) NSArray      *realPasswords;
+@property (nonatomic, assign) BOOL         isAutoLogin;
+@property (nonatomic, assign) BOOL         isLocalDB;  //Only the biometric authentication screen is displayed
+
+@end
+
+@implementation GatewayViewController
+
+- (void)dealloc {
+    self.model = nil;
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:kArrayVPNTunelErrorMsgGateway object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:koAuthSetCodeGateway object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:CancelConnection object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:JumpToLoginIn object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:kVPNMessageNotification object:nil];
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    self.model = [[GatewayModel alloc] init];
+    self.model.delegate = self;
+    
+    [self initNavigationBarAppearance];
+    [self initCollectionView];
+    [self initPageControl];
+    [self initButtonItems];
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(autoConnectWithOauthCode:) name:koAuthSetCodeGateway object:nil];
+   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cancelConnection) name:CancelConnection object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jumpToLoginIn) name:JumpToLoginIn object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleVPNNotification:) name:kVPNMessageNotification object:nil];
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    
+    static dispatch_once_t onceToken;
+    
+    if (!_autoLoginHandler) {
+        _autoLoginHandler = [[AutoLoginHandler alloc] initWithDelegate:self];
+    }
+    
+    if (_autoLoginHandler.url) {
+        // If autolaunch, do not show add gateway view.
+        dispatch_once(&onceToken, ^{
+            [_autoLoginHandler readyToAutoLogin];
+        });
+        return;
+    }
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([segue.identifier isEqualToString:kSegueToAbout] || [segue.identifier isEqualToString:kSegueToLogSettings] || [segue.identifier isEqualToString:kSegueToChallenge] || [segue.identifier isEqualToString:kSegueToChangePassword] ||
+        [segue.identifier isEqualToString:kSegueToSMS]) {
+        return;  // These destinations doesn't need more setting.
+    }
+    
+    id<ANViewControllerSwitchProtocol> p = nil;
+    NSDictionary *option = nil;
+    
+    UINavigationController *destNavivation = (UINavigationController *)segue.destinationViewController;
+    if (destNavivation.viewControllers.count > 0) {
+        p = [destNavivation.viewControllers firstObject];
+    } else {
+        ANError(@"Can't find destination view controller.");
+        return;
+    }
+    
+    if ([segue.identifier isEqualToString:kSegueToSettings]) {
+        if ([sender isKindOfClass:[Gateway class]]) {
+            option = @{@"gateway": sender};
+        }
+        [p switchFromSender:self withOption:option];
+    } else if ([segue.identifier isEqualToString:kSegueToLogin]) {
+        [p switchFromSender:self withOption:nil];
+    }
+}
+
+-(NSDictionary *) webAuthConfig
+{
+    NSDictionary *option = nil;
+    Gateway *gateway = [self.model currentGateway];
+    __weak typeof(self) weakSelf = self;
+    void (^competion)(NSError *error, NSString *session, NSString *username, NSString *acsInfo) = ^(NSError *error, NSString *session, NSString *username, NSString *acsInfo) {
+        __strong typeof(weakSelf) strongSelf = weakSelf;
+        
+        ANInfo(@"Error: %@, Session:%@, username:%@, oauth acsInfo:%@", error, session, username, acsInfo);
+        
+        if (session && session.length > 0) {
+            if (acsInfo && acsInfo.length > 0) {
+                AAAManager *manager = [AAAManager sharedInstance];
+                [manager setOAuthAcsInfo:acsInfo];
+            }
+            if (self.webAuthUrl && [self.webAuthUrl length] > 0) {
+                [strongSelf.model loginWithSession:session andUsername:username andoAuthURL:self.webAuthUrl andcallbackURL:self.callbackUrl];
+            } else {
+                [strongSelf.model loginWithSession:session andUsername:username];
+            }
+        } else {
+            [strongSelf didFinishLogin:NO];
+        };
+        
+        if (error) {
+            NSString *message = NSLocalizedString(@"Connection to server failed", nil);
+            PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                          message:message];
+            [strongSelf presentViewController:dialog animated:YES completion:nil];
+        }
+    };
+    
+    option = @{@"host": gateway.host,
+               @"port": gateway.port,
+               @"alias": gateway.alias,
+               @"url": self.webAuthUrl,
+               @"completion": competion
+               };
+    
+    return option;
+}
+
+- (void)addButtonClicked:(id)sender {
+    [self performSegueWithIdentifier:kSegueToSettings sender:self];
+}
+
+- (void)moreButtonClicked:(id)sender {
+    YCXMenuItem *logItem = [YCXMenuItem menuItem:NSLocalizedString(@"Log", nil)
+                                           image:[UIImage imageNamed:@"GatewayLog"]
+                                             tag:kMenuIndexLog
+                                        userInfo:nil];
+    [logItem setForeColor:UIColorFromRGBA(0x666666, 1.0)];
+    
+    YCXMenuItem *aboutItem = [YCXMenuItem menuItem:NSLocalizedString(@"About", nil)
+                                             image:[UIImage imageNamed:@"GatewayAbout"]
+                                               tag:kMenuIndexAbout
+                                          userInfo:nil];
+    [aboutItem setForeColor:UIColorFromRGBA(0x666666, 1.0)];
+    NSArray *items = @[logItem, aboutItem];
+    
+    [YCXMenu setTintColor:[UIColor whiteColor]];
+    [YCXMenu setSeparatorColor:UIColorFromRGBA(0xe2e2e2, 1.0)];
+    [YCXMenu setSelectedColor:UIColorFromRGBA(0xe2e2e2, 1.0)];
+    [YCXMenu setCornerRadius:CGFLOAT_MIN];
+    if ([YCXMenu isShow]){
+        [YCXMenu dismissMenu];
+    } else {
+        [YCXMenu showMenuInView:self.view fromRect:CGRectMake(self.view.frame.size.width - 60, 0, 60, 0) menuItems:items selected:^(NSInteger index, YCXMenuItem *item) {
+            if (index == kMenuIndexLog) {
+                [self performSegueWithIdentifier:kSegueToLogSettings sender:nil];
+            } else if (index == kMenuIndexAbout) {
+                [self performSegueWithIdentifier:kSegueToAbout sender:nil];
+            }
+        }];
+    }
+}
+
+- (void)initNavigationBarAppearance {
+    // To make the black line under navigation bar disappear (for iOS11).
+    [[UINavigationBar appearance] setBackgroundImage:[[UIImage alloc] init] forBarMetrics:UIBarMetricsDefault];
+    [[UINavigationBar appearance] setShadowImage:[[UIImage alloc] init]];
+}
+
+- (void)initCollectionView {
+    // Register cells.
+    [self.collectionView registerNib:[UINib nibWithNibName:@"EmptyGatewayCell" bundle:nil]
+          forCellWithReuseIdentifier:kEmptyGatewayCellID];
+    [self.collectionView registerNib:[UINib nibWithNibName:@"GatewayCell" bundle:nil]
+          forCellWithReuseIdentifier:kGatewayCellID];
+    // Setup layout class.
+    [self.collectionView setCollectionViewLayout:[[GatewayViewLayout alloc] init]];
+    
+    self.collectionView.allowsSelection = YES;
+    self.collectionView.decelerationRate = 0.994;  // Between UIScrollViewDecelerationRateNormal and UIScrollViewDecelerationRateFast
+}
+
+- (void)initPageControl {
+    [self setPageControlAppearance];
+    self.pageControl.userInteractionEnabled = NO;
+    
+    NSInteger totalGateways = [self.model numberOfGateways];
+    if (totalGateways <= 0) {
+        self.pageControl.hidden = YES;
+    } else {
+        self.pageControl.hidden = NO;
+        self.pageControl.numberOfPages = totalGateways;
+        self.pageControl.currentPage = 0;
+    }
+}
+
+- (void)updatePageControlNumbers:(NSInteger)totalPages {
+    self.pageControl.hidden = totalPages > 0 ? NO : YES;
+    self.pageControl.numberOfPages = totalPages;
+}
+
+- (void)updatePageControlCurrentPage:(NSInteger)index {
+    NSInteger total = self.pageControl.numberOfPages;
+    if (index >= total || index < 0) {
+        ANDebug(@"Index \(%zi) of page control is out of page numbers \(%zi)", index, total);
+        return;
+    } else {
+        self.pageControl.currentPage = index;
+    }
+}
+
+- (void)updateCurrentGatewayIndex:(NSInteger)index {
+    [self.model selectGatewayAtIndex:index];
+    [Singleton sharedSingleton].currentPageNumber = index;
+}
+
+- (void)setGatewayCellAsSelectedWithIndex:(NSInteger)index {
+    [self clearGatewayCellsShadow];
+    
+    [self setCurrentCellShadowWithIndex:index];
+}
+
+- (void)clearGatewayCellsShadow {
+    for (UICollectionViewCell *cell in self.collectionView.visibleCells) {
+        if (cell) {
+            if ([cell respondsToSelector:@selector(clearShadow)]) {
+                [cell performSelector:@selector(clearShadow)];
+            }
+        }
+    }
+}
+
+- (void)setCurrentCellShadowWithIndex:(NSInteger)index {
+    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
+    GatewayCell *currentCell = (GatewayCell *)[self.collectionView cellForItemAtIndexPath:indexPath];
+    if (currentCell) {
+        if ([currentCell respondsToSelector:@selector(addShadow)]) {
+            [currentCell performSelector:@selector(addShadow)];
+        }
+    }
+}
+
+- (void)initButtonItems {
+    [self.addGatewayButton setTarget:self];
+    [self.addGatewayButton setAction:@selector(addButtonClicked:)];
+    
+    [self.moreButton setTarget:self];
+    [self.moreButton setAction:@selector(moreButtonClicked:)];
+}
+
+- (void)setPageControlAppearance {
+    self.pageControl.pageIndicatorTintColor = UIColorFromRGBA(0x999999, 1.0);
+    self.pageControl.currentPageIndicatorTintColor = MAIN_COLOR;
+}
+
+- (void)reloadWithAnimation {
+    [UIView transitionWithView:self.collectionView
+                      duration:0.3
+                       options:UIViewAnimationOptionTransitionCrossDissolve
+                    animations:^{
+                        [self.collectionView reloadData];
+                    }
+                    completion:nil];
+}
+
+- (void)deleteGateway {
+    [self.model deleteCurrentGateway];
+
+    NSInteger total = [self.model numberOfGateways];
+    if (total == 0) {
+        [self updateCurrentGatewayIndex:0];
+        [self reloadWithAnimation];
+    } else{
+        
+        NSInteger integer = 0;
+        if (self.pageControl.currentPage == total){
+            
+            integer = self.pageControl.currentPage - 1;
+        }else{
+            
+            integer = self.pageControl.currentPage;
+        }
+        
+        [self updateCurrentGatewayIndex:integer];
+        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.pageControl.currentPage inSection:0];
+        [self.collectionView deleteItemsAtIndexPaths:@[indexPath]];
+    }
+    
+    [SecuritySetting clearGesture];
+    [self updatePageControlNumbers:[self.model numberOfGateways]];
+}
+
+#pragma mark - UICollectionViewDataSource
+- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
+    NSInteger totalGateways = [self.model numberOfGateways];
+    
+    return totalGateways > 0 ? totalGateways : 1;
+}
+
+- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
+    UICollectionViewCell *cell = nil;
+    NSInteger totalGateways = [self.model numberOfGateways];
+    
+    if (totalGateways > 0) {
+        cell = [collectionView dequeueReusableCellWithReuseIdentifier:kGatewayCellID forIndexPath:indexPath];
+        Gateway *gateway = [self.model gatewayAtIndex:indexPath.row];
+        if (gateway) {
+            [(GatewayCell *)cell configureWithGateway:gateway delegate:self];
+        }
+    } else {
+        cell = [collectionView dequeueReusableCellWithReuseIdentifier:kEmptyGatewayCellID forIndexPath:indexPath];
+        EmptyGatewayCell *emptyCell = (EmptyGatewayCell *)cell;
+        [emptyCell.addGatewayButton addTarget:self action:@selector(addButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
+        [emptyCell.emptyGatewayButton addTarget:self action:@selector(addButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
+    }
+    
+    if ([cell respondsToSelector:@selector(changeLayoutForIphone5)]) {
+        [cell performSelector:@selector(changeLayoutForIphone5)];
+    }
+    
+    return cell;
+}
+
+#pragma mark - UICollectionViewDelegate
+- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
+    [collectionView deselectItemAtIndexPath:indexPath animated:YES];
+    
+    [self setGatewayCellAsSelectedWithIndex:indexPath.item];
+}
+
+#pragma mark - UIScrollViewDelegate
+- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
+    int page = (int)(scrollView.contentOffset.x / kCellWidth);
+    if (page != self.pageControl.currentPage) {
+        [self updatePageControlCurrentPage:page];
+        [self updateCurrentGatewayIndex:page];
+        [self setGatewayCellAsSelectedWithIndex:page];
+    }
+}
+
+#pragma mark - GatewaySettingDelegate
+- (void)didFinishedEdit:(BOOL)isNew {
+    NSInteger totalPages = [self.model numberOfGateways];
+    NSInteger currentPage = 0;
+    if (isNew) {
+        currentPage = totalPages-1;
+        [self updateCurrentGatewayIndex:currentPage];
+
+        if (totalPages == 1) {
+            [self reloadWithAnimation];
+        } else {
+            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:currentPage inSection:0];
+            [self.collectionView insertItemsAtIndexPaths:@[indexPath]];
+        }
+        
+        [self updatePageControlNumbers:totalPages];
+    } else {
+        currentPage = self.pageControl.currentPage;
+        [self updateCurrentGatewayIndex:currentPage];
+        
+        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:currentPage inSection:0];
+        [self.collectionView reloadItemsAtIndexPaths:@[indexPath]];
+    }
+    
+    [self setGatewayCellAsSelectedWithIndex:currentPage];
+    
+    if (isNew) {
+        
+        [self.collectionView setContentSize:CGSizeMake(currentPage * kScreenWidth, kScreenHeight)];
+        [self.collectionView setContentOffset:CGPointMake(currentPage * kScreenWidth, 0) animated:YES];
+    }
+}
+
+#pragma mark - GatewayCellDelegate
+- (void)didStartLogin:(NSString *)gatewayTitle cell:(UICollectionViewCell *)cell {
+    
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameGateway];
+    [userDefaults removeObjectForKey:KEY_OAUTH_URL];
+    [userDefaults removeObjectForKey:@"dns_list"];
+    
+    [AAAManager sharedInstance].resources = @"";
+    
+    self.webAuthUrl = @"";
+    self.isAutoLogin = NO;
+    self.isLocalDB = YES;
+    [Singleton sharedSingleton].isAuthentication = NO;
+    
+    if ([cell respondsToSelector:@selector(addShadow)]) {
+        [cell performSelector:@selector(addShadow)];
+    }
+    
+    _loginCell = (GatewayCell *)cell;
+    [self.collectionView setScrollEnabled:NO];
+    
+    Gateway *currentGateway = [self.model currentGateway];
+    if (!currentGateway.isWebAuthEnabled) {
+        [self.model login];
+    } else {
+        self.webAuthUrl = @"";
+        [self startWebAuth];
+    }
+}
+
+- (void)didCancelLogin:(NSString *)gatewayTitle {
+    _loginCell = nil;
+    [self.collectionView setScrollEnabled:YES];
+    [self.model cancelLogin];
+}
+
+- (void)willDeleteGateway:(NSString *)gatewayUrl {
+    if (!gatewayUrl) {
+        ANError(@"Gateway URL is nil, can't be deleted.");
+        return;
+    }
+    if (![gatewayUrl isEqualToString:[self.model currentGateway].url]) {
+        ANInfo(@"Gateway \"%@\" is not current gateway, don't delete.", gatewayUrl);
+        return;
+    }
+    
+    __weak typeof(self) weakSelf = self;
+    PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Delete", nil)
+                                                                  message:NSLocalizedString(@"Are you sure to delete this site?", nil)
+                                                            confirmAction:^{
+                                                                Gateway *gateway = [weakSelf.model currentGateway];
+                                                                if (!gateway) {
+                                                                    ANError(@"Can't find gateway named \"%@\".", gatewayUrl);
+                                                                    return;
+                                                                } else {
+                                                                    [weakSelf deleteGateway];
+                                                                }
+                                                            }
+                                                             cancelAction:nil];
+    [self presentViewController:popup animated:YES completion:nil];
+}
+
+- (void)willEditGateway:(NSString *)gatewayUrl andPort:(NSString *)gatewayPort {
+    Gateway *gateway = [self.model gatewayOfUrl:gatewayUrl andPort:gatewayPort];
+    [self performSegueWithIdentifier:kSegueToSettings sender:gateway];
+}
+
+#pragma mark - WebAuth
+- (void)startWebAuth {
+    [self webAuthConfig];
+    ZTWebAuthViewController *control = [[ZTWebAuthViewController alloc] init];
+    control.infoDic = [self webAuthConfig];
+    [self.navigationController pushViewController:control animated:YES];
+}
+
+#pragma mark - Login Handler
+- (void)didFinishLogin:(BOOL)success {
+    [_loginCell setAsNormal];
+    
+    [self.collectionView setScrollEnabled:YES];
+    
+    if (success) {
+        [self.model didAccessCurrentGateway];
+        
+        [_loginCell setAccessDate:[self.model currentGatewayAccessDate]];  // Update gateway cell after login.
+        
+        [self performSegueWithIdentifier:kSegueToResource sender:self];
+    }
+}
+
+- (void)continueLoginWithUrl:(NSString *)url callback:(NSString *)callback {
+    self.webAuthUrl = url;
+    self.callbackUrl = callback;
+    [_loginCell setAsLoggingIn];
+    
+    if (url) {
+        [self.model didAccessCurrentGateway];
+        
+        [_loginCell setAccessDate:[self.model currentGatewayAccessDate]];
+        [self startWebAuth];
+    }
+}
+
+#pragma mark - Auto Login Handler
+- (void)perpareForAutoLogin:(void (^)(void))completion {
+    completion();
+}
+
+- (void)didReceiveLoginRequest:(VPNAccount *)account {
+    if (!account) {
+        return;
+    }
+    
+    _loginAccount = account;
+    
+    __weak __typeof(self) weakSelf = self;
+    [self perpareForAutoLogin:^{
+        [weakSelf sendAutoLogoutNotification];
+        [weakSelf doRealAutoLogin];
+    }];
+    
+}
+
+- (void)didReceiveLoginRequest:(VPNAccount *)account oauthreq:(NSString *)request oauthcode:(NSString *)code {
+    NSString *urlString = nil;
+    if ([account.vsPort isEqualToString:@"443"]) {
+        urlString = [NSString stringWithFormat:@"https://%@%@%@?code=%@", account.vsHost, OAUTH_SESSION_URL, request, code];
+    } else {
+        urlString = [NSString stringWithFormat:@"https://%@:%@%@%@?code=%@", account.vsHost, account.vsPort, OAUTH_SESSION_URL, request, code];
+    }
+    ANInfo(@"didReceiveLoginRequest:continue login url=%@", urlString);
+    [self continueLoginWithUrl:urlString callback:account.autoLoginCallback];
+}
+
+- (void)handleVPNTunnelError:(NSNotification *)notification {
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    NSString *errMessage = [vpnWrapper getErrorMsgWithCode];
+    if (errMessage && errMessage.length > 0) {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:errMessage];
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+- (void)didReceiveLoginRequest:(VPNAccount *)account session:(NSString *)sess {
+    if (!sess || sess.length <= 0) {
+        ANWarn(@"Can't create secure tunnel with empty session.");
+        return;
+    }
+    
+    [self triggerNetworkFlowWithHost:account.vsHost andPort:account.vsPort];
+    
+    ANDebug(@"Secure tunnel will be created with session.");
+    AAAManager *manager = [AAAManager sharedInstance];
+    manager.account = account;
+    [manager setSessionID:sess];
+    
+        //Reset connect fail reason.
+        NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameGateway];
+        [userDefaults removeObjectForKey:@"tunnel_result"];
+    [[ArrayVPNWrapper sharedInstance] startSSLVPN];
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleVPNTunnelError:)
+                                                 name:kArrayVPNTunelErrorMsgGateway object:nil];
+}
+
+- (void)doRealAutoLogin {
+    if (!_loginAccount) return;
+    
+    __weak __typeof(self) weakSelf = self;
+    [self.navigationController.view startLoadingWithMessage:@"Connecting..."
+                                                buttonTitle:NSLocalizedString(@"Cancel", nil)
+                                               cancelAction:^{
+                                                   [weakSelf.model cancelLogin];
+                                               }];
+    
+    [self.model autoLoginwithAccount:_loginAccount];
+}
+
+- (void)logoutThenLogin {
+    __weak __typeof(self) weakSelf = self;
+    
+    [self.model logoutCurrentSession:^{
+        ANDebug(@"Logout successfully, do login");
+        
+        [self sendAutoLogoutNotification];
+        // Wait 1 second for l3vpn thread to stop.
+        [weakSelf performSelector:@selector(doRealAutoLogin) withObject:nil afterDelay:1];
+    }];
+}
+
+- (void)autoLoginFailed:(NSString *)errorMessage {
+    if (!errorMessage) {
+        return;
+    }
+    
+    ANInfo(@"Login failed: %@", errorMessage);
+    
+    PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                   message:errorMessage
+                                                             confirmAction:nil
+                                                              cancelAction:nil];
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)didReceiveDisconnectRequest:(VPNAccount *)account IsLogout:(BOOL)islogout {
+    ANInfo(@"Receive logout request");
+    
+    [self sendAutoLogoutNotification];
+    
+    Gateway *gateway = [[GatewayManager sharedInstance] gatewayOfUrl:account.vsURL andport:account.vsPort];
+    if (!gateway) {  // MPP has been launched by URLScheme with session.
+        ANDebug(@"Secure tunnel will be destoryed with session.");
+        
+        [[ArrayVPNWrapper sharedInstance] stopSSLVPN];
+        if (islogout) {
+            NSInteger ret = [[AAAManager sharedInstance] logoutL3VPNSession];
+            if (ret != ERR_SUCCESS) {
+                ANError(@"Logout failed with error code: %zi.", ret);
+            }
+        }
+    }
+}
+
+- (void)sendAutoLogoutNotification {
+    [[NSNotificationCenter defaultCenter] postNotificationName:kAutoLogoutNotification object:nil];
+}
+
+/**
+ *  This method is meaningful only on first time launched by URLScheme with session after installed from AppStore.
+ *  Cuz it needs the user to allow MPP app to use network privilege, it MUST have network flow. So, it make
+ *  a simple "HEAD" http request here, and the result is not cared about.
+ */
+- (void)triggerNetworkFlowWithHost:(NSString *)host andPort:(NSString *)port {
+    NSString *realPort = @"443";
+    
+    if (!host || host.length == 0) {
+        return;
+    }
+    
+    if (port && port.length > 0) {
+        realPort = port;
+    }
+    
+    NSString *urlString = [NSString stringWithFormat:@"https://%@:%@", host, realPort];
+    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
+    request.HTTPMethod = @"HEAD";
+    NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:nil];
+    [connection start];
+    
+    ANDebug(@"A http request has been sent for auto-login. URL is: %@.", urlString);
+}
+
+- (void)autoConnectWithOauthCode:(NSNotification *)notification {
+    NSString *code =[notification.userInfo objectForKey:@"code"];
+    
+    if (code.length <= 0) {
+        ANError(@"autoConnectWithOauthCode: Get oAuth code failed.");
+        
+        return;
+    }
+    
+    ANInfo(@"autoConnectWithOauthCode: get oauth code successfully=%@", code);
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameGateway];
+    NSString *oauthUrl = [userDefaults valueForKey:KEY_OAUTH_URL];
+    if (oauthUrl.length <= 0) {
+        ANError(@"autoConnectWithOauthCode: Get saved oauth url failed.");
+        
+        return;
+    }
+    oauthUrl = [NSString stringWithFormat:@"%@%@", oauthUrl, code];
+    ANInfo(@"autoConnectWithOauthCode: connect with oauth url=%@", oauthUrl);
+    [self continueLoginWithUrl:oauthUrl callback:nil];
+}
+
+#pragma mark - GatewayModelDelegate
+- (void)needLoginInfo {
+    
+    BOOL isAuth = [Singleton sharedSingleton].isAuthentication;
+    Gateway *gateway = [self.model currentGateway];
+    
+    if (isAuth || gateway.isRadiusPWD){
+        
+        [self performSegueWithIdentifier:kSegueToLogin sender:self];
+    }else{
+        
+        [self checkVerifyMothod];
+    }
+}
+
+- (void)needRegister {
+    [self performSegueWithIdentifier:kSegueToLogin sender:self];
+}
+
+- (void)needConfirm:(NSString *)message {
+    __weak typeof(self) weakSelf = self;
+    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil message:message preferredStyle:UIAlertControllerStyleActionSheet];
+    UIAlertAction *alertActionDestructive = [UIAlertAction actionWithTitle:NSLocalizedString(@"Continue, but never show me this again", nil)
+                                                                     style:UIAlertActionStyleDestructive
+                                                                   handler:^(UIAlertAction *action){
+                                                                       [weakSelf.model suppressCheckServerCertForCurrentGateway];
+                                                                       [weakSelf.model continueLogin];
+                                                                   }];
+    UIAlertAction *alertActionDefault = [UIAlertAction actionWithTitle:NSLocalizedString(@"Continue", nil)
+                                                                 style:UIAlertActionStyleDefault
+                                                               handler:^(UIAlertAction *action){
+                                                                   [weakSelf.model continueLogin];
+                                                               }];
+    UIAlertAction *alertActionCancel = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
+                                                                style:UIAlertActionStyleCancel
+                                                              handler:^(UIAlertAction *action){
+                                                                  [weakSelf didFinishLogin:NO];
+                                                              }];
+    [alertController addAction:alertActionDestructive];
+    [alertController addAction:alertActionDefault];
+    [alertController addAction:alertActionCancel];
+    UIPopoverPresentationController *popover = alertController.popoverPresentationController;
+    if (popover){
+        popover.sourceView = self.view;
+        popover.sourceRect = CGRectMake(self.view.bounds.size.width/2.0, self.view.bounds.size.height, 1.0, 1.0);
+        popover.permittedArrowDirections = UIPopoverArrowDirectionAny;
+    }
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [self presentViewController:alertController animated:YES completion:nil];
+    });
+}
+
+- (void)needLogout {
+    ANInfo(@"Need logout current session");
+    
+    __weak typeof(self) weakSelf = self;
+    NSString *message = [NSString stringWithFormat:NSLocalizedString(@"There is currently an active connection to %@, you can disconnect the current session,\
+                                                                     and start a new connection, or display the active connection.", nil),
+                                                                    [AAAManager sharedInstance].account.vsHost];
+    PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+                                                                   message:message
+                                                              confirmTitle:NSLocalizedString(@"Active Connection",nil)
+                                                               cancelTitle:NSLocalizedString(@"New Connection", nil)
+                                                             confirmAction:^{
+                                                                 [weakSelf logoutThenLogin];
+                                                             }
+                                                              cancelAction:nil];
+    
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)needVDIAuth {
+    __weak typeof(self) weakSelf = self;
+    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"VDI Credential", nil)
+                                                                             message:NSLocalizedString(@"Please input username and password", nil)
+                                                                      preferredStyle:UIAlertControllerStyleAlert];
+    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
+                                                           style:UIAlertActionStyleCancel
+                                                         handler:^(UIAlertAction * _Nonnull action) {
+                                                             [weakSelf.model loginWithVDIUsername:nil password:nil];
+                                                         }];
+    UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
+                                                            style:UIAlertActionStyleDefault
+                                                          handler:^(UIAlertAction * _Nonnull action) {
+                                                              NSString *username = alertController.textFields[0].text;  // Username text field
+                                                              NSString *password = alertController.textFields[1].text;  // Password text field
+                                                              username = [username stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
+                                                              
+                                                              [weakSelf.model loginWithVDIUsername:username password:password];
+                                                          }];
+    
+    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = NSLocalizedString(@"Username", nil);
+    }];
+    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = NSLocalizedString(@"Password", nil);
+    }];
+    [alertController addAction:confirmAction];
+    [alertController addAction:cancelAction];
+    
+    [self presentViewController:alertController animated:YES completion:nil];
+}
+
+- (void)needDoPreLoginCV {
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{
+        [[RulesManager sharedInstance].interactionHandler takeAction];
+    });
+}
+
+- (void)loginError:(NSString *)message {
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [self didFinishLogin:NO];
+    });
+    if (!message) {
+        return;
+    }
+    
+    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:message];
+    
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)loginErrorOfTip:(NSString *)message {
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [self didFinishLogin:NO];
+    });
+    if (!message) {
+        return;
+    }
+    
+    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Tips",nil) message:message];
+    
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)loginFinished:(BOOL)success {
+    [self didFinishLogin:success];
+    
+    [self.navigationController.view stopLoading];
+}
+
+- (void)checkVerifyMothod {
+    Gateway *gateway = [self.model currentGateway];
+    NSString *username = gateway.username;
+    NSString *port = gateway.port;
+    
+    _realPasswords = @[@"", @"", @""];
+    NSDictionary *methodDic = [Singleton getCurrentGatewayMethod:[self.model currentGateway]];
+    NSString *lastName = [methodDic objectForKey:@"userName"] ?: @"";
+    if ([username isEqualToString:@""]){
+        
+        username = lastName;
+    }
+    
+    if (username != nil) {
+        if (!gateway.lastAccessedDate) {  // Prevent from getting saved password after reinstall.
+            [PasswordManager removePasswordsOfHost:gateway.host username:username port:port];
+        }
+        if ([username isEqualToString:lastName] && (gateway.isGestureEnabled || gateway.isFaceOrTouchIDEnabled)) {
+            
+            _realPasswords = [PasswordManager passwordsOfHost:gateway.host username:username port:port];
+            if (![_realPasswords isEqual:@[@"", @"", @""]]){
+                
+                [self mutilVerifyMothod];
+                return;
+            }
+        } else {
+            ANDebug(@"delete user \"%@\" password", username?username:@"nil");
+            [Singleton setCurrentGatewayMethod:@{} andKey:gateway];
+        }
+    }
+    [self performSegueWithIdentifier:kSegueToLogin sender:self];
+}
+
+#pragma mark - 生物认证 手势认证
+-(void) mutilVerifyMothod
+{
+    Gateway *gw = [self.model currentGateway];
+    if (gw.isFaceOrTouchIDEnabled || gw.isGestureEnabled){
+        
+        [Singleton sharedSingleton].isAuthentication = YES;
+        LocalAuthFinishBlockType completeBlock = ^(BOOL isAllow, SecuritySettingOption authType){
+            
+            [Singleton sharedSingleton].isAuthentication = isAllow;
+            if (isAllow){
+                
+                self.isAutoLogin = YES;
+                [self login];
+            }
+        };
+        UIViewController *control = [LocalAuthUtil getAuthVCWithCompletion:completeBlock];
+        control.modalPresentationStyle = UIModalPresentationFullScreen;
+        [self presentViewController:control animated:YES completion:nil];
+    }
+}
+
+- (void)login {
+    
+    VPNAccount *account = [self inputResult];
+    
+    if (account == nil) {
+        ANWarn(@"Cannot get account information");
+        return;
+    }
+    
+    InformationToSave *info = [InformationToSave sharedInstance];
+    
+    info.lastLoginAccount = account;
+    [info save];
+    
+    AAAManager *manager = [AAAManager sharedInstance];
+    manager.errorCode = 0; // Success
+    [manager continueVPNThreadWithAccount:account];
+}
+
+- (VPNAccount *)inputResult {
+    
+    AAAManager *manager = [AAAManager sharedInstance];
+    
+    VPNAccount * account = manager.account;
+    
+    NSDictionary *methodDic = [Singleton getCurrentGatewayMethod:[self.model currentGatewayUpInside]];
+    
+    NSString *methodType = [methodDic objectForKey:@"methodType"];
+    if ([methodType isEqualToString:@"0"]){
+        
+        [Singleton sharedSingleton].isSupportAuth = YES;
+    }else{
+        
+        [Singleton sharedSingleton].isSupportAuth = NO;
+    }
+    
+    account.loginMethod = [methodDic objectForKey:@"methodName"] ?: @"";
+    account.userName = [methodDic objectForKey:@"userName"] ?: @"";
+    
+    account.passWord  = _realPasswords[0]  ?: @"";
+    account.passWord2 = _realPasswords[1]  ?: @"";
+    account.passWord3 = _realPasswords[2]  ?: @"";
+    
+    UIDevice *devInfo = [UIDevice currentDevice];
+    account.deviceName =[NSString stringWithFormat:@"%@|Apple;%@;iOS %@", devInfo.name, devInfo.platformString, devInfo.systemVersion];
+    
+    return account;
+}
+
+-(void) cancelConnection
+{
+    [self didFinishLogin:NO];
+    [[AAAManager sharedInstance] cancelLoginTapped];
+}
+
+-(void) jumpToLoginIn
+{
+    [self performSegueWithIdentifier:kSegueToLogin sender:self];
+}
+
+- (void)handleVPNNotification:(NSNotification *)notification {
+    //only faceid/touchid/gestuer auth
+    if (!self.isAutoLogin){
+        
+        return;
+    }
+    
+    VPNMessage *message = notification.object;
+    AAAManager *manager = [AAAManager sharedInstance];
+    NSInteger error = manager.errorCode;
+    NSString *aMessage;
+    
+    switch (message.code) {
+        case VPN_CB_CONNECTED: {
+            if (!self.isLocalDB){
+                
+                [self pop];
+            }
+            [self didFinishLogin:YES];
+            break;
+        }
+        case VPN_CB_DISCONNECTING: {
+            if (!self.isLocalDB){
+                
+                [self pop];
+            }
+            self.isAutoLogin = NO;
+            [self didFinishLogin:NO];
+            break;
+        }
+        case VPN_CB_CHALLENGE: {
+            self.isLocalDB = NO;
+            [self performSegueWithIdentifier:kSegueToChallenge sender:nil];
+            break;
+        }
+        case VPN_CB_CONN_FAILED: {
+            switch (error) {
+                case ERR_WRONG_USER_PASS:
+                    aMessage = manager.errorInformation;
+                    break;
+                case ERR_AUTHORIZE_FAILED:
+                    aMessage = NSLocalizedString(@"Login failed", nil);
+                    break;
+                case ERR_CALLBACK_FAILED:
+                    break;
+                case ERR_INTERRUPTED:
+                    break;
+                case ERR_CLIENT_SECURITY:
+                    aMessage = NSLocalizedString(@"Client security is not supported", nil);
+                    break;
+                case ERR_SMS_GET_PHONE:
+                    aMessage = NSLocalizedString(@"The system failed to get your phone number to do OTP authentication", nil);
+                    break;
+                case ERR_SMS_SEND:
+                    aMessage = NSLocalizedString(@"The system failed to send message to your phone", nil);
+                    break;
+                case ERR_SMS_TOO_MANY_RETRY:
+                    aMessage = NSLocalizedString(@"Your attempt to sign in failed, because you have entered wrong SMS verification code for too many times", nil);
+                    break;
+                case ERR_HWID_DENY:
+                    aMessage = NSLocalizedString(@"The device is denied because of wrong hardware ID!", nil);
+                    break;
+                case ERR_HWID_PENDING:
+                    aMessage = NSLocalizedString(@"The hardware ID of this device is not approved yet!", nil);
+                    break;
+                default:
+                    ANError(@"Login failed with error message: %@", aMessage);
+                    break;
+            }
+            
+            Gateway *gw = [[[GatewayModel alloc] init] currentGatewayUpInside];
+            if (!gw.isShowLoginDialogEnabled) {
+                if (aMessage && aMessage.length > 0) {
+                    if (![aMessage containsString:@"<a href='"]) {
+                        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:aMessage];
+                        [self presentViewController:dialog animated:YES completion:nil];
+                    } else {
+                        ANInfo(@"Connect failed:Error message=%@", aMessage);
+                        NSRange subStrRange = [aMessage rangeOfString:@"<a href='"];
+                        NSMutableString *finalMessage = [NSMutableString stringWithString:aMessage];
+                        [finalMessage deleteCharactersInRange:NSMakeRange(subStrRange.location, (int)strlen("<a href='"))];
+                        NSString *displayMessage = [finalMessage substringToIndex:[finalMessage rangeOfString:@"'>"].location];
+                        ANInfo(@"Connect failed:Display message=%@", displayMessage);
+                        
+                        NSString *URLMessage = [aMessage substringFromIndex:(subStrRange.location + subStrRange.length)];
+                        URLMessage = [URLMessage substringToIndex:[URLMessage rangeOfString:@"'>"].location];
+                        ANInfo(@"URL message=%@", URLMessage);
+                        
+                        PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil) message:displayMessage confirmAction:^{
+                                                                    NSURL *url = [NSURL URLWithString:URLMessage];
+                                                                    OpenURL(url);
+                                                                    }
+                                                        cancelAction:nil];
+                        [self presentViewController:popup animated:YES completion:nil];
+                    }
+                }
+            }
+            
+            break;
+        }
+        case VPN_CB_LOGIN:{
+            if (error == ERR_WRONG_USER_PASS || error == ERR_USER_LOCKED) {
+                __weak typeof(self) weakSelf = self;
+                if (![manager.errorInformation containsString:@"<a href='"]) {
+                    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                                  message:[self loginFailedMessage:error]
+                                                                                   action:^{
+                                                                                       [weakSelf showLoginActivity:NO];
+                                                                                   }];
+                    [self presentViewController:dialog animated:YES completion:nil];
+                } else {
+                    ANInfo(@"Error message=%@", manager.errorInformation);
+                    NSRange subStrRange = [manager.errorInformation rangeOfString:@"<a href='"];
+                    NSMutableString *finalMessage = [NSMutableString stringWithString:manager.errorInformation];
+                    [finalMessage deleteCharactersInRange:NSMakeRange(subStrRange.location, (int)strlen("<a href='"))];
+                    NSString *displayMessage = [finalMessage substringToIndex:[finalMessage rangeOfString:@"'>"].location];
+                    ANInfo(@"Display message=%@", displayMessage);
+                    
+                    NSString *URLMessage = [manager.errorInformation substringFromIndex:(subStrRange.location + subStrRange.length)];
+                    URLMessage = [URLMessage substringToIndex:[URLMessage rangeOfString:@"'>"].location];
+                    ANInfo(@"URL message=%@", URLMessage);
+                    
+                    PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil) message:displayMessage confirmAction:^{
+                                                                NSURL *url = [NSURL URLWithString:URLMessage];
+                                                                OpenURL(url);
+                                                                [weakSelf showLoginActivity:NO];
+                        
+                                                                // If password is wrong, pop to root view.
+                                                                [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                }
+                                               cancelAction:^{
+                                                                [weakSelf showLoginActivity:NO];
+                                                                // If password is wrong, pop to root view.
+                                                                [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                }];
+                    [self presentViewController:popup animated:YES completion:nil];
+                }
+            } else if (error == ERR_AUTHORIZE_FAILED) {
+                PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@""
+                                                                              message:NSLocalizedString(@"Authorize failed",nil)];
+                [self presentViewController:dialog animated:YES completion:nil];
+                
+            }
+        }
+        case VPN_CB_SMS: {
+            self.isLocalDB = NO;
+            if ([self.navigationController.topViewController isKindOfClass:[SMSViewController class]]) {
+                [self refreshTopView];
+            } else {
+                [self performSegueWithIdentifier:kSegueToSMS sender:nil];
+            }
+            break;
+        }
+        case VPN_CB_CHANGPASSWORD: {
+            self.isLocalDB = NO;
+            [self performSegueWithIdentifier:kSegueToChangePassword sender:nil];
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+- (NSString *)loginFailedMessage:(NSInteger)errorCode {
+    AAAManager *manager = [AAAManager sharedInstance];
+    
+    if (errorCode == ERR_USER_LOCKED) {
+        NSString *errorMessage = manager.errorInformation;
+        if (errorMessage && errorMessage.length > 0) {
+            return errorMessage;
+        }
+    }
+    
+    NSString *errorMessage = manager.errorInformation;
+    if (errorMessage && errorMessage.length > 0) {
+        return errorMessage;
+    }
+    
+    // Return this string for all login error (incorrect username or password) except SMX auth.
+    return NSLocalizedString(@"Login failed, please check username and password", nil);
+}
+
+- (void)refreshTopView {
+    UIViewController *top = [self.navigationController topViewController];
+    SEL handler = NSSelectorFromString(@"refreshView");
+    if ([top respondsToSelector:handler]) {
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+        [top performSelector:handler];
+    }
+}
+
+- (void)pop {
+    if (self.navigationController.viewControllers.count > 1) {
+        [self.navigationController popViewControllerAnimated:YES];
+    }else{
+        [self dismissViewControllerAnimated:YES completion:nil];
+    }
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewayViewController.m.InfosecEnterprise
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewayViewController.m.InfosecEnterprise	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewayViewController.m.InfosecEnterprise	(working copy)
@@ -0,0 +1,1184 @@
+//
+//  GatewayViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/10.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "YCXMenu.h"
+#import "ANLogger.h"
+#import "ANPopupDialog.h"
+#import "AutoLoginHandler.h"
+#import "ArrayVPNWrapper.h"
+#import "GatewayModel.h"
+#import "GatewayCell.h"
+#import "UIView+Loading.h"
+#import "LoginViewController.h"
+#import "ResourcesViewController.h"
+#import "RulesManager.h"
+#import "EmptyGatewayCell.h"
+#import "GatewayViewLayout.h"
+#import "GatewayViewController.h"
+#import "GatewaySettingsViewController.h"
+#import "LocalAuthUtil.h"
+#import "PasswordManager.h"
+#import "InformationToSave.h"
+#import "UIDevice+Hardware.h"
+#import "Singleton.h"
+#import "UIViewController+Activity.h"
+#import "SMSViewController.h"
+#import "ZTWebAuthViewController.h"
+
+static NSString * const kSegueToChallenge = @"LoginToChallenge";
+static NSString * const kSegueToSMS = @"LoginToSMS";
+static NSString * const kSegueToChangePassword = @"LoginToChangePassword";
+
+typedef NS_ENUM(NSInteger, MenuIndex) {
+    kMenuIndexLog = 0,
+    kMenuIndexAbout
+};
+
+#define OAUTH_SESSION_URL               @"/prx/000/http/localh/"
+#define CancelConnection               @"CancelConnection"
+#define JumpToLoginIn                  @"jumpToLoginIn"
+
+#if TARGET_OS_IPHONE
+NSString * const kAppGroupNameGateway = @"group.net.infosec.groupenterprise";
+NSString * const kArrayVPNTunelErrorMsgGateway = @"net.arraynetworks.sslvpn.errormsg";
+NSString * const koAuthSetCodeGateway = @"net.arraynetworks.oauthsetcode";
+#elif TARGET_OS_MAC
+NSString * const kAppGroupNameGateway = @"5VZLZ3YQ9P.net.arraynetworks.MacTunnel";
+#endif
+
+static NSString * const kSegueToSettings = @"GatewayToSettings";
+static NSString * const kSegueToLogin = @"GatewayToLogin";
+static NSString * const kSegueToResource = @"GatewayToResource";
+static NSString * const kSegueToAbout = @"GatewayToAbout";
+static NSString * const kSegueToLogSettings = @"GatewayToLogSettings";
+static NSString * const kSegueToWebAuth = @"GatewayToWebAuth";
+
+@interface GatewayViewController () <UIScrollViewDelegate, LoginControllerDelegate, GatewaySettingDelegate, GatewayCellDelegate, GatewayModelDelegate,
+AutoLoginHandlerDelegate, GatewayModelDelegate> {
+    VPNAccount  *_loginAccount;
+    GatewayCell *_loginCell;
+    AutoLoginHandler *_autoLoginHandler;
+}
+
+@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
+@property (weak, nonatomic) IBOutlet UIPageControl *pageControl;
+@property (weak, nonatomic) IBOutlet UIBarButtonItem *addGatewayButton;
+@property (weak, nonatomic) IBOutlet UIBarButtonItem *moreButton;
+
+@property (strong, nonatomic) GatewayModel *model;
+@property (nonatomic, strong) NSString     *webAuthUrl;
+@property (nonatomic, strong) NSString     *callbackUrl;
+@property (nonatomic, strong) NSArray      *realPasswords;
+@property (nonatomic, assign) BOOL         isAutoLogin;
+@property (nonatomic, assign) BOOL         isLocalDB;  //Only the biometric authentication screen is displayed
+
+@end
+
+@implementation GatewayViewController
+
+- (void)dealloc {
+    self.model = nil;
+#if TARGET_OS_IPHONE
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:kArrayVPNTunelErrorMsgGateway object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:koAuthSetCodeGateway object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:CancelConnection object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:JumpToLoginIn object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:kVPNMessageNotification object:nil];
+#endif
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    self.model = [[GatewayModel alloc] init];
+    self.model.delegate = self;
+    
+    [self initNavigationBarAppearance];
+    [self initCollectionView];
+    [self initPageControl];
+    [self initButtonItems];
+#if TARGET_OS_IPHONE
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(autoConnectWithOauthCode:) name:koAuthSetCodeGateway object:nil];
+   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cancelConnection) name:CancelConnection object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jumpToLoginIn) name:JumpToLoginIn object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleVPNNotification:) name:kVPNMessageNotification object:nil];
+#endif
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    
+    static dispatch_once_t onceToken;
+    
+    if (!_autoLoginHandler) {
+        _autoLoginHandler = [[AutoLoginHandler alloc] initWithDelegate:self];
+    }
+    
+    if (_autoLoginHandler.url) {
+        // If autolaunch, do not show add gateway view.
+        dispatch_once(&onceToken, ^{
+            [_autoLoginHandler readyToAutoLogin];
+        });
+        return;
+    }
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([segue.identifier isEqualToString:kSegueToAbout] || [segue.identifier isEqualToString:kSegueToLogSettings] || [segue.identifier isEqualToString:kSegueToChallenge] || [segue.identifier isEqualToString:kSegueToChangePassword] ||
+        [segue.identifier isEqualToString:kSegueToSMS]) {
+        return;  // These destinations doesn't need more setting.
+    }
+    
+    id<ANViewControllerSwitchProtocol> p = nil;
+    NSDictionary *option = nil;
+    
+    UINavigationController *destNavivation = (UINavigationController *)segue.destinationViewController;
+    if (destNavivation.viewControllers.count > 0) {
+        p = [destNavivation.viewControllers firstObject];
+    } else {
+        ANError(@"Can't find destination view controller.");
+        return;
+    }
+    
+    if ([segue.identifier isEqualToString:kSegueToSettings]) {
+        if ([sender isKindOfClass:[Gateway class]]) {
+            option = @{@"gateway": sender};
+        }
+        [p switchFromSender:self withOption:option];
+    } else if ([segue.identifier isEqualToString:kSegueToLogin]) {
+        [p switchFromSender:self withOption:nil];
+    }
+}
+
+-(NSDictionary *) webAuthConfig
+{
+    NSDictionary *option = nil;
+    Gateway *gateway = [self.model currentGateway];
+    __weak typeof(self) weakSelf = self;
+    void (^competion)(NSError *error, NSString *session, NSString *username, NSString *acsInfo) = ^(NSError *error, NSString *session, NSString *username, NSString *acsInfo) {
+        __strong typeof(weakSelf) strongSelf = weakSelf;
+        
+        ANInfo(@"Error: %@, Session:%@, username:%@, oauth acsInfo:%@", error, session, username, acsInfo);
+        
+        if (session && session.length > 0) {
+            if (acsInfo && acsInfo.length > 0) {
+                AAAManager *manager = [AAAManager sharedInstance];
+                [manager setOAuthAcsInfo:acsInfo];
+            }
+            if (self.webAuthUrl && [self.webAuthUrl length] > 0) {
+                [strongSelf.model loginWithSession:session andUsername:username andoAuthURL:self.webAuthUrl andcallbackURL:self.callbackUrl];
+            } else {
+                [strongSelf.model loginWithSession:session andUsername:username];
+            }
+        } else {
+            [strongSelf didFinishLogin:NO];
+        };
+        
+        if (error) {
+            NSString *message = NSLocalizedString(@"Connection to server failed", nil);
+            PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                          message:message];
+            [strongSelf presentViewController:dialog animated:YES completion:nil];
+        }
+    };
+    
+    option = @{@"host": gateway.host,
+               @"port": gateway.port,
+               @"alias": gateway.alias,
+               @"url": self.webAuthUrl,
+               @"completion": competion
+               };
+    
+    return option;
+}
+
+- (void)addButtonClicked:(id)sender {
+    [self performSegueWithIdentifier:kSegueToSettings sender:self];
+}
+
+- (void)moreButtonClicked:(id)sender {
+    YCXMenuItem *logItem = [YCXMenuItem menuItem:NSLocalizedString(@"Log", nil)
+                                           image:[UIImage imageNamed:@"GatewayLog"]
+                                             tag:kMenuIndexLog
+                                        userInfo:nil];
+    [logItem setForeColor:UIColorFromRGBA(0x666666, 1.0)];
+    
+    YCXMenuItem *aboutItem = [YCXMenuItem menuItem:NSLocalizedString(@"About", nil)
+                                             image:[UIImage imageNamed:@"GatewayAbout"]
+                                               tag:kMenuIndexAbout
+                                          userInfo:nil];
+    [aboutItem setForeColor:UIColorFromRGBA(0x666666, 1.0)];
+    NSArray *items = @[logItem, aboutItem];
+    
+    [YCXMenu setTintColor:[UIColor whiteColor]];
+    [YCXMenu setSeparatorColor:UIColorFromRGBA(0xe2e2e2, 1.0)];
+    [YCXMenu setSelectedColor:UIColorFromRGBA(0xe2e2e2, 1.0)];
+    [YCXMenu setCornerRadius:CGFLOAT_MIN];
+    if ([YCXMenu isShow]){
+        [YCXMenu dismissMenu];
+    } else {
+        [YCXMenu showMenuInView:self.view fromRect:CGRectMake(self.view.frame.size.width - 60, 0, 60, 0) menuItems:items selected:^(NSInteger index, YCXMenuItem *item) {
+            if (index == kMenuIndexLog) {
+                [self performSegueWithIdentifier:kSegueToLogSettings sender:nil];
+            } else if (index == kMenuIndexAbout) {
+                [self performSegueWithIdentifier:kSegueToAbout sender:nil];
+            }
+        }];
+    }
+}
+
+- (void)initNavigationBarAppearance {
+    // To make the black line under navigation bar disappear (for iOS11).
+    [[UINavigationBar appearance] setBackgroundImage:[[UIImage alloc] init] forBarMetrics:UIBarMetricsDefault];
+    [[UINavigationBar appearance] setShadowImage:[[UIImage alloc] init]];
+}
+
+- (void)initCollectionView {
+    // Register cells.
+    [self.collectionView registerNib:[UINib nibWithNibName:@"EmptyGatewayCell" bundle:nil]
+          forCellWithReuseIdentifier:kEmptyGatewayCellID];
+    [self.collectionView registerNib:[UINib nibWithNibName:@"GatewayCell" bundle:nil]
+          forCellWithReuseIdentifier:kGatewayCellID];
+    // Setup layout class.
+    [self.collectionView setCollectionViewLayout:[[GatewayViewLayout alloc] init]];
+    
+    self.collectionView.allowsSelection = YES;
+    self.collectionView.decelerationRate = 0.994;  // Between UIScrollViewDecelerationRateNormal and UIScrollViewDecelerationRateFast
+}
+
+- (void)initPageControl {
+    [self setPageControlAppearance];
+    self.pageControl.userInteractionEnabled = NO;
+    
+    NSInteger totalGateways = [self.model numberOfGateways];
+    if (totalGateways <= 0) {
+        self.pageControl.hidden = YES;
+    } else {
+        self.pageControl.hidden = NO;
+        self.pageControl.numberOfPages = totalGateways;
+        self.pageControl.currentPage = 0;
+    }
+}
+
+- (void)updatePageControlNumbers:(NSInteger)totalPages {
+    self.pageControl.hidden = totalPages > 0 ? NO : YES;
+    self.pageControl.numberOfPages = totalPages;
+}
+
+- (void)updatePageControlCurrentPage:(NSInteger)index {
+    NSInteger total = self.pageControl.numberOfPages;
+    if (index >= total || index < 0) {
+        ANDebug(@"Index \(%zi) of page control is out of page numbers \(%zi)", index, total);
+        return;
+    } else {
+        self.pageControl.currentPage = index;
+    }
+}
+
+- (void)updateCurrentGatewayIndex:(NSInteger)index {
+    [self.model selectGatewayAtIndex:index];
+    [Singleton sharedSingleton].currentPageNumber = index;
+}
+
+- (void)setGatewayCellAsSelectedWithIndex:(NSInteger)index {
+    [self clearGatewayCellsShadow];
+    
+    [self setCurrentCellShadowWithIndex:index];
+}
+
+- (void)clearGatewayCellsShadow {
+    for (UICollectionViewCell *cell in self.collectionView.visibleCells) {
+        if (cell) {
+            if ([cell respondsToSelector:@selector(clearShadow)]) {
+                [cell performSelector:@selector(clearShadow)];
+            }
+        }
+    }
+}
+
+- (void)setCurrentCellShadowWithIndex:(NSInteger)index {
+    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
+    GatewayCell *currentCell = (GatewayCell *)[self.collectionView cellForItemAtIndexPath:indexPath];
+    if (currentCell) {
+        if ([currentCell respondsToSelector:@selector(addShadow)]) {
+            [currentCell performSelector:@selector(addShadow)];
+        }
+    }
+}
+
+- (void)initButtonItems {
+    [self.addGatewayButton setTarget:self];
+    [self.addGatewayButton setAction:@selector(addButtonClicked:)];
+    
+    [self.moreButton setTarget:self];
+    [self.moreButton setAction:@selector(moreButtonClicked:)];
+}
+
+- (void)setPageControlAppearance {
+    self.pageControl.pageIndicatorTintColor = UIColorFromRGBA(0x999999, 1.0);
+    self.pageControl.currentPageIndicatorTintColor = MAIN_COLOR;
+}
+
+- (void)reloadWithAnimation {
+    [UIView transitionWithView:self.collectionView
+                      duration:0.3
+                       options:UIViewAnimationOptionTransitionCrossDissolve
+                    animations:^{
+                        [self.collectionView reloadData];
+                    }
+                    completion:nil];
+}
+
+- (void)deleteGateway {
+    [self.model deleteCurrentGateway];
+
+    NSInteger total = [self.model numberOfGateways];
+    if (total == 0) {
+        [self updateCurrentGatewayIndex:0];
+        [self reloadWithAnimation];
+    } else{
+        
+        NSInteger integer = 0;
+        if (self.pageControl.currentPage == total){
+            
+            integer = self.pageControl.currentPage - 1;
+        }else{
+            
+            integer = self.pageControl.currentPage;
+        }
+        
+        [self updateCurrentGatewayIndex:integer];
+        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.pageControl.currentPage inSection:0];
+        [self.collectionView deleteItemsAtIndexPaths:@[indexPath]];
+    }
+    
+    [SecuritySetting clearGesture];
+    [self updatePageControlNumbers:[self.model numberOfGateways]];
+}
+
+#pragma mark - UICollectionViewDataSource
+- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
+    NSInteger totalGateways = [self.model numberOfGateways];
+    
+    return totalGateways > 0 ? totalGateways : 1;
+}
+
+- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
+    UICollectionViewCell *cell = nil;
+    NSInteger totalGateways = [self.model numberOfGateways];
+    
+    if (totalGateways > 0) {
+        cell = [collectionView dequeueReusableCellWithReuseIdentifier:kGatewayCellID forIndexPath:indexPath];
+        Gateway *gateway = [self.model gatewayAtIndex:indexPath.row];
+        if (gateway) {
+            [(GatewayCell *)cell configureWithGateway:gateway delegate:self];
+        }
+    } else {
+        cell = [collectionView dequeueReusableCellWithReuseIdentifier:kEmptyGatewayCellID forIndexPath:indexPath];
+        EmptyGatewayCell *emptyCell = (EmptyGatewayCell *)cell;
+        [emptyCell.addGatewayButton addTarget:self action:@selector(addButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
+        [emptyCell.emptyGatewayButton addTarget:self action:@selector(addButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
+    }
+    
+    if ([cell respondsToSelector:@selector(changeLayoutForIphone5)]) {
+        [cell performSelector:@selector(changeLayoutForIphone5)];
+    }
+    
+    return cell;
+}
+
+#pragma mark - UICollectionViewDelegate
+- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
+    [collectionView deselectItemAtIndexPath:indexPath animated:YES];
+    
+    [self setGatewayCellAsSelectedWithIndex:indexPath.item];
+}
+
+#pragma mark - UIScrollViewDelegate
+- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
+    int page = (int)(scrollView.contentOffset.x / kCellWidth);
+    if (page != self.pageControl.currentPage) {
+        [self updatePageControlCurrentPage:page];
+        [self updateCurrentGatewayIndex:page];
+        [self setGatewayCellAsSelectedWithIndex:page];
+    }
+}
+
+#pragma mark - GatewaySettingDelegate
+- (void)didFinishedEdit:(BOOL)isNew {
+    NSInteger totalPages = [self.model numberOfGateways];
+    NSInteger currentPage = 0;
+    if (isNew) {
+        currentPage = totalPages-1;
+        [self updateCurrentGatewayIndex:currentPage];
+
+        if (totalPages == 1) {
+            [self reloadWithAnimation];
+        } else {
+            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:currentPage inSection:0];
+            [self.collectionView insertItemsAtIndexPaths:@[indexPath]];
+        }
+        
+        [self updatePageControlNumbers:totalPages];
+    } else {
+        currentPage = self.pageControl.currentPage;
+        [self updateCurrentGatewayIndex:currentPage];
+        
+        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:currentPage inSection:0];
+        [self.collectionView reloadItemsAtIndexPaths:@[indexPath]];
+    }
+    
+    [self setGatewayCellAsSelectedWithIndex:currentPage];
+    
+    if (isNew) {
+        
+        [self.collectionView setContentSize:CGSizeMake(currentPage * kScreenWidth, kScreenHeight)];
+        [self.collectionView setContentOffset:CGPointMake(currentPage * kScreenWidth, 0) animated:YES];
+    }
+}
+
+#pragma mark - GatewayCellDelegate
+- (void)didStartLogin:(NSString *)gatewayTitle cell:(UICollectionViewCell *)cell {
+    
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameGateway];
+    [userDefaults removeObjectForKey:KEY_OAUTH_URL];
+    [userDefaults removeObjectForKey:@"dns_list"];
+    
+    [AAAManager sharedInstance].resources = @"";
+    
+    self.webAuthUrl = @"";
+    self.isAutoLogin = NO;
+    self.isLocalDB = YES;
+    [Singleton sharedSingleton].isAuthentication = NO;
+    
+    if ([cell respondsToSelector:@selector(addShadow)]) {
+        [cell performSelector:@selector(addShadow)];
+    }
+    
+    _loginCell = (GatewayCell *)cell;
+    [self.collectionView setScrollEnabled:NO];
+    
+    Gateway *currentGateway = [self.model currentGateway];
+    if (!currentGateway.isWebAuthEnabled) {
+        [self.model login];
+    } else {
+        self.webAuthUrl = @"";
+        [self startWebAuth];
+    }
+}
+
+- (void)didCancelLogin:(NSString *)gatewayTitle {
+    _loginCell = nil;
+    [self.collectionView setScrollEnabled:YES];
+    [self.model cancelLogin];
+}
+
+- (void)willDeleteGateway:(NSString *)gatewayUrl {
+    if (!gatewayUrl) {
+        ANError(@"Gateway URL is nil, can't be deleted.");
+        return;
+    }
+    if (![gatewayUrl isEqualToString:[self.model currentGateway].url]) {
+        ANInfo(@"Gateway \"%@\" is not current gateway, don't delete.", gatewayUrl);
+        return;
+    }
+    
+    __weak typeof(self) weakSelf = self;
+    PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Delete", nil)
+                                                                  message:NSLocalizedString(@"Are you sure to delete this site?", nil)
+                                                            confirmAction:^{
+                                                                Gateway *gateway = [weakSelf.model currentGateway];
+                                                                if (!gateway) {
+                                                                    ANError(@"Can't find gateway named \"%@\".", gatewayUrl);
+                                                                    return;
+                                                                } else {
+                                                                    [weakSelf deleteGateway];
+                                                                }
+                                                            }
+                                                             cancelAction:nil];
+    [self presentViewController:popup animated:YES completion:nil];
+}
+
+- (void)willEditGateway:(NSString *)gatewayUrl andPort:(NSString *)gatewayPort {
+    Gateway *gateway = [self.model gatewayOfUrl:gatewayUrl andPort:gatewayPort];
+    [self performSegueWithIdentifier:kSegueToSettings sender:gateway];
+}
+
+#pragma mark - WebAuth
+- (void)startWebAuth {
+    [self webAuthConfig];
+    ZTWebAuthViewController *control = [[ZTWebAuthViewController alloc] init];
+    control.infoDic = [self webAuthConfig];
+    [self.navigationController pushViewController:control animated:YES];
+}
+
+#pragma mark - Login Handler
+- (void)didFinishLogin:(BOOL)success {
+    [_loginCell setAsNormal];
+    
+    [self.collectionView setScrollEnabled:YES];
+    
+    if (success) {
+        [self.model didAccessCurrentGateway];
+        
+        [_loginCell setAccessDate:[self.model currentGatewayAccessDate]];  // Update gateway cell after login.
+        
+        [self performSegueWithIdentifier:kSegueToResource sender:self];
+    }
+}
+
+- (void)continueLoginWithUrl:(NSString *)url callback:(NSString *)callback {
+    self.webAuthUrl = url;
+    self.callbackUrl = callback;
+    [_loginCell setAsLoggingIn];
+    
+    if (url) {
+        [self.model didAccessCurrentGateway];
+        
+        [_loginCell setAccessDate:[self.model currentGatewayAccessDate]];
+        [self startWebAuth];
+    }
+}
+
+#pragma mark - Auto Login Handler
+- (void)perpareForAutoLogin:(void (^)(void))completion {
+    completion();
+}
+
+- (void)didReceiveLoginRequest:(VPNAccount *)account {
+    if (!account) {
+        return;
+    }
+    
+    _loginAccount = account;
+    
+    __weak __typeof(self) weakSelf = self;
+    [self perpareForAutoLogin:^{
+        [weakSelf sendAutoLogoutNotification];
+        [weakSelf doRealAutoLogin];
+    }];
+    
+}
+
+- (void)didReceiveLoginRequest:(VPNAccount *)account oauthreq:(NSString *)request oauthcode:(NSString *)code {
+    NSString *urlString = nil;
+    if ([account.vsPort isEqualToString:@"443"]) {
+        urlString = [NSString stringWithFormat:@"https://%@%@%@?code=%@", account.vsHost, OAUTH_SESSION_URL, request, code];
+    } else {
+        urlString = [NSString stringWithFormat:@"https://%@:%@%@%@?code=%@", account.vsHost, account.vsPort, OAUTH_SESSION_URL, request, code];
+    }
+    ANInfo(@"didReceiveLoginRequest:continue login url=%@", urlString);
+    [self continueLoginWithUrl:urlString callback:account.autoLoginCallback];
+}
+
+- (void)handleVPNTunnelError:(NSNotification *)notification {
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    NSString *errMessage = [vpnWrapper getErrorMsgWithCode];
+    if (errMessage && errMessage.length > 0) {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:errMessage];
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+- (void)didReceiveLoginRequest:(VPNAccount *)account session:(NSString *)sess {
+    if (!sess || sess.length <= 0) {
+        ANWarn(@"Can't create secure tunnel with empty session.");
+        return;
+    }
+    
+    [self triggerNetworkFlowWithHost:account.vsHost andPort:account.vsPort];
+    
+    ANDebug(@"Secure tunnel will be created with session.");
+    AAAManager *manager = [AAAManager sharedInstance];
+    manager.account = account;
+    [manager setSessionID:sess];
+    
+#if TARGET_OS_IPHONE
+        //Reset connect fail reason.
+        NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameGateway];
+        [userDefaults removeObjectForKey:@"tunnel_result"];
+#endif
+    [[ArrayVPNWrapper sharedInstance] startSSLVPN];
+    
+#if TARGET_OS_IPHONE
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleVPNTunnelError:)
+                                                 name:kArrayVPNTunelErrorMsgGateway object:nil];
+#endif
+}
+
+- (void)doRealAutoLogin {
+    if (!_loginAccount) return;
+    
+    __weak __typeof(self) weakSelf = self;
+    [self.navigationController.view startLoadingWithMessage:@"Connecting..."
+                                                buttonTitle:NSLocalizedString(@"Cancel", nil)
+                                               cancelAction:^{
+                                                   [weakSelf.model cancelLogin];
+                                               }];
+    
+    [self.model autoLoginwithAccount:_loginAccount];
+}
+
+- (void)logoutThenLogin {
+    __weak __typeof(self) weakSelf = self;
+    
+    [self.model logoutCurrentSession:^{
+        ANDebug(@"Logout successfully, do login");
+        
+        [self sendAutoLogoutNotification];
+        // Wait 1 second for l3vpn thread to stop.
+        [weakSelf performSelector:@selector(doRealAutoLogin) withObject:nil afterDelay:1];
+    }];
+}
+
+- (void)autoLoginFailed:(NSString *)errorMessage {
+    if (!errorMessage) {
+        return;
+    }
+    
+    ANInfo(@"Login failed: %@", errorMessage);
+    
+    PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                   message:errorMessage
+                                                             confirmAction:nil
+                                                              cancelAction:nil];
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)didReceiveDisconnectRequest:(VPNAccount *)account IsLogout:(BOOL)islogout {
+    ANInfo(@"Receive logout request");
+    
+    [self sendAutoLogoutNotification];
+    
+    Gateway *gateway = [[GatewayManager sharedInstance] gatewayOfUrl:account.vsURL andport:account.vsPort];
+    if (!gateway) {  // MPP has been launched by URLScheme with session.
+        ANDebug(@"Secure tunnel will be destoryed with session.");
+        
+        [[ArrayVPNWrapper sharedInstance] stopSSLVPN];
+        if (islogout) {
+            NSInteger ret = [[AAAManager sharedInstance] logoutL3VPNSession];
+            if (ret != ERR_SUCCESS) {
+                ANError(@"Logout failed with error code: %zi.", ret);
+            }
+        }
+    }
+}
+
+- (void)sendAutoLogoutNotification {
+    [[NSNotificationCenter defaultCenter] postNotificationName:kAutoLogoutNotification object:nil];
+}
+
+/**
+ *  This method is meaningful only on first time launched by URLScheme with session after installed from AppStore.
+ *  Cuz it needs the user to allow MPP app to use network privilege, it MUST have network flow. So, it make
+ *  a simple "HEAD" http request here, and the result is not cared about.
+ */
+- (void)triggerNetworkFlowWithHost:(NSString *)host andPort:(NSString *)port {
+    NSString *realPort = @"443";
+    
+    if (!host || host.length == 0) {
+        return;
+    }
+    
+    if (port && port.length > 0) {
+        realPort = port;
+    }
+    
+    NSString *urlString = [NSString stringWithFormat:@"https://%@:%@", host, realPort];
+    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
+    request.HTTPMethod = @"HEAD";
+    NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:nil];
+    [connection start];
+    
+    ANDebug(@"A http request has been sent for auto-login. URL is: %@.", urlString);
+}
+
+- (void)autoConnectWithOauthCode:(NSNotification *)notification {
+    NSString *code =[notification.userInfo objectForKey:@"code"];
+    
+    if (code.length <= 0) {
+        ANError(@"autoConnectWithOauthCode: Get oAuth code failed.");
+        
+        return;
+    }
+    
+    ANInfo(@"autoConnectWithOauthCode: get oauth code successfully=%@", code);
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameGateway];
+    NSString *oauthUrl = [userDefaults valueForKey:KEY_OAUTH_URL];
+    if (oauthUrl.length <= 0) {
+        ANError(@"autoConnectWithOauthCode: Get saved oauth url failed.");
+        
+        return;
+    }
+    oauthUrl = [NSString stringWithFormat:@"%@%@", oauthUrl, code];
+    ANInfo(@"autoConnectWithOauthCode: connect with oauth url=%@", oauthUrl);
+    [self continueLoginWithUrl:oauthUrl callback:nil];
+}
+
+#pragma mark - GatewayModelDelegate
+- (void)needLoginInfo {
+    
+    BOOL isAuth = [Singleton sharedSingleton].isAuthentication;
+    Gateway *gateway = [self.model currentGateway];
+    
+    if (isAuth || gateway.isRadiusPWD){
+        
+        [self performSegueWithIdentifier:kSegueToLogin sender:self];
+    }else{
+        
+        [self checkVerifyMothod];
+    }
+}
+
+- (void)needRegister {
+    [self performSegueWithIdentifier:kSegueToLogin sender:self];
+}
+
+- (void)needConfirm:(NSString *)message {
+    __weak typeof(self) weakSelf = self;
+    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil message:message preferredStyle:UIAlertControllerStyleActionSheet];
+    UIAlertAction *alertActionDestructive = [UIAlertAction actionWithTitle:NSLocalizedString(@"Continue, but never show me this again", nil)
+                                                                     style:UIAlertActionStyleDestructive
+                                                                   handler:^(UIAlertAction *action){
+                                                                       [weakSelf.model suppressCheckServerCertForCurrentGateway];
+                                                                       [weakSelf.model continueLogin];
+                                                                   }];
+    UIAlertAction *alertActionDefault = [UIAlertAction actionWithTitle:NSLocalizedString(@"Continue", nil)
+                                                                 style:UIAlertActionStyleDefault
+                                                               handler:^(UIAlertAction *action){
+                                                                   [weakSelf.model continueLogin];
+                                                               }];
+    UIAlertAction *alertActionCancel = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
+                                                                style:UIAlertActionStyleCancel
+                                                              handler:^(UIAlertAction *action){
+                                                                  [weakSelf didFinishLogin:NO];
+                                                              }];
+    [alertController addAction:alertActionDestructive];
+    [alertController addAction:alertActionDefault];
+    [alertController addAction:alertActionCancel];
+    UIPopoverPresentationController *popover = alertController.popoverPresentationController;
+    if (popover){
+        popover.sourceView = self.view;
+        popover.sourceRect = CGRectMake(self.view.bounds.size.width/2.0, self.view.bounds.size.height, 1.0, 1.0);
+        popover.permittedArrowDirections = UIPopoverArrowDirectionAny;
+    }
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [self presentViewController:alertController animated:YES completion:nil];
+    });
+}
+
+- (void)needLogout {
+    ANInfo(@"Need logout current session");
+    
+    __weak typeof(self) weakSelf = self;
+    NSString *message = [NSString stringWithFormat:NSLocalizedString(@"There is currently an active connection to %@, you can disconnect the current session,\
+                                                                     and start a new connection, or display the active connection.", nil),
+                                                                    [AAAManager sharedInstance].account.vsHost];
+    PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+                                                                   message:message
+                                                              confirmTitle:NSLocalizedString(@"Active Connection",nil)
+                                                               cancelTitle:NSLocalizedString(@"New Connection", nil)
+                                                             confirmAction:^{
+                                                                 [weakSelf logoutThenLogin];
+                                                             }
+                                                              cancelAction:nil];
+    
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)needVDIAuth {
+    __weak typeof(self) weakSelf = self;
+    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"VDI Credential", nil)
+                                                                             message:NSLocalizedString(@"Please input username and password", nil)
+                                                                      preferredStyle:UIAlertControllerStyleAlert];
+    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
+                                                           style:UIAlertActionStyleCancel
+                                                         handler:^(UIAlertAction * _Nonnull action) {
+                                                             [weakSelf.model loginWithVDIUsername:nil password:nil];
+                                                         }];
+    UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
+                                                            style:UIAlertActionStyleDefault
+                                                          handler:^(UIAlertAction * _Nonnull action) {
+                                                              NSString *username = alertController.textFields[0].text;  // Username text field
+                                                              NSString *password = alertController.textFields[1].text;  // Password text field
+                                                              username = [username stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
+                                                              
+                                                              [weakSelf.model loginWithVDIUsername:username password:password];
+                                                          }];
+    
+    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = NSLocalizedString(@"Username", nil);
+    }];
+    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = NSLocalizedString(@"Password", nil);
+    }];
+    [alertController addAction:confirmAction];
+    [alertController addAction:cancelAction];
+    
+    [self presentViewController:alertController animated:YES completion:nil];
+}
+
+- (void)needDoPreLoginCV {
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{
+        [[RulesManager sharedInstance].interactionHandler takeAction];
+    });
+}
+
+- (void)loginError:(NSString *)message {
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [self didFinishLogin:NO];
+    });
+    if (!message) {
+        return;
+    }
+    
+    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:message];
+    
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)loginErrorOfTip:(NSString *)message {
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [self didFinishLogin:NO];
+    });
+    if (!message) {
+        return;
+    }
+    
+    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Tips",nil) message:message];
+    
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)loginFinished:(BOOL)success {
+    [self didFinishLogin:success];
+    
+    [self.navigationController.view stopLoading];
+}
+
+- (void)checkVerifyMothod {
+    Gateway *gateway = [self.model currentGateway];
+    NSString *username = gateway.username;
+    NSString *port = gateway.port;
+    
+    _realPasswords = @[@"", @"", @""];
+    NSDictionary *methodDic = [Singleton getCurrentGatewayMethod:[self.model currentGateway]];
+    NSString *lastName = [methodDic objectForKey:@"userName"] ?: @"";
+    if ([username isEqualToString:@""]){
+        
+        username = lastName;
+    }
+    
+    if (username != nil) {
+        if (!gateway.lastAccessedDate) {  // Prevent from getting saved password after reinstall.
+            [PasswordManager removePasswordsOfHost:gateway.host username:username port:port];
+        }
+        if ([username isEqualToString:lastName] && (gateway.isGestureEnabled || gateway.isFaceOrTouchIDEnabled)) {
+            
+            _realPasswords = [PasswordManager passwordsOfHost:gateway.host username:username port:port];
+            if (![_realPasswords isEqual:@[@"", @"", @""]]){
+                
+                [self mutilVerifyMothod];
+                return;
+            }
+        } else {
+            ANDebug(@"delete user \"%@\" password", username?username:@"nil");
+            [Singleton setCurrentGatewayMethod:@{} andKey:gateway];
+        }
+    }
+    [self performSegueWithIdentifier:kSegueToLogin sender:self];
+}
+
+#pragma mark - 生物认证 手势认证
+-(void) mutilVerifyMothod
+{
+    Gateway *gw = [self.model currentGateway];
+    if (gw.isFaceOrTouchIDEnabled || gw.isGestureEnabled){
+        
+        [Singleton sharedSingleton].isAuthentication = YES;
+        LocalAuthFinishBlockType completeBlock = ^(BOOL isAllow, SecuritySettingOption authType){
+            
+            [Singleton sharedSingleton].isAuthentication = isAllow;
+            if (isAllow){
+                
+                self.isAutoLogin = YES;
+                [self login];
+            }
+        };
+        UIViewController *control = [LocalAuthUtil getAuthVCWithCompletion:completeBlock];
+        control.modalPresentationStyle = UIModalPresentationFullScreen;
+        [self presentViewController:control animated:YES completion:nil];
+    }
+}
+
+- (void)login {
+    
+    VPNAccount *account = [self inputResult];
+    
+    if (account == nil) {
+        ANWarn(@"Cannot get account information");
+        return;
+    }
+    
+    InformationToSave *info = [InformationToSave sharedInstance];
+    
+    info.lastLoginAccount = account;
+    [info save];
+    
+    AAAManager *manager = [AAAManager sharedInstance];
+    manager.errorCode = 0; // Success
+    [manager continueVPNThreadWithAccount:account];
+}
+
+- (VPNAccount *)inputResult {
+    
+    AAAManager *manager = [AAAManager sharedInstance];
+    
+    VPNAccount * account = manager.account;
+    
+    NSDictionary *methodDic = [Singleton getCurrentGatewayMethod:[self.model currentGatewayUpInside]];
+    
+    NSString *methodType = [methodDic objectForKey:@"methodType"];
+    if ([methodType isEqualToString:@"0"]){
+        
+        [Singleton sharedSingleton].isSupportAuth = YES;
+    }else{
+        
+        [Singleton sharedSingleton].isSupportAuth = NO;
+    }
+    
+    account.loginMethod = [methodDic objectForKey:@"methodName"] ?: @"";
+    account.userName = [methodDic objectForKey:@"userName"] ?: @"";
+    
+    account.passWord  = _realPasswords[0]  ?: @"";
+    account.passWord2 = _realPasswords[1]  ?: @"";
+    account.passWord3 = _realPasswords[2]  ?: @"";
+    
+    UIDevice *devInfo = [UIDevice currentDevice];
+    account.deviceName =[NSString stringWithFormat:@"%@|Apple;%@;iOS %@", devInfo.name, devInfo.platformString, devInfo.systemVersion];
+    
+    return account;
+}
+
+-(void) cancelConnection
+{
+    [self didFinishLogin:NO];
+    [[AAAManager sharedInstance] cancelLoginTapped];
+}
+
+-(void) jumpToLoginIn
+{
+    [self performSegueWithIdentifier:kSegueToLogin sender:self];
+}
+
+- (void)handleVPNNotification:(NSNotification *)notification {
+    //only faceid/touchid/gestuer auth
+    if (!self.isAutoLogin){
+        
+        return;
+    }
+    
+    VPNMessage *message = notification.object;
+    AAAManager *manager = [AAAManager sharedInstance];
+    NSInteger error = manager.errorCode;
+    NSString *aMessage;
+    
+    switch (message.code) {
+        case VPN_CB_CONNECTED: {
+            if (!self.isLocalDB){
+                
+                [self pop];
+            }
+            [self didFinishLogin:YES];
+            break;
+        }
+        case VPN_CB_DISCONNECTING: {
+            if (!self.isLocalDB){
+                
+                [self pop];
+            }
+            self.isAutoLogin = NO;
+            [self didFinishLogin:NO];
+            break;
+        }
+        case VPN_CB_CHALLENGE: {
+            self.isLocalDB = NO;
+            [self performSegueWithIdentifier:kSegueToChallenge sender:nil];
+            break;
+        }
+        case VPN_CB_CONN_FAILED: {
+            switch (error) {
+                case ERR_WRONG_USER_PASS:
+                    aMessage = manager.errorInformation;
+                    break;
+                case ERR_AUTHORIZE_FAILED:
+                    aMessage = NSLocalizedString(@"Login failed", nil);
+                    break;
+                case ERR_CALLBACK_FAILED:
+                    break;
+                case ERR_INTERRUPTED:
+                    break;
+                case ERR_CLIENT_SECURITY:
+                    aMessage = NSLocalizedString(@"Client security is not supported", nil);
+                    break;
+                case ERR_SMS_GET_PHONE:
+                    aMessage = NSLocalizedString(@"The system failed to get your phone number to do OTP authentication", nil);
+                    break;
+                case ERR_SMS_SEND:
+                    aMessage = NSLocalizedString(@"The system failed to send message to your phone", nil);
+                    break;
+                case ERR_SMS_TOO_MANY_RETRY:
+                    aMessage = NSLocalizedString(@"Your attempt to sign in failed, because you have entered wrong SMS verification code for too many times", nil);
+                    break;
+                case ERR_HWID_DENY:
+                    aMessage = NSLocalizedString(@"The device is denied because of wrong hardware ID!", nil);
+                    break;
+                case ERR_HWID_PENDING:
+                    aMessage = NSLocalizedString(@"The hardware ID of this device is not approved yet!", nil);
+                    break;
+                default:
+                    ANError(@"Login failed with error message: %@", aMessage);
+                    break;
+            }
+            
+            Gateway *gw = [[[GatewayModel alloc] init] currentGatewayUpInside];
+            if (!gw.isShowLoginDialogEnabled) {
+                if (aMessage && aMessage.length > 0) {
+                    if (![aMessage containsString:@"<a href='"]) {
+                        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:aMessage];
+                        [self presentViewController:dialog animated:YES completion:nil];
+                    } else {
+                        ANInfo(@"Connect failed:Error message=%@", aMessage);
+                        NSRange subStrRange = [aMessage rangeOfString:@"<a href='"];
+                        NSMutableString *finalMessage = [NSMutableString stringWithString:aMessage];
+                        [finalMessage deleteCharactersInRange:NSMakeRange(subStrRange.location, (int)strlen("<a href='"))];
+                        NSString *displayMessage = [finalMessage substringToIndex:[finalMessage rangeOfString:@"'>"].location];
+                        ANInfo(@"Connect failed:Display message=%@", displayMessage);
+                        
+                        NSString *URLMessage = [aMessage substringFromIndex:(subStrRange.location + subStrRange.length)];
+                        URLMessage = [URLMessage substringToIndex:[URLMessage rangeOfString:@"'>"].location];
+                        ANInfo(@"URL message=%@", URLMessage);
+                        
+                        PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil) message:displayMessage confirmAction:^{
+                                                                    NSURL *url = [NSURL URLWithString:URLMessage];
+                                                                    OpenURL(url);
+                                                                    }
+                                                        cancelAction:nil];
+                        [self presentViewController:popup animated:YES completion:nil];
+                    }
+                }
+            }
+            
+            break;
+        }
+        case VPN_CB_LOGIN:{
+            if (error == ERR_WRONG_USER_PASS || error == ERR_USER_LOCKED) {
+                __weak typeof(self) weakSelf = self;
+                if (![manager.errorInformation containsString:@"<a href='"]) {
+                    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                                  message:[self loginFailedMessage:error]
+                                                                                   action:^{
+                                                                                       [weakSelf showLoginActivity:NO];
+                                                                                   }];
+                    [self presentViewController:dialog animated:YES completion:nil];
+                } else {
+                    ANInfo(@"Error message=%@", manager.errorInformation);
+                    NSRange subStrRange = [manager.errorInformation rangeOfString:@"<a href='"];
+                    NSMutableString *finalMessage = [NSMutableString stringWithString:manager.errorInformation];
+                    [finalMessage deleteCharactersInRange:NSMakeRange(subStrRange.location, (int)strlen("<a href='"))];
+                    NSString *displayMessage = [finalMessage substringToIndex:[finalMessage rangeOfString:@"'>"].location];
+                    ANInfo(@"Display message=%@", displayMessage);
+                    
+                    NSString *URLMessage = [manager.errorInformation substringFromIndex:(subStrRange.location + subStrRange.length)];
+                    URLMessage = [URLMessage substringToIndex:[URLMessage rangeOfString:@"'>"].location];
+                    ANInfo(@"URL message=%@", URLMessage);
+                    
+                    PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil) message:displayMessage confirmAction:^{
+                                                                NSURL *url = [NSURL URLWithString:URLMessage];
+                                                                OpenURL(url);
+                                                                [weakSelf showLoginActivity:NO];
+                        
+                                                                // If password is wrong, pop to root view.
+                                                                [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                }
+                                               cancelAction:^{
+                                                                [weakSelf showLoginActivity:NO];
+                                                                // If password is wrong, pop to root view.
+                                                                [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                }];
+                    [self presentViewController:popup animated:YES completion:nil];
+                }
+            } else if (error == ERR_AUTHORIZE_FAILED) {
+                PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@""
+                                                                              message:NSLocalizedString(@"Authorize failed",nil)];
+                [self presentViewController:dialog animated:YES completion:nil];
+                
+            }
+        }
+        case VPN_CB_SMS: {
+            self.isLocalDB = NO;
+            if ([self.navigationController.topViewController isKindOfClass:[SMSViewController class]]) {
+                [self refreshTopView];
+            } else {
+                [self performSegueWithIdentifier:kSegueToSMS sender:nil];
+            }
+            break;
+        }
+        case VPN_CB_CHANGPASSWORD: {
+            self.isLocalDB = NO;
+            [self performSegueWithIdentifier:kSegueToChangePassword sender:nil];
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+- (NSString *)loginFailedMessage:(NSInteger)errorCode {
+    AAAManager *manager = [AAAManager sharedInstance];
+    
+    if (errorCode == ERR_USER_LOCKED) {
+        NSString *errorMessage = manager.errorInformation;
+        if (errorMessage && errorMessage.length > 0) {
+            return errorMessage;
+        }
+    }
+    
+    NSString *errorMessage = manager.errorInformation;
+    if (errorMessage && errorMessage.length > 0) {
+        return errorMessage;
+    }
+    
+    // Return this string for all login error (incorrect username or password) except SMX auth.
+    return NSLocalizedString(@"Login failed, please check username and password", nil);
+}
+
+- (void)refreshTopView {
+    UIViewController *top = [self.navigationController topViewController];
+    SEL handler = NSSelectorFromString(@"refreshView");
+    if ([top respondsToSelector:handler]) {
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+        [top performSelector:handler];
+    }
+}
+
+- (void)pop {
+    if (self.navigationController.viewControllers.count > 1) {
+        [self.navigationController popViewControllerAnimated:YES];
+    }else{
+        [self dismissViewControllerAnimated:YES completion:nil];
+    }
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewayViewController.m.InfosecStore
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewayViewController.m.InfosecStore	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewayViewController.m.InfosecStore	(working copy)
@@ -0,0 +1,1184 @@
+//
+//  GatewayViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/10.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "YCXMenu.h"
+#import "ANLogger.h"
+#import "ANPopupDialog.h"
+#import "AutoLoginHandler.h"
+#import "ArrayVPNWrapper.h"
+#import "GatewayModel.h"
+#import "GatewayCell.h"
+#import "UIView+Loading.h"
+#import "LoginViewController.h"
+#import "ResourcesViewController.h"
+#import "RulesManager.h"
+#import "EmptyGatewayCell.h"
+#import "GatewayViewLayout.h"
+#import "GatewayViewController.h"
+#import "GatewaySettingsViewController.h"
+#import "LocalAuthUtil.h"
+#import "PasswordManager.h"
+#import "InformationToSave.h"
+#import "UIDevice+Hardware.h"
+#import "Singleton.h"
+#import "UIViewController+Activity.h"
+#import "SMSViewController.h"
+#import "ZTWebAuthViewController.h"
+
+static NSString * const kSegueToChallenge = @"LoginToChallenge";
+static NSString * const kSegueToSMS = @"LoginToSMS";
+static NSString * const kSegueToChangePassword = @"LoginToChangePassword";
+
+typedef NS_ENUM(NSInteger, MenuIndex) {
+    kMenuIndexLog = 0,
+    kMenuIndexAbout
+};
+
+#define OAUTH_SESSION_URL               @"/prx/000/http/localh/"
+#define CancelConnection               @"CancelConnection"
+#define JumpToLoginIn                  @"jumpToLoginIn"
+
+#if TARGET_OS_IPHONE
+NSString * const kAppGroupNameGateway = @"group.net.infosec.MotionPro";
+NSString * const kArrayVPNTunelErrorMsgGateway = @"net.arraynetworks.sslvpn.errormsg";
+NSString * const koAuthSetCodeGateway = @"net.arraynetworks.oauthsetcode";
+#elif TARGET_OS_MAC
+NSString * const kAppGroupNameGateway = @"5VZLZ3YQ9P.net.arraynetworks.MacTunnel";
+#endif
+
+static NSString * const kSegueToSettings = @"GatewayToSettings";
+static NSString * const kSegueToLogin = @"GatewayToLogin";
+static NSString * const kSegueToResource = @"GatewayToResource";
+static NSString * const kSegueToAbout = @"GatewayToAbout";
+static NSString * const kSegueToLogSettings = @"GatewayToLogSettings";
+static NSString * const kSegueToWebAuth = @"GatewayToWebAuth";
+
+@interface GatewayViewController () <UIScrollViewDelegate, LoginControllerDelegate, GatewaySettingDelegate, GatewayCellDelegate, GatewayModelDelegate,
+AutoLoginHandlerDelegate, GatewayModelDelegate> {
+    VPNAccount  *_loginAccount;
+    GatewayCell *_loginCell;
+    AutoLoginHandler *_autoLoginHandler;
+}
+
+@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
+@property (weak, nonatomic) IBOutlet UIPageControl *pageControl;
+@property (weak, nonatomic) IBOutlet UIBarButtonItem *addGatewayButton;
+@property (weak, nonatomic) IBOutlet UIBarButtonItem *moreButton;
+
+@property (strong, nonatomic) GatewayModel *model;
+@property (nonatomic, strong) NSString     *webAuthUrl;
+@property (nonatomic, strong) NSString     *callbackUrl;
+@property (nonatomic, strong) NSArray      *realPasswords;
+@property (nonatomic, assign) BOOL         isAutoLogin;
+@property (nonatomic, assign) BOOL         isLocalDB;  //Only the biometric authentication screen is displayed
+
+@end
+
+@implementation GatewayViewController
+
+- (void)dealloc {
+    self.model = nil;
+#if TARGET_OS_IPHONE
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:kArrayVPNTunelErrorMsgGateway object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:koAuthSetCodeGateway object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:CancelConnection object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:JumpToLoginIn object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:kVPNMessageNotification object:nil];
+#endif
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    self.model = [[GatewayModel alloc] init];
+    self.model.delegate = self;
+    
+    [self initNavigationBarAppearance];
+    [self initCollectionView];
+    [self initPageControl];
+    [self initButtonItems];
+#if TARGET_OS_IPHONE
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(autoConnectWithOauthCode:) name:koAuthSetCodeGateway object:nil];
+   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cancelConnection) name:CancelConnection object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jumpToLoginIn) name:JumpToLoginIn object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleVPNNotification:) name:kVPNMessageNotification object:nil];
+#endif
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    
+    static dispatch_once_t onceToken;
+    
+    if (!_autoLoginHandler) {
+        _autoLoginHandler = [[AutoLoginHandler alloc] initWithDelegate:self];
+    }
+    
+    if (_autoLoginHandler.url) {
+        // If autolaunch, do not show add gateway view.
+        dispatch_once(&onceToken, ^{
+            [_autoLoginHandler readyToAutoLogin];
+        });
+        return;
+    }
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([segue.identifier isEqualToString:kSegueToAbout] || [segue.identifier isEqualToString:kSegueToLogSettings] || [segue.identifier isEqualToString:kSegueToChallenge] || [segue.identifier isEqualToString:kSegueToChangePassword] ||
+        [segue.identifier isEqualToString:kSegueToSMS]) {
+        return;  // These destinations doesn't need more setting.
+    }
+    
+    id<ANViewControllerSwitchProtocol> p = nil;
+    NSDictionary *option = nil;
+    
+    UINavigationController *destNavivation = (UINavigationController *)segue.destinationViewController;
+    if (destNavivation.viewControllers.count > 0) {
+        p = [destNavivation.viewControllers firstObject];
+    } else {
+        ANError(@"Can't find destination view controller.");
+        return;
+    }
+    
+    if ([segue.identifier isEqualToString:kSegueToSettings]) {
+        if ([sender isKindOfClass:[Gateway class]]) {
+            option = @{@"gateway": sender};
+        }
+        [p switchFromSender:self withOption:option];
+    } else if ([segue.identifier isEqualToString:kSegueToLogin]) {
+        [p switchFromSender:self withOption:nil];
+    }
+}
+
+-(NSDictionary *) webAuthConfig
+{
+    NSDictionary *option = nil;
+    Gateway *gateway = [self.model currentGateway];
+    __weak typeof(self) weakSelf = self;
+    void (^competion)(NSError *error, NSString *session, NSString *username, NSString *acsInfo) = ^(NSError *error, NSString *session, NSString *username, NSString *acsInfo) {
+        __strong typeof(weakSelf) strongSelf = weakSelf;
+        
+        ANInfo(@"Error: %@, Session:%@, username:%@, oauth acsInfo:%@", error, session, username, acsInfo);
+        
+        if (session && session.length > 0) {
+            if (acsInfo && acsInfo.length > 0) {
+                AAAManager *manager = [AAAManager sharedInstance];
+                [manager setOAuthAcsInfo:acsInfo];
+            }
+            if (self.webAuthUrl && [self.webAuthUrl length] > 0) {
+                [strongSelf.model loginWithSession:session andUsername:username andoAuthURL:self.webAuthUrl andcallbackURL:self.callbackUrl];
+            } else {
+                [strongSelf.model loginWithSession:session andUsername:username];
+            }
+        } else {
+            [strongSelf didFinishLogin:NO];
+        };
+        
+        if (error) {
+            NSString *message = NSLocalizedString(@"Connection to server failed", nil);
+            PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                          message:message];
+            [strongSelf presentViewController:dialog animated:YES completion:nil];
+        }
+    };
+    
+    option = @{@"host": gateway.host,
+               @"port": gateway.port,
+               @"alias": gateway.alias,
+               @"url": self.webAuthUrl,
+               @"completion": competion
+               };
+    
+    return option;
+}
+
+- (void)addButtonClicked:(id)sender {
+    [self performSegueWithIdentifier:kSegueToSettings sender:self];
+}
+
+- (void)moreButtonClicked:(id)sender {
+    YCXMenuItem *logItem = [YCXMenuItem menuItem:NSLocalizedString(@"Log", nil)
+                                           image:[UIImage imageNamed:@"GatewayLog"]
+                                             tag:kMenuIndexLog
+                                        userInfo:nil];
+    [logItem setForeColor:UIColorFromRGBA(0x666666, 1.0)];
+    
+    YCXMenuItem *aboutItem = [YCXMenuItem menuItem:NSLocalizedString(@"About", nil)
+                                             image:[UIImage imageNamed:@"GatewayAbout"]
+                                               tag:kMenuIndexAbout
+                                          userInfo:nil];
+    [aboutItem setForeColor:UIColorFromRGBA(0x666666, 1.0)];
+    NSArray *items = @[logItem, aboutItem];
+    
+    [YCXMenu setTintColor:[UIColor whiteColor]];
+    [YCXMenu setSeparatorColor:UIColorFromRGBA(0xe2e2e2, 1.0)];
+    [YCXMenu setSelectedColor:UIColorFromRGBA(0xe2e2e2, 1.0)];
+    [YCXMenu setCornerRadius:CGFLOAT_MIN];
+    if ([YCXMenu isShow]){
+        [YCXMenu dismissMenu];
+    } else {
+        [YCXMenu showMenuInView:self.view fromRect:CGRectMake(self.view.frame.size.width - 60, 0, 60, 0) menuItems:items selected:^(NSInteger index, YCXMenuItem *item) {
+            if (index == kMenuIndexLog) {
+                [self performSegueWithIdentifier:kSegueToLogSettings sender:nil];
+            } else if (index == kMenuIndexAbout) {
+                [self performSegueWithIdentifier:kSegueToAbout sender:nil];
+            }
+        }];
+    }
+}
+
+- (void)initNavigationBarAppearance {
+    // To make the black line under navigation bar disappear (for iOS11).
+    [[UINavigationBar appearance] setBackgroundImage:[[UIImage alloc] init] forBarMetrics:UIBarMetricsDefault];
+    [[UINavigationBar appearance] setShadowImage:[[UIImage alloc] init]];
+}
+
+- (void)initCollectionView {
+    // Register cells.
+    [self.collectionView registerNib:[UINib nibWithNibName:@"EmptyGatewayCell" bundle:nil]
+          forCellWithReuseIdentifier:kEmptyGatewayCellID];
+    [self.collectionView registerNib:[UINib nibWithNibName:@"GatewayCell" bundle:nil]
+          forCellWithReuseIdentifier:kGatewayCellID];
+    // Setup layout class.
+    [self.collectionView setCollectionViewLayout:[[GatewayViewLayout alloc] init]];
+    
+    self.collectionView.allowsSelection = YES;
+    self.collectionView.decelerationRate = 0.994;  // Between UIScrollViewDecelerationRateNormal and UIScrollViewDecelerationRateFast
+}
+
+- (void)initPageControl {
+    [self setPageControlAppearance];
+    self.pageControl.userInteractionEnabled = NO;
+    
+    NSInteger totalGateways = [self.model numberOfGateways];
+    if (totalGateways <= 0) {
+        self.pageControl.hidden = YES;
+    } else {
+        self.pageControl.hidden = NO;
+        self.pageControl.numberOfPages = totalGateways;
+        self.pageControl.currentPage = 0;
+    }
+}
+
+- (void)updatePageControlNumbers:(NSInteger)totalPages {
+    self.pageControl.hidden = totalPages > 0 ? NO : YES;
+    self.pageControl.numberOfPages = totalPages;
+}
+
+- (void)updatePageControlCurrentPage:(NSInteger)index {
+    NSInteger total = self.pageControl.numberOfPages;
+    if (index >= total || index < 0) {
+        ANDebug(@"Index \(%zi) of page control is out of page numbers \(%zi)", index, total);
+        return;
+    } else {
+        self.pageControl.currentPage = index;
+    }
+}
+
+- (void)updateCurrentGatewayIndex:(NSInteger)index {
+    [self.model selectGatewayAtIndex:index];
+    [Singleton sharedSingleton].currentPageNumber = index;
+}
+
+- (void)setGatewayCellAsSelectedWithIndex:(NSInteger)index {
+    [self clearGatewayCellsShadow];
+    
+    [self setCurrentCellShadowWithIndex:index];
+}
+
+- (void)clearGatewayCellsShadow {
+    for (UICollectionViewCell *cell in self.collectionView.visibleCells) {
+        if (cell) {
+            if ([cell respondsToSelector:@selector(clearShadow)]) {
+                [cell performSelector:@selector(clearShadow)];
+            }
+        }
+    }
+}
+
+- (void)setCurrentCellShadowWithIndex:(NSInteger)index {
+    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
+    GatewayCell *currentCell = (GatewayCell *)[self.collectionView cellForItemAtIndexPath:indexPath];
+    if (currentCell) {
+        if ([currentCell respondsToSelector:@selector(addShadow)]) {
+            [currentCell performSelector:@selector(addShadow)];
+        }
+    }
+}
+
+- (void)initButtonItems {
+    [self.addGatewayButton setTarget:self];
+    [self.addGatewayButton setAction:@selector(addButtonClicked:)];
+    
+    [self.moreButton setTarget:self];
+    [self.moreButton setAction:@selector(moreButtonClicked:)];
+}
+
+- (void)setPageControlAppearance {
+    self.pageControl.pageIndicatorTintColor = UIColorFromRGBA(0x999999, 1.0);
+    self.pageControl.currentPageIndicatorTintColor = MAIN_COLOR;
+}
+
+- (void)reloadWithAnimation {
+    [UIView transitionWithView:self.collectionView
+                      duration:0.3
+                       options:UIViewAnimationOptionTransitionCrossDissolve
+                    animations:^{
+                        [self.collectionView reloadData];
+                    }
+                    completion:nil];
+}
+
+- (void)deleteGateway {
+    [self.model deleteCurrentGateway];
+
+    NSInteger total = [self.model numberOfGateways];
+    if (total == 0) {
+        [self updateCurrentGatewayIndex:0];
+        [self reloadWithAnimation];
+    } else{
+        
+        NSInteger integer = 0;
+        if (self.pageControl.currentPage == total){
+            
+            integer = self.pageControl.currentPage - 1;
+        }else{
+            
+            integer = self.pageControl.currentPage;
+        }
+        
+        [self updateCurrentGatewayIndex:integer];
+        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.pageControl.currentPage inSection:0];
+        [self.collectionView deleteItemsAtIndexPaths:@[indexPath]];
+    }
+    
+    [SecuritySetting clearGesture];
+    [self updatePageControlNumbers:[self.model numberOfGateways]];
+}
+
+#pragma mark - UICollectionViewDataSource
+- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
+    NSInteger totalGateways = [self.model numberOfGateways];
+    
+    return totalGateways > 0 ? totalGateways : 1;
+}
+
+- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
+    UICollectionViewCell *cell = nil;
+    NSInteger totalGateways = [self.model numberOfGateways];
+    
+    if (totalGateways > 0) {
+        cell = [collectionView dequeueReusableCellWithReuseIdentifier:kGatewayCellID forIndexPath:indexPath];
+        Gateway *gateway = [self.model gatewayAtIndex:indexPath.row];
+        if (gateway) {
+            [(GatewayCell *)cell configureWithGateway:gateway delegate:self];
+        }
+    } else {
+        cell = [collectionView dequeueReusableCellWithReuseIdentifier:kEmptyGatewayCellID forIndexPath:indexPath];
+        EmptyGatewayCell *emptyCell = (EmptyGatewayCell *)cell;
+        [emptyCell.addGatewayButton addTarget:self action:@selector(addButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
+        [emptyCell.emptyGatewayButton addTarget:self action:@selector(addButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
+    }
+    
+    if ([cell respondsToSelector:@selector(changeLayoutForIphone5)]) {
+        [cell performSelector:@selector(changeLayoutForIphone5)];
+    }
+    
+    return cell;
+}
+
+#pragma mark - UICollectionViewDelegate
+- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
+    [collectionView deselectItemAtIndexPath:indexPath animated:YES];
+    
+    [self setGatewayCellAsSelectedWithIndex:indexPath.item];
+}
+
+#pragma mark - UIScrollViewDelegate
+- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
+    int page = (int)(scrollView.contentOffset.x / kCellWidth);
+    if (page != self.pageControl.currentPage) {
+        [self updatePageControlCurrentPage:page];
+        [self updateCurrentGatewayIndex:page];
+        [self setGatewayCellAsSelectedWithIndex:page];
+    }
+}
+
+#pragma mark - GatewaySettingDelegate
+- (void)didFinishedEdit:(BOOL)isNew {
+    NSInteger totalPages = [self.model numberOfGateways];
+    NSInteger currentPage = 0;
+    if (isNew) {
+        currentPage = totalPages-1;
+        [self updateCurrentGatewayIndex:currentPage];
+
+        if (totalPages == 1) {
+            [self reloadWithAnimation];
+        } else {
+            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:currentPage inSection:0];
+            [self.collectionView insertItemsAtIndexPaths:@[indexPath]];
+        }
+        
+        [self updatePageControlNumbers:totalPages];
+    } else {
+        currentPage = self.pageControl.currentPage;
+        [self updateCurrentGatewayIndex:currentPage];
+        
+        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:currentPage inSection:0];
+        [self.collectionView reloadItemsAtIndexPaths:@[indexPath]];
+    }
+    
+    [self setGatewayCellAsSelectedWithIndex:currentPage];
+    
+    if (isNew) {
+        
+        [self.collectionView setContentSize:CGSizeMake(currentPage * kScreenWidth, kScreenHeight)];
+        [self.collectionView setContentOffset:CGPointMake(currentPage * kScreenWidth, 0) animated:YES];
+    }
+}
+
+#pragma mark - GatewayCellDelegate
+- (void)didStartLogin:(NSString *)gatewayTitle cell:(UICollectionViewCell *)cell {
+    
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameGateway];
+    [userDefaults removeObjectForKey:KEY_OAUTH_URL];
+    [userDefaults removeObjectForKey:@"dns_list"];
+    
+    [AAAManager sharedInstance].resources = @"";
+    
+    self.webAuthUrl = @"";
+    self.isAutoLogin = NO;
+    self.isLocalDB = YES;
+    [Singleton sharedSingleton].isAuthentication = NO;
+    
+    if ([cell respondsToSelector:@selector(addShadow)]) {
+        [cell performSelector:@selector(addShadow)];
+    }
+    
+    _loginCell = (GatewayCell *)cell;
+    [self.collectionView setScrollEnabled:NO];
+    
+    Gateway *currentGateway = [self.model currentGateway];
+    if (!currentGateway.isWebAuthEnabled) {
+        [self.model login];
+    } else {
+        self.webAuthUrl = @"";
+        [self startWebAuth];
+    }
+}
+
+- (void)didCancelLogin:(NSString *)gatewayTitle {
+    _loginCell = nil;
+    [self.collectionView setScrollEnabled:YES];
+    [self.model cancelLogin];
+}
+
+- (void)willDeleteGateway:(NSString *)gatewayUrl {
+    if (!gatewayUrl) {
+        ANError(@"Gateway URL is nil, can't be deleted.");
+        return;
+    }
+    if (![gatewayUrl isEqualToString:[self.model currentGateway].url]) {
+        ANInfo(@"Gateway \"%@\" is not current gateway, don't delete.", gatewayUrl);
+        return;
+    }
+    
+    __weak typeof(self) weakSelf = self;
+    PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Delete", nil)
+                                                                  message:NSLocalizedString(@"Are you sure to delete this site?", nil)
+                                                            confirmAction:^{
+                                                                Gateway *gateway = [weakSelf.model currentGateway];
+                                                                if (!gateway) {
+                                                                    ANError(@"Can't find gateway named \"%@\".", gatewayUrl);
+                                                                    return;
+                                                                } else {
+                                                                    [weakSelf deleteGateway];
+                                                                }
+                                                            }
+                                                             cancelAction:nil];
+    [self presentViewController:popup animated:YES completion:nil];
+}
+
+- (void)willEditGateway:(NSString *)gatewayUrl andPort:(NSString *)gatewayPort {
+    Gateway *gateway = [self.model gatewayOfUrl:gatewayUrl andPort:gatewayPort];
+    [self performSegueWithIdentifier:kSegueToSettings sender:gateway];
+}
+
+#pragma mark - WebAuth
+- (void)startWebAuth {
+    [self webAuthConfig];
+    ZTWebAuthViewController *control = [[ZTWebAuthViewController alloc] init];
+    control.infoDic = [self webAuthConfig];
+    [self.navigationController pushViewController:control animated:YES];
+}
+
+#pragma mark - Login Handler
+- (void)didFinishLogin:(BOOL)success {
+    [_loginCell setAsNormal];
+    
+    [self.collectionView setScrollEnabled:YES];
+    
+    if (success) {
+        [self.model didAccessCurrentGateway];
+        
+        [_loginCell setAccessDate:[self.model currentGatewayAccessDate]];  // Update gateway cell after login.
+        
+        [self performSegueWithIdentifier:kSegueToResource sender:self];
+    }
+}
+
+- (void)continueLoginWithUrl:(NSString *)url callback:(NSString *)callback {
+    self.webAuthUrl = url;
+    self.callbackUrl = callback;
+    [_loginCell setAsLoggingIn];
+    
+    if (url) {
+        [self.model didAccessCurrentGateway];
+        
+        [_loginCell setAccessDate:[self.model currentGatewayAccessDate]];
+        [self startWebAuth];
+    }
+}
+
+#pragma mark - Auto Login Handler
+- (void)perpareForAutoLogin:(void (^)(void))completion {
+    completion();
+}
+
+- (void)didReceiveLoginRequest:(VPNAccount *)account {
+    if (!account) {
+        return;
+    }
+    
+    _loginAccount = account;
+    
+    __weak __typeof(self) weakSelf = self;
+    [self perpareForAutoLogin:^{
+        [weakSelf sendAutoLogoutNotification];
+        [weakSelf doRealAutoLogin];
+    }];
+    
+}
+
+- (void)didReceiveLoginRequest:(VPNAccount *)account oauthreq:(NSString *)request oauthcode:(NSString *)code {
+    NSString *urlString = nil;
+    if ([account.vsPort isEqualToString:@"443"]) {
+        urlString = [NSString stringWithFormat:@"https://%@%@%@?code=%@", account.vsHost, OAUTH_SESSION_URL, request, code];
+    } else {
+        urlString = [NSString stringWithFormat:@"https://%@:%@%@%@?code=%@", account.vsHost, account.vsPort, OAUTH_SESSION_URL, request, code];
+    }
+    ANInfo(@"didReceiveLoginRequest:continue login url=%@", urlString);
+    [self continueLoginWithUrl:urlString callback:account.autoLoginCallback];
+}
+
+- (void)handleVPNTunnelError:(NSNotification *)notification {
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    NSString *errMessage = [vpnWrapper getErrorMsgWithCode];
+    if (errMessage && errMessage.length > 0) {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:errMessage];
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+- (void)didReceiveLoginRequest:(VPNAccount *)account session:(NSString *)sess {
+    if (!sess || sess.length <= 0) {
+        ANWarn(@"Can't create secure tunnel with empty session.");
+        return;
+    }
+    
+    [self triggerNetworkFlowWithHost:account.vsHost andPort:account.vsPort];
+    
+    ANDebug(@"Secure tunnel will be created with session.");
+    AAAManager *manager = [AAAManager sharedInstance];
+    manager.account = account;
+    [manager setSessionID:sess];
+    
+#if TARGET_OS_IPHONE
+        //Reset connect fail reason.
+        NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameGateway];
+        [userDefaults removeObjectForKey:@"tunnel_result"];
+#endif
+    [[ArrayVPNWrapper sharedInstance] startSSLVPN];
+    
+#if TARGET_OS_IPHONE
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleVPNTunnelError:)
+                                                 name:kArrayVPNTunelErrorMsgGateway object:nil];
+#endif
+}
+
+- (void)doRealAutoLogin {
+    if (!_loginAccount) return;
+    
+    __weak __typeof(self) weakSelf = self;
+    [self.navigationController.view startLoadingWithMessage:@"Connecting..."
+                                                buttonTitle:NSLocalizedString(@"Cancel", nil)
+                                               cancelAction:^{
+                                                   [weakSelf.model cancelLogin];
+                                               }];
+    
+    [self.model autoLoginwithAccount:_loginAccount];
+}
+
+- (void)logoutThenLogin {
+    __weak __typeof(self) weakSelf = self;
+    
+    [self.model logoutCurrentSession:^{
+        ANDebug(@"Logout successfully, do login");
+        
+        [self sendAutoLogoutNotification];
+        // Wait 1 second for l3vpn thread to stop.
+        [weakSelf performSelector:@selector(doRealAutoLogin) withObject:nil afterDelay:1];
+    }];
+}
+
+- (void)autoLoginFailed:(NSString *)errorMessage {
+    if (!errorMessage) {
+        return;
+    }
+    
+    ANInfo(@"Login failed: %@", errorMessage);
+    
+    PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                   message:errorMessage
+                                                             confirmAction:nil
+                                                              cancelAction:nil];
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)didReceiveDisconnectRequest:(VPNAccount *)account IsLogout:(BOOL)islogout {
+    ANInfo(@"Receive logout request");
+    
+    [self sendAutoLogoutNotification];
+    
+    Gateway *gateway = [[GatewayManager sharedInstance] gatewayOfUrl:account.vsURL andport:account.vsPort];
+    if (!gateway) {  // MPP has been launched by URLScheme with session.
+        ANDebug(@"Secure tunnel will be destoryed with session.");
+        
+        [[ArrayVPNWrapper sharedInstance] stopSSLVPN];
+        if (islogout) {
+            NSInteger ret = [[AAAManager sharedInstance] logoutL3VPNSession];
+            if (ret != ERR_SUCCESS) {
+                ANError(@"Logout failed with error code: %zi.", ret);
+            }
+        }
+    }
+}
+
+- (void)sendAutoLogoutNotification {
+    [[NSNotificationCenter defaultCenter] postNotificationName:kAutoLogoutNotification object:nil];
+}
+
+/**
+ *  This method is meaningful only on first time launched by URLScheme with session after installed from AppStore.
+ *  Cuz it needs the user to allow MPP app to use network privilege, it MUST have network flow. So, it make
+ *  a simple "HEAD" http request here, and the result is not cared about.
+ */
+- (void)triggerNetworkFlowWithHost:(NSString *)host andPort:(NSString *)port {
+    NSString *realPort = @"443";
+    
+    if (!host || host.length == 0) {
+        return;
+    }
+    
+    if (port && port.length > 0) {
+        realPort = port;
+    }
+    
+    NSString *urlString = [NSString stringWithFormat:@"https://%@:%@", host, realPort];
+    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
+    request.HTTPMethod = @"HEAD";
+    NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:nil];
+    [connection start];
+    
+    ANDebug(@"A http request has been sent for auto-login. URL is: %@.", urlString);
+}
+
+- (void)autoConnectWithOauthCode:(NSNotification *)notification {
+    NSString *code =[notification.userInfo objectForKey:@"code"];
+    
+    if (code.length <= 0) {
+        ANError(@"autoConnectWithOauthCode: Get oAuth code failed.");
+        
+        return;
+    }
+    
+    ANInfo(@"autoConnectWithOauthCode: get oauth code successfully=%@", code);
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameGateway];
+    NSString *oauthUrl = [userDefaults valueForKey:KEY_OAUTH_URL];
+    if (oauthUrl.length <= 0) {
+        ANError(@"autoConnectWithOauthCode: Get saved oauth url failed.");
+        
+        return;
+    }
+    oauthUrl = [NSString stringWithFormat:@"%@%@", oauthUrl, code];
+    ANInfo(@"autoConnectWithOauthCode: connect with oauth url=%@", oauthUrl);
+    [self continueLoginWithUrl:oauthUrl callback:nil];
+}
+
+#pragma mark - GatewayModelDelegate
+- (void)needLoginInfo {
+    
+    BOOL isAuth = [Singleton sharedSingleton].isAuthentication;
+    Gateway *gateway = [self.model currentGateway];
+    
+    if (isAuth || gateway.isRadiusPWD){
+        
+        [self performSegueWithIdentifier:kSegueToLogin sender:self];
+    }else{
+        
+        [self checkVerifyMothod];
+    }
+}
+
+- (void)needRegister {
+    [self performSegueWithIdentifier:kSegueToLogin sender:self];
+}
+
+- (void)needConfirm:(NSString *)message {
+    __weak typeof(self) weakSelf = self;
+    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil message:message preferredStyle:UIAlertControllerStyleActionSheet];
+    UIAlertAction *alertActionDestructive = [UIAlertAction actionWithTitle:NSLocalizedString(@"Continue, but never show me this again", nil)
+                                                                     style:UIAlertActionStyleDestructive
+                                                                   handler:^(UIAlertAction *action){
+                                                                       [weakSelf.model suppressCheckServerCertForCurrentGateway];
+                                                                       [weakSelf.model continueLogin];
+                                                                   }];
+    UIAlertAction *alertActionDefault = [UIAlertAction actionWithTitle:NSLocalizedString(@"Continue", nil)
+                                                                 style:UIAlertActionStyleDefault
+                                                               handler:^(UIAlertAction *action){
+                                                                   [weakSelf.model continueLogin];
+                                                               }];
+    UIAlertAction *alertActionCancel = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
+                                                                style:UIAlertActionStyleCancel
+                                                              handler:^(UIAlertAction *action){
+                                                                  [weakSelf didFinishLogin:NO];
+                                                              }];
+    [alertController addAction:alertActionDestructive];
+    [alertController addAction:alertActionDefault];
+    [alertController addAction:alertActionCancel];
+    UIPopoverPresentationController *popover = alertController.popoverPresentationController;
+    if (popover){
+        popover.sourceView = self.view;
+        popover.sourceRect = CGRectMake(self.view.bounds.size.width/2.0, self.view.bounds.size.height, 1.0, 1.0);
+        popover.permittedArrowDirections = UIPopoverArrowDirectionAny;
+    }
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [self presentViewController:alertController animated:YES completion:nil];
+    });
+}
+
+- (void)needLogout {
+    ANInfo(@"Need logout current session");
+    
+    __weak typeof(self) weakSelf = self;
+    NSString *message = [NSString stringWithFormat:NSLocalizedString(@"There is currently an active connection to %@, you can disconnect the current session,\
+                                                                     and start a new connection, or display the active connection.", nil),
+                                                                    [AAAManager sharedInstance].account.vsHost];
+    PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+                                                                   message:message
+                                                              confirmTitle:NSLocalizedString(@"Active Connection",nil)
+                                                               cancelTitle:NSLocalizedString(@"New Connection", nil)
+                                                             confirmAction:^{
+                                                                 [weakSelf logoutThenLogin];
+                                                             }
+                                                              cancelAction:nil];
+    
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)needVDIAuth {
+    __weak typeof(self) weakSelf = self;
+    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"VDI Credential", nil)
+                                                                             message:NSLocalizedString(@"Please input username and password", nil)
+                                                                      preferredStyle:UIAlertControllerStyleAlert];
+    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
+                                                           style:UIAlertActionStyleCancel
+                                                         handler:^(UIAlertAction * _Nonnull action) {
+                                                             [weakSelf.model loginWithVDIUsername:nil password:nil];
+                                                         }];
+    UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
+                                                            style:UIAlertActionStyleDefault
+                                                          handler:^(UIAlertAction * _Nonnull action) {
+                                                              NSString *username = alertController.textFields[0].text;  // Username text field
+                                                              NSString *password = alertController.textFields[1].text;  // Password text field
+                                                              username = [username stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
+                                                              
+                                                              [weakSelf.model loginWithVDIUsername:username password:password];
+                                                          }];
+    
+    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = NSLocalizedString(@"Username", nil);
+    }];
+    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = NSLocalizedString(@"Password", nil);
+    }];
+    [alertController addAction:confirmAction];
+    [alertController addAction:cancelAction];
+    
+    [self presentViewController:alertController animated:YES completion:nil];
+}
+
+- (void)needDoPreLoginCV {
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{
+        [[RulesManager sharedInstance].interactionHandler takeAction];
+    });
+}
+
+- (void)loginError:(NSString *)message {
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [self didFinishLogin:NO];
+    });
+    if (!message) {
+        return;
+    }
+    
+    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:message];
+    
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)loginErrorOfTip:(NSString *)message {
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [self didFinishLogin:NO];
+    });
+    if (!message) {
+        return;
+    }
+    
+    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Tips",nil) message:message];
+    
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)loginFinished:(BOOL)success {
+    [self didFinishLogin:success];
+    
+    [self.navigationController.view stopLoading];
+}
+
+- (void)checkVerifyMothod {
+    Gateway *gateway = [self.model currentGateway];
+    NSString *username = gateway.username;
+    NSString *port = gateway.port;
+    
+    _realPasswords = @[@"", @"", @""];
+    NSDictionary *methodDic = [Singleton getCurrentGatewayMethod:[self.model currentGateway]];
+    NSString *lastName = [methodDic objectForKey:@"userName"] ?: @"";
+    if ([username isEqualToString:@""]){
+        
+        username = lastName;
+    }
+    
+    if (username != nil) {
+        if (!gateway.lastAccessedDate) {  // Prevent from getting saved password after reinstall.
+            [PasswordManager removePasswordsOfHost:gateway.host username:username port:port];
+        }
+        if ([username isEqualToString:lastName] && (gateway.isGestureEnabled || gateway.isFaceOrTouchIDEnabled)) {
+            
+            _realPasswords = [PasswordManager passwordsOfHost:gateway.host username:username port:port];
+            if (![_realPasswords isEqual:@[@"", @"", @""]]){
+                
+                [self mutilVerifyMothod];
+                return;
+            }
+        } else {
+            ANDebug(@"delete user \"%@\" password", username?username:@"nil");
+            [Singleton setCurrentGatewayMethod:@{} andKey:gateway];
+        }
+    }
+    [self performSegueWithIdentifier:kSegueToLogin sender:self];
+}
+
+#pragma mark - 生物认证 手势认证
+-(void) mutilVerifyMothod
+{
+    Gateway *gw = [self.model currentGateway];
+    if (gw.isFaceOrTouchIDEnabled || gw.isGestureEnabled){
+        
+        [Singleton sharedSingleton].isAuthentication = YES;
+        LocalAuthFinishBlockType completeBlock = ^(BOOL isAllow, SecuritySettingOption authType){
+            
+            [Singleton sharedSingleton].isAuthentication = isAllow;
+            if (isAllow){
+                
+                self.isAutoLogin = YES;
+                [self login];
+            }
+        };
+        UIViewController *control = [LocalAuthUtil getAuthVCWithCompletion:completeBlock];
+        control.modalPresentationStyle = UIModalPresentationFullScreen;
+        [self presentViewController:control animated:YES completion:nil];
+    }
+}
+
+- (void)login {
+    
+    VPNAccount *account = [self inputResult];
+    
+    if (account == nil) {
+        ANWarn(@"Cannot get account information");
+        return;
+    }
+    
+    InformationToSave *info = [InformationToSave sharedInstance];
+    
+    info.lastLoginAccount = account;
+    [info save];
+    
+    AAAManager *manager = [AAAManager sharedInstance];
+    manager.errorCode = 0; // Success
+    [manager continueVPNThreadWithAccount:account];
+}
+
+- (VPNAccount *)inputResult {
+    
+    AAAManager *manager = [AAAManager sharedInstance];
+    
+    VPNAccount * account = manager.account;
+    
+    NSDictionary *methodDic = [Singleton getCurrentGatewayMethod:[self.model currentGatewayUpInside]];
+    
+    NSString *methodType = [methodDic objectForKey:@"methodType"];
+    if ([methodType isEqualToString:@"0"]){
+        
+        [Singleton sharedSingleton].isSupportAuth = YES;
+    }else{
+        
+        [Singleton sharedSingleton].isSupportAuth = NO;
+    }
+    
+    account.loginMethod = [methodDic objectForKey:@"methodName"] ?: @"";
+    account.userName = [methodDic objectForKey:@"userName"] ?: @"";
+    
+    account.passWord  = _realPasswords[0]  ?: @"";
+    account.passWord2 = _realPasswords[1]  ?: @"";
+    account.passWord3 = _realPasswords[2]  ?: @"";
+    
+    UIDevice *devInfo = [UIDevice currentDevice];
+    account.deviceName =[NSString stringWithFormat:@"%@|Apple;%@;iOS %@", devInfo.name, devInfo.platformString, devInfo.systemVersion];
+    
+    return account;
+}
+
+-(void) cancelConnection
+{
+    [self didFinishLogin:NO];
+    [[AAAManager sharedInstance] cancelLoginTapped];
+}
+
+-(void) jumpToLoginIn
+{
+    [self performSegueWithIdentifier:kSegueToLogin sender:self];
+}
+
+- (void)handleVPNNotification:(NSNotification *)notification {
+    //only faceid/touchid/gestuer auth
+    if (!self.isAutoLogin){
+        
+        return;
+    }
+    
+    VPNMessage *message = notification.object;
+    AAAManager *manager = [AAAManager sharedInstance];
+    NSInteger error = manager.errorCode;
+    NSString *aMessage;
+    
+    switch (message.code) {
+        case VPN_CB_CONNECTED: {
+            if (!self.isLocalDB){
+                
+                [self pop];
+            }
+            [self didFinishLogin:YES];
+            break;
+        }
+        case VPN_CB_DISCONNECTING: {
+            if (!self.isLocalDB){
+                
+                [self pop];
+            }
+            self.isAutoLogin = NO;
+            [self didFinishLogin:NO];
+            break;
+        }
+        case VPN_CB_CHALLENGE: {
+            self.isLocalDB = NO;
+            [self performSegueWithIdentifier:kSegueToChallenge sender:nil];
+            break;
+        }
+        case VPN_CB_CONN_FAILED: {
+            switch (error) {
+                case ERR_WRONG_USER_PASS:
+                    aMessage = manager.errorInformation;
+                    break;
+                case ERR_AUTHORIZE_FAILED:
+                    aMessage = NSLocalizedString(@"Login failed", nil);
+                    break;
+                case ERR_CALLBACK_FAILED:
+                    break;
+                case ERR_INTERRUPTED:
+                    break;
+                case ERR_CLIENT_SECURITY:
+                    aMessage = NSLocalizedString(@"Client security is not supported", nil);
+                    break;
+                case ERR_SMS_GET_PHONE:
+                    aMessage = NSLocalizedString(@"The system failed to get your phone number to do OTP authentication", nil);
+                    break;
+                case ERR_SMS_SEND:
+                    aMessage = NSLocalizedString(@"The system failed to send message to your phone", nil);
+                    break;
+                case ERR_SMS_TOO_MANY_RETRY:
+                    aMessage = NSLocalizedString(@"Your attempt to sign in failed, because you have entered wrong SMS verification code for too many times", nil);
+                    break;
+                case ERR_HWID_DENY:
+                    aMessage = NSLocalizedString(@"The device is denied because of wrong hardware ID!", nil);
+                    break;
+                case ERR_HWID_PENDING:
+                    aMessage = NSLocalizedString(@"The hardware ID of this device is not approved yet!", nil);
+                    break;
+                default:
+                    ANError(@"Login failed with error message: %@", aMessage);
+                    break;
+            }
+            
+            Gateway *gw = [[[GatewayModel alloc] init] currentGatewayUpInside];
+            if (!gw.isShowLoginDialogEnabled) {
+                if (aMessage && aMessage.length > 0) {
+                    if (![aMessage containsString:@"<a href='"]) {
+                        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:aMessage];
+                        [self presentViewController:dialog animated:YES completion:nil];
+                    } else {
+                        ANInfo(@"Connect failed:Error message=%@", aMessage);
+                        NSRange subStrRange = [aMessage rangeOfString:@"<a href='"];
+                        NSMutableString *finalMessage = [NSMutableString stringWithString:aMessage];
+                        [finalMessage deleteCharactersInRange:NSMakeRange(subStrRange.location, (int)strlen("<a href='"))];
+                        NSString *displayMessage = [finalMessage substringToIndex:[finalMessage rangeOfString:@"'>"].location];
+                        ANInfo(@"Connect failed:Display message=%@", displayMessage);
+                        
+                        NSString *URLMessage = [aMessage substringFromIndex:(subStrRange.location + subStrRange.length)];
+                        URLMessage = [URLMessage substringToIndex:[URLMessage rangeOfString:@"'>"].location];
+                        ANInfo(@"URL message=%@", URLMessage);
+                        
+                        PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil) message:displayMessage confirmAction:^{
+                                                                    NSURL *url = [NSURL URLWithString:URLMessage];
+                                                                    OpenURL(url);
+                                                                    }
+                                                        cancelAction:nil];
+                        [self presentViewController:popup animated:YES completion:nil];
+                    }
+                }
+            }
+            
+            break;
+        }
+        case VPN_CB_LOGIN:{
+            if (error == ERR_WRONG_USER_PASS || error == ERR_USER_LOCKED) {
+                __weak typeof(self) weakSelf = self;
+                if (![manager.errorInformation containsString:@"<a href='"]) {
+                    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                                  message:[self loginFailedMessage:error]
+                                                                                   action:^{
+                                                                                       [weakSelf showLoginActivity:NO];
+                                                                                   }];
+                    [self presentViewController:dialog animated:YES completion:nil];
+                } else {
+                    ANInfo(@"Error message=%@", manager.errorInformation);
+                    NSRange subStrRange = [manager.errorInformation rangeOfString:@"<a href='"];
+                    NSMutableString *finalMessage = [NSMutableString stringWithString:manager.errorInformation];
+                    [finalMessage deleteCharactersInRange:NSMakeRange(subStrRange.location, (int)strlen("<a href='"))];
+                    NSString *displayMessage = [finalMessage substringToIndex:[finalMessage rangeOfString:@"'>"].location];
+                    ANInfo(@"Display message=%@", displayMessage);
+                    
+                    NSString *URLMessage = [manager.errorInformation substringFromIndex:(subStrRange.location + subStrRange.length)];
+                    URLMessage = [URLMessage substringToIndex:[URLMessage rangeOfString:@"'>"].location];
+                    ANInfo(@"URL message=%@", URLMessage);
+                    
+                    PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil) message:displayMessage confirmAction:^{
+                                                                NSURL *url = [NSURL URLWithString:URLMessage];
+                                                                OpenURL(url);
+                                                                [weakSelf showLoginActivity:NO];
+                        
+                                                                // If password is wrong, pop to root view.
+                                                                [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                }
+                                               cancelAction:^{
+                                                                [weakSelf showLoginActivity:NO];
+                                                                // If password is wrong, pop to root view.
+                                                                [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                }];
+                    [self presentViewController:popup animated:YES completion:nil];
+                }
+            } else if (error == ERR_AUTHORIZE_FAILED) {
+                PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@""
+                                                                              message:NSLocalizedString(@"Authorize failed",nil)];
+                [self presentViewController:dialog animated:YES completion:nil];
+                
+            }
+        }
+        case VPN_CB_SMS: {
+            self.isLocalDB = NO;
+            if ([self.navigationController.topViewController isKindOfClass:[SMSViewController class]]) {
+                [self refreshTopView];
+            } else {
+                [self performSegueWithIdentifier:kSegueToSMS sender:nil];
+            }
+            break;
+        }
+        case VPN_CB_CHANGPASSWORD: {
+            self.isLocalDB = NO;
+            [self performSegueWithIdentifier:kSegueToChangePassword sender:nil];
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+- (NSString *)loginFailedMessage:(NSInteger)errorCode {
+    AAAManager *manager = [AAAManager sharedInstance];
+    
+    if (errorCode == ERR_USER_LOCKED) {
+        NSString *errorMessage = manager.errorInformation;
+        if (errorMessage && errorMessage.length > 0) {
+            return errorMessage;
+        }
+    }
+    
+    NSString *errorMessage = manager.errorInformation;
+    if (errorMessage && errorMessage.length > 0) {
+        return errorMessage;
+    }
+    
+    // Return this string for all login error (incorrect username or password) except SMX auth.
+    return NSLocalizedString(@"Login failed, please check username and password", nil);
+}
+
+- (void)refreshTopView {
+    UIViewController *top = [self.navigationController topViewController];
+    SEL handler = NSSelectorFromString(@"refreshView");
+    if ([top respondsToSelector:handler]) {
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+        [top performSelector:handler];
+    }
+}
+
+- (void)pop {
+    if (self.navigationController.viewControllers.count > 1) {
+        [self.navigationController popViewControllerAnimated:YES];
+    }else{
+        [self dismissViewControllerAnimated:YES completion:nil];
+    }
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewayViewController.m.MotionPro
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewayViewController.m.MotionPro	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewayViewController.m.MotionPro	(working copy)
@@ -0,0 +1,1184 @@
+//
+//  GatewayViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/10.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "YCXMenu.h"
+#import "ANLogger.h"
+#import "ANPopupDialog.h"
+#import "AutoLoginHandler.h"
+#import "ArrayVPNWrapper.h"
+#import "GatewayModel.h"
+#import "GatewayCell.h"
+#import "UIView+Loading.h"
+#import "LoginViewController.h"
+#import "ResourcesViewController.h"
+#import "RulesManager.h"
+#import "EmptyGatewayCell.h"
+#import "GatewayViewLayout.h"
+#import "GatewayViewController.h"
+#import "GatewaySettingsViewController.h"
+#import "LocalAuthUtil.h"
+#import "PasswordManager.h"
+#import "InformationToSave.h"
+#import "UIDevice+Hardware.h"
+#import "Singleton.h"
+#import "UIViewController+Activity.h"
+#import "SMSViewController.h"
+#import "ZTWebAuthViewController.h"
+
+static NSString * const kSegueToChallenge = @"LoginToChallenge";
+static NSString * const kSegueToSMS = @"LoginToSMS";
+static NSString * const kSegueToChangePassword = @"LoginToChangePassword";
+
+typedef NS_ENUM(NSInteger, MenuIndex) {
+    kMenuIndexLog = 0,
+    kMenuIndexAbout
+};
+
+#define OAUTH_SESSION_URL               @"/prx/000/http/localh/"
+#define CancelConnection               @"CancelConnection"
+#define JumpToLoginIn                  @"jumpToLoginIn"
+
+#if TARGET_OS_IPHONE
+NSString * const kAppGroupNameGateway = @"group.net.arraynetworks.MotionPro";
+NSString * const kArrayVPNTunelErrorMsgGateway = @"net.arraynetworks.sslvpn.errormsg";
+NSString * const koAuthSetCodeGateway = @"net.arraynetworks.oauthsetcode";
+#elif TARGET_OS_MAC
+NSString * const kAppGroupNameGateway = @"5VZLZ3YQ9P.net.arraynetworks.MacTunnel";
+#endif
+
+static NSString * const kSegueToSettings = @"GatewayToSettings";
+static NSString * const kSegueToLogin = @"GatewayToLogin";
+static NSString * const kSegueToResource = @"GatewayToResource";
+static NSString * const kSegueToAbout = @"GatewayToAbout";
+static NSString * const kSegueToLogSettings = @"GatewayToLogSettings";
+static NSString * const kSegueToWebAuth = @"GatewayToWebAuth";
+
+@interface GatewayViewController () <UIScrollViewDelegate, LoginControllerDelegate, GatewaySettingDelegate, GatewayCellDelegate, GatewayModelDelegate,
+AutoLoginHandlerDelegate, GatewayModelDelegate> {
+    VPNAccount  *_loginAccount;
+    GatewayCell *_loginCell;
+    AutoLoginHandler *_autoLoginHandler;
+}
+
+@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
+@property (weak, nonatomic) IBOutlet UIPageControl *pageControl;
+@property (weak, nonatomic) IBOutlet UIBarButtonItem *addGatewayButton;
+@property (weak, nonatomic) IBOutlet UIBarButtonItem *moreButton;
+
+@property (strong, nonatomic) GatewayModel *model;
+@property (nonatomic, strong) NSString     *webAuthUrl;
+@property (nonatomic, strong) NSString     *callbackUrl;
+@property (nonatomic, strong) NSArray      *realPasswords;
+@property (nonatomic, assign) BOOL         isAutoLogin;
+@property (nonatomic, assign) BOOL         isLocalDB;  //Only the biometric authentication screen is displayed
+
+@end
+
+@implementation GatewayViewController
+
+- (void)dealloc {
+    self.model = nil;
+#if TARGET_OS_IPHONE
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:kArrayVPNTunelErrorMsgGateway object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:koAuthSetCodeGateway object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:CancelConnection object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:JumpToLoginIn object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:kVPNMessageNotification object:nil];
+#endif
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    self.model = [[GatewayModel alloc] init];
+    self.model.delegate = self;
+    
+    [self initNavigationBarAppearance];
+    [self initCollectionView];
+    [self initPageControl];
+    [self initButtonItems];
+#if TARGET_OS_IPHONE
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(autoConnectWithOauthCode:) name:koAuthSetCodeGateway object:nil];
+   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cancelConnection) name:CancelConnection object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jumpToLoginIn) name:JumpToLoginIn object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleVPNNotification:) name:kVPNMessageNotification object:nil];
+#endif
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    
+    static dispatch_once_t onceToken;
+    
+    if (!_autoLoginHandler) {
+        _autoLoginHandler = [[AutoLoginHandler alloc] initWithDelegate:self];
+    }
+    
+    if (_autoLoginHandler.url) {
+        // If autolaunch, do not show add gateway view.
+        dispatch_once(&onceToken, ^{
+            [_autoLoginHandler readyToAutoLogin];
+        });
+        return;
+    }
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([segue.identifier isEqualToString:kSegueToAbout] || [segue.identifier isEqualToString:kSegueToLogSettings] || [segue.identifier isEqualToString:kSegueToChallenge] || [segue.identifier isEqualToString:kSegueToChangePassword] ||
+        [segue.identifier isEqualToString:kSegueToSMS]) {
+        return;  // These destinations doesn't need more setting.
+    }
+    
+    id<ANViewControllerSwitchProtocol> p = nil;
+    NSDictionary *option = nil;
+    
+    UINavigationController *destNavivation = (UINavigationController *)segue.destinationViewController;
+    if (destNavivation.viewControllers.count > 0) {
+        p = [destNavivation.viewControllers firstObject];
+    } else {
+        ANError(@"Can't find destination view controller.");
+        return;
+    }
+    
+    if ([segue.identifier isEqualToString:kSegueToSettings]) {
+        if ([sender isKindOfClass:[Gateway class]]) {
+            option = @{@"gateway": sender};
+        }
+        [p switchFromSender:self withOption:option];
+    } else if ([segue.identifier isEqualToString:kSegueToLogin]) {
+        [p switchFromSender:self withOption:nil];
+    }
+}
+
+-(NSDictionary *) webAuthConfig
+{
+    NSDictionary *option = nil;
+    Gateway *gateway = [self.model currentGateway];
+    __weak typeof(self) weakSelf = self;
+    void (^competion)(NSError *error, NSString *session, NSString *username, NSString *acsInfo) = ^(NSError *error, NSString *session, NSString *username, NSString *acsInfo) {
+        __strong typeof(weakSelf) strongSelf = weakSelf;
+        
+        ANInfo(@"Error: %@, Session:%@, username:%@, oauth acsInfo:%@", error, session, username, acsInfo);
+        
+        if (session && session.length > 0) {
+            if (acsInfo && acsInfo.length > 0) {
+                AAAManager *manager = [AAAManager sharedInstance];
+                [manager setOAuthAcsInfo:acsInfo];
+            }
+            if (self.webAuthUrl && [self.webAuthUrl length] > 0) {
+                [strongSelf.model loginWithSession:session andUsername:username andoAuthURL:self.webAuthUrl andcallbackURL:self.callbackUrl];
+            } else {
+                [strongSelf.model loginWithSession:session andUsername:username];
+            }
+        } else {
+            [strongSelf didFinishLogin:NO];
+        };
+        
+        if (error) {
+            NSString *message = NSLocalizedString(@"Connection to server failed", nil);
+            PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                          message:message];
+            [strongSelf presentViewController:dialog animated:YES completion:nil];
+        }
+    };
+    
+    option = @{@"host": gateway.host,
+               @"port": gateway.port,
+               @"alias": gateway.alias,
+               @"url": self.webAuthUrl,
+               @"completion": competion
+               };
+    
+    return option;
+}
+
+- (void)addButtonClicked:(id)sender {
+    [self performSegueWithIdentifier:kSegueToSettings sender:self];
+}
+
+- (void)moreButtonClicked:(id)sender {
+    YCXMenuItem *logItem = [YCXMenuItem menuItem:NSLocalizedString(@"Log", nil)
+                                           image:[UIImage imageNamed:@"GatewayLog"]
+                                             tag:kMenuIndexLog
+                                        userInfo:nil];
+    [logItem setForeColor:UIColorFromRGBA(0x666666, 1.0)];
+    
+    YCXMenuItem *aboutItem = [YCXMenuItem menuItem:NSLocalizedString(@"About", nil)
+                                             image:[UIImage imageNamed:@"GatewayAbout"]
+                                               tag:kMenuIndexAbout
+                                          userInfo:nil];
+    [aboutItem setForeColor:UIColorFromRGBA(0x666666, 1.0)];
+    NSArray *items = @[logItem, aboutItem];
+    
+    [YCXMenu setTintColor:[UIColor whiteColor]];
+    [YCXMenu setSeparatorColor:UIColorFromRGBA(0xe2e2e2, 1.0)];
+    [YCXMenu setSelectedColor:UIColorFromRGBA(0xe2e2e2, 1.0)];
+    [YCXMenu setCornerRadius:CGFLOAT_MIN];
+    if ([YCXMenu isShow]){
+        [YCXMenu dismissMenu];
+    } else {
+        [YCXMenu showMenuInView:self.view fromRect:CGRectMake(self.view.frame.size.width - 60, 0, 60, 0) menuItems:items selected:^(NSInteger index, YCXMenuItem *item) {
+            if (index == kMenuIndexLog) {
+                [self performSegueWithIdentifier:kSegueToLogSettings sender:nil];
+            } else if (index == kMenuIndexAbout) {
+                [self performSegueWithIdentifier:kSegueToAbout sender:nil];
+            }
+        }];
+    }
+}
+
+- (void)initNavigationBarAppearance {
+    // To make the black line under navigation bar disappear (for iOS11).
+    [[UINavigationBar appearance] setBackgroundImage:[[UIImage alloc] init] forBarMetrics:UIBarMetricsDefault];
+    [[UINavigationBar appearance] setShadowImage:[[UIImage alloc] init]];
+}
+
+- (void)initCollectionView {
+    // Register cells.
+    [self.collectionView registerNib:[UINib nibWithNibName:@"EmptyGatewayCell" bundle:nil]
+          forCellWithReuseIdentifier:kEmptyGatewayCellID];
+    [self.collectionView registerNib:[UINib nibWithNibName:@"GatewayCell" bundle:nil]
+          forCellWithReuseIdentifier:kGatewayCellID];
+    // Setup layout class.
+    [self.collectionView setCollectionViewLayout:[[GatewayViewLayout alloc] init]];
+    
+    self.collectionView.allowsSelection = YES;
+    self.collectionView.decelerationRate = 0.994;  // Between UIScrollViewDecelerationRateNormal and UIScrollViewDecelerationRateFast
+}
+
+- (void)initPageControl {
+    [self setPageControlAppearance];
+    self.pageControl.userInteractionEnabled = NO;
+    
+    NSInteger totalGateways = [self.model numberOfGateways];
+    if (totalGateways <= 0) {
+        self.pageControl.hidden = YES;
+    } else {
+        self.pageControl.hidden = NO;
+        self.pageControl.numberOfPages = totalGateways;
+        self.pageControl.currentPage = 0;
+    }
+}
+
+- (void)updatePageControlNumbers:(NSInteger)totalPages {
+    self.pageControl.hidden = totalPages > 0 ? NO : YES;
+    self.pageControl.numberOfPages = totalPages;
+}
+
+- (void)updatePageControlCurrentPage:(NSInteger)index {
+    NSInteger total = self.pageControl.numberOfPages;
+    if (index >= total || index < 0) {
+        ANDebug(@"Index \(%zi) of page control is out of page numbers \(%zi)", index, total);
+        return;
+    } else {
+        self.pageControl.currentPage = index;
+    }
+}
+
+- (void)updateCurrentGatewayIndex:(NSInteger)index {
+    [self.model selectGatewayAtIndex:index];
+    [Singleton sharedSingleton].currentPageNumber = index;
+}
+
+- (void)setGatewayCellAsSelectedWithIndex:(NSInteger)index {
+    [self clearGatewayCellsShadow];
+    
+    [self setCurrentCellShadowWithIndex:index];
+}
+
+- (void)clearGatewayCellsShadow {
+    for (UICollectionViewCell *cell in self.collectionView.visibleCells) {
+        if (cell) {
+            if ([cell respondsToSelector:@selector(clearShadow)]) {
+                [cell performSelector:@selector(clearShadow)];
+            }
+        }
+    }
+}
+
+- (void)setCurrentCellShadowWithIndex:(NSInteger)index {
+    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
+    GatewayCell *currentCell = (GatewayCell *)[self.collectionView cellForItemAtIndexPath:indexPath];
+    if (currentCell) {
+        if ([currentCell respondsToSelector:@selector(addShadow)]) {
+            [currentCell performSelector:@selector(addShadow)];
+        }
+    }
+}
+
+- (void)initButtonItems {
+    [self.addGatewayButton setTarget:self];
+    [self.addGatewayButton setAction:@selector(addButtonClicked:)];
+    
+    [self.moreButton setTarget:self];
+    [self.moreButton setAction:@selector(moreButtonClicked:)];
+}
+
+- (void)setPageControlAppearance {
+    self.pageControl.pageIndicatorTintColor = UIColorFromRGBA(0x999999, 1.0);
+    self.pageControl.currentPageIndicatorTintColor = MAIN_COLOR;
+}
+
+- (void)reloadWithAnimation {
+    [UIView transitionWithView:self.collectionView
+                      duration:0.3
+                       options:UIViewAnimationOptionTransitionCrossDissolve
+                    animations:^{
+                        [self.collectionView reloadData];
+                    }
+                    completion:nil];
+}
+
+- (void)deleteGateway {
+    [self.model deleteCurrentGateway];
+
+    NSInteger total = [self.model numberOfGateways];
+    if (total == 0) {
+        [self updateCurrentGatewayIndex:0];
+        [self reloadWithAnimation];
+    } else{
+        
+        NSInteger integer = 0;
+        if (self.pageControl.currentPage == total){
+            
+            integer = self.pageControl.currentPage - 1;
+        }else{
+            
+            integer = self.pageControl.currentPage;
+        }
+        
+        [self updateCurrentGatewayIndex:integer];
+        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.pageControl.currentPage inSection:0];
+        [self.collectionView deleteItemsAtIndexPaths:@[indexPath]];
+    }
+    
+    [SecuritySetting clearGesture];
+    [self updatePageControlNumbers:[self.model numberOfGateways]];
+}
+
+#pragma mark - UICollectionViewDataSource
+- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
+    NSInteger totalGateways = [self.model numberOfGateways];
+    
+    return totalGateways > 0 ? totalGateways : 1;
+}
+
+- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
+    UICollectionViewCell *cell = nil;
+    NSInteger totalGateways = [self.model numberOfGateways];
+    
+    if (totalGateways > 0) {
+        cell = [collectionView dequeueReusableCellWithReuseIdentifier:kGatewayCellID forIndexPath:indexPath];
+        Gateway *gateway = [self.model gatewayAtIndex:indexPath.row];
+        if (gateway) {
+            [(GatewayCell *)cell configureWithGateway:gateway delegate:self];
+        }
+    } else {
+        cell = [collectionView dequeueReusableCellWithReuseIdentifier:kEmptyGatewayCellID forIndexPath:indexPath];
+        EmptyGatewayCell *emptyCell = (EmptyGatewayCell *)cell;
+        [emptyCell.addGatewayButton addTarget:self action:@selector(addButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
+        [emptyCell.emptyGatewayButton addTarget:self action:@selector(addButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
+    }
+    
+    if ([cell respondsToSelector:@selector(changeLayoutForIphone5)]) {
+        [cell performSelector:@selector(changeLayoutForIphone5)];
+    }
+    
+    return cell;
+}
+
+#pragma mark - UICollectionViewDelegate
+- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
+    [collectionView deselectItemAtIndexPath:indexPath animated:YES];
+    
+    [self setGatewayCellAsSelectedWithIndex:indexPath.item];
+}
+
+#pragma mark - UIScrollViewDelegate
+- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
+    int page = (int)(scrollView.contentOffset.x / kCellWidth);
+    if (page != self.pageControl.currentPage) {
+        [self updatePageControlCurrentPage:page];
+        [self updateCurrentGatewayIndex:page];
+        [self setGatewayCellAsSelectedWithIndex:page];
+    }
+}
+
+#pragma mark - GatewaySettingDelegate
+- (void)didFinishedEdit:(BOOL)isNew {
+    NSInteger totalPages = [self.model numberOfGateways];
+    NSInteger currentPage = 0;
+    if (isNew) {
+        currentPage = totalPages-1;
+        [self updateCurrentGatewayIndex:currentPage];
+
+        if (totalPages == 1) {
+            [self reloadWithAnimation];
+        } else {
+            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:currentPage inSection:0];
+            [self.collectionView insertItemsAtIndexPaths:@[indexPath]];
+        }
+        
+        [self updatePageControlNumbers:totalPages];
+    } else {
+        currentPage = self.pageControl.currentPage;
+        [self updateCurrentGatewayIndex:currentPage];
+        
+        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:currentPage inSection:0];
+        [self.collectionView reloadItemsAtIndexPaths:@[indexPath]];
+    }
+    
+    [self setGatewayCellAsSelectedWithIndex:currentPage];
+    
+    if (isNew) {
+        
+        [self.collectionView setContentSize:CGSizeMake(currentPage * kScreenWidth, kScreenHeight)];
+        [self.collectionView setContentOffset:CGPointMake(currentPage * kScreenWidth, 0) animated:YES];
+    }
+}
+
+#pragma mark - GatewayCellDelegate
+- (void)didStartLogin:(NSString *)gatewayTitle cell:(UICollectionViewCell *)cell {
+    
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameGateway];
+    [userDefaults removeObjectForKey:KEY_OAUTH_URL];
+    [userDefaults removeObjectForKey:@"dns_list"];
+    
+    [AAAManager sharedInstance].resources = @"";
+    
+    self.webAuthUrl = @"";
+    self.isAutoLogin = NO;
+    self.isLocalDB = YES;
+    [Singleton sharedSingleton].isAuthentication = NO;
+    
+    if ([cell respondsToSelector:@selector(addShadow)]) {
+        [cell performSelector:@selector(addShadow)];
+    }
+    
+    _loginCell = (GatewayCell *)cell;
+    [self.collectionView setScrollEnabled:NO];
+    
+    Gateway *currentGateway = [self.model currentGateway];
+    if (!currentGateway.isWebAuthEnabled) {
+        [self.model login];
+    } else {
+        self.webAuthUrl = @"";
+        [self startWebAuth];
+    }
+}
+
+- (void)didCancelLogin:(NSString *)gatewayTitle {
+    _loginCell = nil;
+    [self.collectionView setScrollEnabled:YES];
+    [self.model cancelLogin];
+}
+
+- (void)willDeleteGateway:(NSString *)gatewayUrl {
+    if (!gatewayUrl) {
+        ANError(@"Gateway URL is nil, can't be deleted.");
+        return;
+    }
+    if (![gatewayUrl isEqualToString:[self.model currentGateway].url]) {
+        ANInfo(@"Gateway \"%@\" is not current gateway, don't delete.", gatewayUrl);
+        return;
+    }
+    
+    __weak typeof(self) weakSelf = self;
+    PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Delete", nil)
+                                                                  message:NSLocalizedString(@"Are you sure to delete this site?", nil)
+                                                            confirmAction:^{
+                                                                Gateway *gateway = [weakSelf.model currentGateway];
+                                                                if (!gateway) {
+                                                                    ANError(@"Can't find gateway named \"%@\".", gatewayUrl);
+                                                                    return;
+                                                                } else {
+                                                                    [weakSelf deleteGateway];
+                                                                }
+                                                            }
+                                                             cancelAction:nil];
+    [self presentViewController:popup animated:YES completion:nil];
+}
+
+- (void)willEditGateway:(NSString *)gatewayUrl andPort:(NSString *)gatewayPort {
+    Gateway *gateway = [self.model gatewayOfUrl:gatewayUrl andPort:gatewayPort];
+    [self performSegueWithIdentifier:kSegueToSettings sender:gateway];
+}
+
+#pragma mark - WebAuth
+- (void)startWebAuth {
+    [self webAuthConfig];
+    ZTWebAuthViewController *control = [[ZTWebAuthViewController alloc] init];
+    control.infoDic = [self webAuthConfig];
+    [self.navigationController pushViewController:control animated:YES];
+}
+
+#pragma mark - Login Handler
+- (void)didFinishLogin:(BOOL)success {
+    [_loginCell setAsNormal];
+    
+    [self.collectionView setScrollEnabled:YES];
+    
+    if (success) {
+        [self.model didAccessCurrentGateway];
+        
+        [_loginCell setAccessDate:[self.model currentGatewayAccessDate]];  // Update gateway cell after login.
+        
+        [self performSegueWithIdentifier:kSegueToResource sender:self];
+    }
+}
+
+- (void)continueLoginWithUrl:(NSString *)url callback:(NSString *)callback {
+    self.webAuthUrl = url;
+    self.callbackUrl = callback;
+    [_loginCell setAsLoggingIn];
+    
+    if (url) {
+        [self.model didAccessCurrentGateway];
+        
+        [_loginCell setAccessDate:[self.model currentGatewayAccessDate]];
+        [self startWebAuth];
+    }
+}
+
+#pragma mark - Auto Login Handler
+- (void)perpareForAutoLogin:(void (^)(void))completion {
+    completion();
+}
+
+- (void)didReceiveLoginRequest:(VPNAccount *)account {
+    if (!account) {
+        return;
+    }
+    
+    _loginAccount = account;
+    
+    __weak __typeof(self) weakSelf = self;
+    [self perpareForAutoLogin:^{
+        [weakSelf sendAutoLogoutNotification];
+        [weakSelf doRealAutoLogin];
+    }];
+    
+}
+
+- (void)didReceiveLoginRequest:(VPNAccount *)account oauthreq:(NSString *)request oauthcode:(NSString *)code {
+    NSString *urlString = nil;
+    if ([account.vsPort isEqualToString:@"443"]) {
+        urlString = [NSString stringWithFormat:@"https://%@%@%@?code=%@", account.vsHost, OAUTH_SESSION_URL, request, code];
+    } else {
+        urlString = [NSString stringWithFormat:@"https://%@:%@%@%@?code=%@", account.vsHost, account.vsPort, OAUTH_SESSION_URL, request, code];
+    }
+    ANInfo(@"didReceiveLoginRequest:continue login url=%@", urlString);
+    [self continueLoginWithUrl:urlString callback:account.autoLoginCallback];
+}
+
+- (void)handleVPNTunnelError:(NSNotification *)notification {
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    NSString *errMessage = [vpnWrapper getErrorMsgWithCode];
+    if (errMessage && errMessage.length > 0) {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:errMessage];
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+- (void)didReceiveLoginRequest:(VPNAccount *)account session:(NSString *)sess {
+    if (!sess || sess.length <= 0) {
+        ANWarn(@"Can't create secure tunnel with empty session.");
+        return;
+    }
+    
+    [self triggerNetworkFlowWithHost:account.vsHost andPort:account.vsPort];
+    
+    ANDebug(@"Secure tunnel will be created with session.");
+    AAAManager *manager = [AAAManager sharedInstance];
+    manager.account = account;
+    [manager setSessionID:sess];
+    
+#if TARGET_OS_IPHONE
+        //Reset connect fail reason.
+        NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameGateway];
+        [userDefaults removeObjectForKey:@"tunnel_result"];
+#endif
+    [[ArrayVPNWrapper sharedInstance] startSSLVPN];
+    
+#if TARGET_OS_IPHONE
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleVPNTunnelError:)
+                                                 name:kArrayVPNTunelErrorMsgGateway object:nil];
+#endif
+}
+
+- (void)doRealAutoLogin {
+    if (!_loginAccount) return;
+    
+    __weak __typeof(self) weakSelf = self;
+    [self.navigationController.view startLoadingWithMessage:@"Connecting..."
+                                                buttonTitle:NSLocalizedString(@"Cancel", nil)
+                                               cancelAction:^{
+                                                   [weakSelf.model cancelLogin];
+                                               }];
+    
+    [self.model autoLoginwithAccount:_loginAccount];
+}
+
+- (void)logoutThenLogin {
+    __weak __typeof(self) weakSelf = self;
+    
+    [self.model logoutCurrentSession:^{
+        ANDebug(@"Logout successfully, do login");
+        
+        [self sendAutoLogoutNotification];
+        // Wait 1 second for l3vpn thread to stop.
+        [weakSelf performSelector:@selector(doRealAutoLogin) withObject:nil afterDelay:1];
+    }];
+}
+
+- (void)autoLoginFailed:(NSString *)errorMessage {
+    if (!errorMessage) {
+        return;
+    }
+    
+    ANInfo(@"Login failed: %@", errorMessage);
+    
+    PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                   message:errorMessage
+                                                             confirmAction:nil
+                                                              cancelAction:nil];
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)didReceiveDisconnectRequest:(VPNAccount *)account IsLogout:(BOOL)islogout {
+    ANInfo(@"Receive logout request");
+    
+    [self sendAutoLogoutNotification];
+    
+    Gateway *gateway = [[GatewayManager sharedInstance] gatewayOfUrl:account.vsURL andport:account.vsPort];
+    if (!gateway) {  // MPP has been launched by URLScheme with session.
+        ANDebug(@"Secure tunnel will be destoryed with session.");
+        
+        [[ArrayVPNWrapper sharedInstance] stopSSLVPN];
+        if (islogout) {
+            NSInteger ret = [[AAAManager sharedInstance] logoutL3VPNSession];
+            if (ret != ERR_SUCCESS) {
+                ANError(@"Logout failed with error code: %zi.", ret);
+            }
+        }
+    }
+}
+
+- (void)sendAutoLogoutNotification {
+    [[NSNotificationCenter defaultCenter] postNotificationName:kAutoLogoutNotification object:nil];
+}
+
+/**
+ *  This method is meaningful only on first time launched by URLScheme with session after installed from AppStore.
+ *  Cuz it needs the user to allow MPP app to use network privilege, it MUST have network flow. So, it make
+ *  a simple "HEAD" http request here, and the result is not cared about.
+ */
+- (void)triggerNetworkFlowWithHost:(NSString *)host andPort:(NSString *)port {
+    NSString *realPort = @"443";
+    
+    if (!host || host.length == 0) {
+        return;
+    }
+    
+    if (port && port.length > 0) {
+        realPort = port;
+    }
+    
+    NSString *urlString = [NSString stringWithFormat:@"https://%@:%@", host, realPort];
+    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
+    request.HTTPMethod = @"HEAD";
+    NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:nil];
+    [connection start];
+    
+    ANDebug(@"A http request has been sent for auto-login. URL is: %@.", urlString);
+}
+
+- (void)autoConnectWithOauthCode:(NSNotification *)notification {
+    NSString *code =[notification.userInfo objectForKey:@"code"];
+    
+    if (code.length <= 0) {
+        ANError(@"autoConnectWithOauthCode: Get oAuth code failed.");
+        
+        return;
+    }
+    
+    ANInfo(@"autoConnectWithOauthCode: get oauth code successfully=%@", code);
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameGateway];
+    NSString *oauthUrl = [userDefaults valueForKey:KEY_OAUTH_URL];
+    if (oauthUrl.length <= 0) {
+        ANError(@"autoConnectWithOauthCode: Get saved oauth url failed.");
+        
+        return;
+    }
+    oauthUrl = [NSString stringWithFormat:@"%@%@", oauthUrl, code];
+    ANInfo(@"autoConnectWithOauthCode: connect with oauth url=%@", oauthUrl);
+    [self continueLoginWithUrl:oauthUrl callback:nil];
+}
+
+#pragma mark - GatewayModelDelegate
+- (void)needLoginInfo {
+    
+    BOOL isAuth = [Singleton sharedSingleton].isAuthentication;
+    Gateway *gateway = [self.model currentGateway];
+    
+    if (isAuth || gateway.isRadiusPWD){
+        
+        [self performSegueWithIdentifier:kSegueToLogin sender:self];
+    }else{
+        
+        [self checkVerifyMothod];
+    }
+}
+
+- (void)needRegister {
+    [self performSegueWithIdentifier:kSegueToLogin sender:self];
+}
+
+- (void)needConfirm:(NSString *)message {
+    __weak typeof(self) weakSelf = self;
+    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil message:message preferredStyle:UIAlertControllerStyleActionSheet];
+    UIAlertAction *alertActionDestructive = [UIAlertAction actionWithTitle:NSLocalizedString(@"Continue, but never show me this again", nil)
+                                                                     style:UIAlertActionStyleDestructive
+                                                                   handler:^(UIAlertAction *action){
+                                                                       [weakSelf.model suppressCheckServerCertForCurrentGateway];
+                                                                       [weakSelf.model continueLogin];
+                                                                   }];
+    UIAlertAction *alertActionDefault = [UIAlertAction actionWithTitle:NSLocalizedString(@"Continue", nil)
+                                                                 style:UIAlertActionStyleDefault
+                                                               handler:^(UIAlertAction *action){
+                                                                   [weakSelf.model continueLogin];
+                                                               }];
+    UIAlertAction *alertActionCancel = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
+                                                                style:UIAlertActionStyleCancel
+                                                              handler:^(UIAlertAction *action){
+                                                                  [weakSelf didFinishLogin:NO];
+                                                              }];
+    [alertController addAction:alertActionDestructive];
+    [alertController addAction:alertActionDefault];
+    [alertController addAction:alertActionCancel];
+    UIPopoverPresentationController *popover = alertController.popoverPresentationController;
+    if (popover){
+        popover.sourceView = self.view;
+        popover.sourceRect = CGRectMake(self.view.bounds.size.width/2.0, self.view.bounds.size.height, 1.0, 1.0);
+        popover.permittedArrowDirections = UIPopoverArrowDirectionAny;
+    }
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [self presentViewController:alertController animated:YES completion:nil];
+    });
+}
+
+- (void)needLogout {
+    ANInfo(@"Need logout current session");
+    
+    __weak typeof(self) weakSelf = self;
+    NSString *message = [NSString stringWithFormat:NSLocalizedString(@"There is currently an active connection to %@, you can disconnect the current session,\
+                                                                     and start a new connection, or display the active connection.", nil),
+                                                                    [AAAManager sharedInstance].account.vsHost];
+    PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+                                                                   message:message
+                                                              confirmTitle:NSLocalizedString(@"Active Connection",nil)
+                                                               cancelTitle:NSLocalizedString(@"New Connection", nil)
+                                                             confirmAction:^{
+                                                                 [weakSelf logoutThenLogin];
+                                                             }
+                                                              cancelAction:nil];
+    
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)needVDIAuth {
+    __weak typeof(self) weakSelf = self;
+    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"VDI Credential", nil)
+                                                                             message:NSLocalizedString(@"Please input username and password", nil)
+                                                                      preferredStyle:UIAlertControllerStyleAlert];
+    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
+                                                           style:UIAlertActionStyleCancel
+                                                         handler:^(UIAlertAction * _Nonnull action) {
+                                                             [weakSelf.model loginWithVDIUsername:nil password:nil];
+                                                         }];
+    UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
+                                                            style:UIAlertActionStyleDefault
+                                                          handler:^(UIAlertAction * _Nonnull action) {
+                                                              NSString *username = alertController.textFields[0].text;  // Username text field
+                                                              NSString *password = alertController.textFields[1].text;  // Password text field
+                                                              username = [username stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
+                                                              
+                                                              [weakSelf.model loginWithVDIUsername:username password:password];
+                                                          }];
+    
+    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = NSLocalizedString(@"Username", nil);
+    }];
+    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = NSLocalizedString(@"Password", nil);
+    }];
+    [alertController addAction:confirmAction];
+    [alertController addAction:cancelAction];
+    
+    [self presentViewController:alertController animated:YES completion:nil];
+}
+
+- (void)needDoPreLoginCV {
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{
+        [[RulesManager sharedInstance].interactionHandler takeAction];
+    });
+}
+
+- (void)loginError:(NSString *)message {
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [self didFinishLogin:NO];
+    });
+    if (!message) {
+        return;
+    }
+    
+    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:message];
+    
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)loginErrorOfTip:(NSString *)message {
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [self didFinishLogin:NO];
+    });
+    if (!message) {
+        return;
+    }
+    
+    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Tips",nil) message:message];
+    
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)loginFinished:(BOOL)success {
+    [self didFinishLogin:success];
+    
+    [self.navigationController.view stopLoading];
+}
+
+- (void)checkVerifyMothod {
+    Gateway *gateway = [self.model currentGateway];
+    NSString *username = gateway.username;
+    NSString *port = gateway.port;
+    
+    _realPasswords = @[@"", @"", @""];
+    NSDictionary *methodDic = [Singleton getCurrentGatewayMethod:[self.model currentGateway]];
+    NSString *lastName = [methodDic objectForKey:@"userName"] ?: @"";
+    if ([username isEqualToString:@""]){
+        
+        username = lastName;
+    }
+    
+    if (username != nil) {
+        if (!gateway.lastAccessedDate) {  // Prevent from getting saved password after reinstall.
+            [PasswordManager removePasswordsOfHost:gateway.host username:username port:port];
+        }
+        if ([username isEqualToString:lastName] && (gateway.isGestureEnabled || gateway.isFaceOrTouchIDEnabled)) {
+            
+            _realPasswords = [PasswordManager passwordsOfHost:gateway.host username:username port:port];
+            if (![_realPasswords isEqual:@[@"", @"", @""]]){
+                
+                [self mutilVerifyMothod];
+                return;
+            }
+        } else {
+            ANDebug(@"delete user \"%@\" password", username?username:@"nil");
+            [Singleton setCurrentGatewayMethod:@{} andKey:gateway];
+        }
+    }
+    [self performSegueWithIdentifier:kSegueToLogin sender:self];
+}
+
+#pragma mark - 生物认证 手势认证
+-(void) mutilVerifyMothod
+{
+    Gateway *gw = [self.model currentGateway];
+    if (gw.isFaceOrTouchIDEnabled || gw.isGestureEnabled){
+        
+        [Singleton sharedSingleton].isAuthentication = YES;
+        LocalAuthFinishBlockType completeBlock = ^(BOOL isAllow, SecuritySettingOption authType){
+            
+            [Singleton sharedSingleton].isAuthentication = isAllow;
+            if (isAllow){
+                
+                self.isAutoLogin = YES;
+                [self login];
+            }
+        };
+        UIViewController *control = [LocalAuthUtil getAuthVCWithCompletion:completeBlock];
+        control.modalPresentationStyle = UIModalPresentationFullScreen;
+        [self presentViewController:control animated:YES completion:nil];
+    }
+}
+
+- (void)login {
+    
+    VPNAccount *account = [self inputResult];
+    
+    if (account == nil) {
+        ANWarn(@"Cannot get account information");
+        return;
+    }
+    
+    InformationToSave *info = [InformationToSave sharedInstance];
+    
+    info.lastLoginAccount = account;
+    [info save];
+    
+    AAAManager *manager = [AAAManager sharedInstance];
+    manager.errorCode = 0; // Success
+    [manager continueVPNThreadWithAccount:account];
+}
+
+- (VPNAccount *)inputResult {
+    
+    AAAManager *manager = [AAAManager sharedInstance];
+    
+    VPNAccount * account = manager.account;
+    
+    NSDictionary *methodDic = [Singleton getCurrentGatewayMethod:[self.model currentGatewayUpInside]];
+    
+    NSString *methodType = [methodDic objectForKey:@"methodType"];
+    if ([methodType isEqualToString:@"0"]){
+        
+        [Singleton sharedSingleton].isSupportAuth = YES;
+    }else{
+        
+        [Singleton sharedSingleton].isSupportAuth = NO;
+    }
+    
+    account.loginMethod = [methodDic objectForKey:@"methodName"] ?: @"";
+    account.userName = [methodDic objectForKey:@"userName"] ?: @"";
+    
+    account.passWord  = _realPasswords[0]  ?: @"";
+    account.passWord2 = _realPasswords[1]  ?: @"";
+    account.passWord3 = _realPasswords[2]  ?: @"";
+    
+    UIDevice *devInfo = [UIDevice currentDevice];
+    account.deviceName =[NSString stringWithFormat:@"%@|Apple;%@;iOS %@", devInfo.name, devInfo.platformString, devInfo.systemVersion];
+    
+    return account;
+}
+
+-(void) cancelConnection
+{
+    [self didFinishLogin:NO];
+    [[AAAManager sharedInstance] cancelLoginTapped];
+}
+
+-(void) jumpToLoginIn
+{
+    [self performSegueWithIdentifier:kSegueToLogin sender:self];
+}
+
+- (void)handleVPNNotification:(NSNotification *)notification {
+    //only faceid/touchid/gestuer auth
+    if (!self.isAutoLogin){
+        
+        return;
+    }
+    
+    VPNMessage *message = notification.object;
+    AAAManager *manager = [AAAManager sharedInstance];
+    NSInteger error = manager.errorCode;
+    NSString *aMessage;
+    
+    switch (message.code) {
+        case VPN_CB_CONNECTED: {
+            if (!self.isLocalDB){
+                
+                [self pop];
+            }
+            [self didFinishLogin:YES];
+            break;
+        }
+        case VPN_CB_DISCONNECTING: {
+            if (!self.isLocalDB){
+                
+                [self pop];
+            }
+            self.isAutoLogin = NO;
+            [self didFinishLogin:NO];
+            break;
+        }
+        case VPN_CB_CHALLENGE: {
+            self.isLocalDB = NO;
+            [self performSegueWithIdentifier:kSegueToChallenge sender:nil];
+            break;
+        }
+        case VPN_CB_CONN_FAILED: {
+            switch (error) {
+                case ERR_WRONG_USER_PASS:
+                    aMessage = manager.errorInformation;
+                    break;
+                case ERR_AUTHORIZE_FAILED:
+                    aMessage = NSLocalizedString(@"Login failed", nil);
+                    break;
+                case ERR_CALLBACK_FAILED:
+                    break;
+                case ERR_INTERRUPTED:
+                    break;
+                case ERR_CLIENT_SECURITY:
+                    aMessage = NSLocalizedString(@"Client security is not supported", nil);
+                    break;
+                case ERR_SMS_GET_PHONE:
+                    aMessage = NSLocalizedString(@"The system failed to get your phone number to do OTP authentication", nil);
+                    break;
+                case ERR_SMS_SEND:
+                    aMessage = NSLocalizedString(@"The system failed to send message to your phone", nil);
+                    break;
+                case ERR_SMS_TOO_MANY_RETRY:
+                    aMessage = NSLocalizedString(@"Your attempt to sign in failed, because you have entered wrong SMS verification code for too many times", nil);
+                    break;
+                case ERR_HWID_DENY:
+                    aMessage = NSLocalizedString(@"The device is denied because of wrong hardware ID!", nil);
+                    break;
+                case ERR_HWID_PENDING:
+                    aMessage = NSLocalizedString(@"The hardware ID of this device is not approved yet!", nil);
+                    break;
+                default:
+                    ANError(@"Login failed with error message: %@", aMessage);
+                    break;
+            }
+            
+            Gateway *gw = [[[GatewayModel alloc] init] currentGatewayUpInside];
+            if (!gw.isShowLoginDialogEnabled) {
+                if (aMessage && aMessage.length > 0) {
+                    if (![aMessage containsString:@"<a href='"]) {
+                        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:aMessage];
+                        [self presentViewController:dialog animated:YES completion:nil];
+                    } else {
+                        ANInfo(@"Connect failed:Error message=%@", aMessage);
+                        NSRange subStrRange = [aMessage rangeOfString:@"<a href='"];
+                        NSMutableString *finalMessage = [NSMutableString stringWithString:aMessage];
+                        [finalMessage deleteCharactersInRange:NSMakeRange(subStrRange.location, (int)strlen("<a href='"))];
+                        NSString *displayMessage = [finalMessage substringToIndex:[finalMessage rangeOfString:@"'>"].location];
+                        ANInfo(@"Connect failed:Display message=%@", displayMessage);
+                        
+                        NSString *URLMessage = [aMessage substringFromIndex:(subStrRange.location + subStrRange.length)];
+                        URLMessage = [URLMessage substringToIndex:[URLMessage rangeOfString:@"'>"].location];
+                        ANInfo(@"URL message=%@", URLMessage);
+                        
+                        PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil) message:displayMessage confirmAction:^{
+                                                                    NSURL *url = [NSURL URLWithString:URLMessage];
+                                                                    OpenURL(url);
+                                                                    }
+                                                        cancelAction:nil];
+                        [self presentViewController:popup animated:YES completion:nil];
+                    }
+                }
+            }
+            
+            break;
+        }
+        case VPN_CB_LOGIN:{
+            if (error == ERR_WRONG_USER_PASS || error == ERR_USER_LOCKED) {
+                __weak typeof(self) weakSelf = self;
+                if (![manager.errorInformation containsString:@"<a href='"]) {
+                    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                                  message:[self loginFailedMessage:error]
+                                                                                   action:^{
+                                                                                       [weakSelf showLoginActivity:NO];
+                                                                                   }];
+                    [self presentViewController:dialog animated:YES completion:nil];
+                } else {
+                    ANInfo(@"Error message=%@", manager.errorInformation);
+                    NSRange subStrRange = [manager.errorInformation rangeOfString:@"<a href='"];
+                    NSMutableString *finalMessage = [NSMutableString stringWithString:manager.errorInformation];
+                    [finalMessage deleteCharactersInRange:NSMakeRange(subStrRange.location, (int)strlen("<a href='"))];
+                    NSString *displayMessage = [finalMessage substringToIndex:[finalMessage rangeOfString:@"'>"].location];
+                    ANInfo(@"Display message=%@", displayMessage);
+                    
+                    NSString *URLMessage = [manager.errorInformation substringFromIndex:(subStrRange.location + subStrRange.length)];
+                    URLMessage = [URLMessage substringToIndex:[URLMessage rangeOfString:@"'>"].location];
+                    ANInfo(@"URL message=%@", URLMessage);
+                    
+                    PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil) message:displayMessage confirmAction:^{
+                                                                NSURL *url = [NSURL URLWithString:URLMessage];
+                                                                OpenURL(url);
+                                                                [weakSelf showLoginActivity:NO];
+                        
+                                                                // If password is wrong, pop to root view.
+                                                                [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                }
+                                               cancelAction:^{
+                                                                [weakSelf showLoginActivity:NO];
+                                                                // If password is wrong, pop to root view.
+                                                                [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                }];
+                    [self presentViewController:popup animated:YES completion:nil];
+                }
+            } else if (error == ERR_AUTHORIZE_FAILED) {
+                PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@""
+                                                                              message:NSLocalizedString(@"Authorize failed",nil)];
+                [self presentViewController:dialog animated:YES completion:nil];
+                
+            }
+        }
+        case VPN_CB_SMS: {
+            self.isLocalDB = NO;
+            if ([self.navigationController.topViewController isKindOfClass:[SMSViewController class]]) {
+                [self refreshTopView];
+            } else {
+                [self performSegueWithIdentifier:kSegueToSMS sender:nil];
+            }
+            break;
+        }
+        case VPN_CB_CHANGPASSWORD: {
+            self.isLocalDB = NO;
+            [self performSegueWithIdentifier:kSegueToChangePassword sender:nil];
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+- (NSString *)loginFailedMessage:(NSInteger)errorCode {
+    AAAManager *manager = [AAAManager sharedInstance];
+    
+    if (errorCode == ERR_USER_LOCKED) {
+        NSString *errorMessage = manager.errorInformation;
+        if (errorMessage && errorMessage.length > 0) {
+            return errorMessage;
+        }
+    }
+    
+    NSString *errorMessage = manager.errorInformation;
+    if (errorMessage && errorMessage.length > 0) {
+        return errorMessage;
+    }
+    
+    // Return this string for all login error (incorrect username or password) except SMX auth.
+    return NSLocalizedString(@"Login failed, please check username and password", nil);
+}
+
+- (void)refreshTopView {
+    UIViewController *top = [self.navigationController topViewController];
+    SEL handler = NSSelectorFromString(@"refreshView");
+    if ([top respondsToSelector:handler]) {
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+        [top performSelector:handler];
+    }
+}
+
+- (void)pop {
+    if (self.navigationController.viewControllers.count > 1) {
+        [self.navigationController popViewControllerAnimated:YES];
+    }else{
+        [self dismissViewControllerAnimated:YES completion:nil];
+    }
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewayViewController.m.MotionProEnterprise
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewayViewController.m.MotionProEnterprise	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/GatewayViewController.m.MotionProEnterprise	(working copy)
@@ -0,0 +1,1184 @@
+//
+//  GatewayViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/10.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "YCXMenu.h"
+#import "ANLogger.h"
+#import "ANPopupDialog.h"
+#import "AutoLoginHandler.h"
+#import "ArrayVPNWrapper.h"
+#import "GatewayModel.h"
+#import "GatewayCell.h"
+#import "UIView+Loading.h"
+#import "LoginViewController.h"
+#import "ResourcesViewController.h"
+#import "RulesManager.h"
+#import "EmptyGatewayCell.h"
+#import "GatewayViewLayout.h"
+#import "GatewayViewController.h"
+#import "GatewaySettingsViewController.h"
+#import "LocalAuthUtil.h"
+#import "PasswordManager.h"
+#import "InformationToSave.h"
+#import "UIDevice+Hardware.h"
+#import "Singleton.h"
+#import "UIViewController+Activity.h"
+#import "SMSViewController.h"
+#import "ZTWebAuthViewController.h"
+
+static NSString * const kSegueToChallenge = @"LoginToChallenge";
+static NSString * const kSegueToSMS = @"LoginToSMS";
+static NSString * const kSegueToChangePassword = @"LoginToChangePassword";
+
+typedef NS_ENUM(NSInteger, MenuIndex) {
+    kMenuIndexLog = 0,
+    kMenuIndexAbout
+};
+
+#define OAUTH_SESSION_URL               @"/prx/000/http/localh/"
+#define CancelConnection               @"CancelConnection"
+#define JumpToLoginIn                  @"jumpToLoginIn"
+
+#if TARGET_OS_IPHONE
+NSString * const kAppGroupNameGateway = @"group.net.arraynetworks.groupenterprise";
+NSString * const kArrayVPNTunelErrorMsgGateway = @"net.arraynetworks.sslvpn.errormsg";
+NSString * const koAuthSetCodeGateway = @"net.arraynetworks.oauthsetcode";
+#elif TARGET_OS_MAC
+NSString * const kAppGroupNameGateway = @"5VZLZ3YQ9P.net.arraynetworks.MacTunnel";
+#endif
+
+static NSString * const kSegueToSettings = @"GatewayToSettings";
+static NSString * const kSegueToLogin = @"GatewayToLogin";
+static NSString * const kSegueToResource = @"GatewayToResource";
+static NSString * const kSegueToAbout = @"GatewayToAbout";
+static NSString * const kSegueToLogSettings = @"GatewayToLogSettings";
+static NSString * const kSegueToWebAuth = @"GatewayToWebAuth";
+
+@interface GatewayViewController () <UIScrollViewDelegate, LoginControllerDelegate, GatewaySettingDelegate, GatewayCellDelegate, GatewayModelDelegate,
+AutoLoginHandlerDelegate, GatewayModelDelegate> {
+    VPNAccount  *_loginAccount;
+    GatewayCell *_loginCell;
+    AutoLoginHandler *_autoLoginHandler;
+}
+
+@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
+@property (weak, nonatomic) IBOutlet UIPageControl *pageControl;
+@property (weak, nonatomic) IBOutlet UIBarButtonItem *addGatewayButton;
+@property (weak, nonatomic) IBOutlet UIBarButtonItem *moreButton;
+
+@property (strong, nonatomic) GatewayModel *model;
+@property (nonatomic, strong) NSString     *webAuthUrl;
+@property (nonatomic, strong) NSString     *callbackUrl;
+@property (nonatomic, strong) NSArray      *realPasswords;
+@property (nonatomic, assign) BOOL         isAutoLogin;
+@property (nonatomic, assign) BOOL         isLocalDB;  //Only the biometric authentication screen is displayed
+
+@end
+
+@implementation GatewayViewController
+
+- (void)dealloc {
+    self.model = nil;
+#if TARGET_OS_IPHONE
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:kArrayVPNTunelErrorMsgGateway object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:koAuthSetCodeGateway object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:CancelConnection object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:JumpToLoginIn object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:kVPNMessageNotification object:nil];
+#endif
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    self.model = [[GatewayModel alloc] init];
+    self.model.delegate = self;
+    
+    [self initNavigationBarAppearance];
+    [self initCollectionView];
+    [self initPageControl];
+    [self initButtonItems];
+#if TARGET_OS_IPHONE
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(autoConnectWithOauthCode:) name:koAuthSetCodeGateway object:nil];
+   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cancelConnection) name:CancelConnection object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jumpToLoginIn) name:JumpToLoginIn object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleVPNNotification:) name:kVPNMessageNotification object:nil];
+#endif
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    
+    static dispatch_once_t onceToken;
+    
+    if (!_autoLoginHandler) {
+        _autoLoginHandler = [[AutoLoginHandler alloc] initWithDelegate:self];
+    }
+    
+    if (_autoLoginHandler.url) {
+        // If autolaunch, do not show add gateway view.
+        dispatch_once(&onceToken, ^{
+            [_autoLoginHandler readyToAutoLogin];
+        });
+        return;
+    }
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([segue.identifier isEqualToString:kSegueToAbout] || [segue.identifier isEqualToString:kSegueToLogSettings] || [segue.identifier isEqualToString:kSegueToChallenge] || [segue.identifier isEqualToString:kSegueToChangePassword] ||
+        [segue.identifier isEqualToString:kSegueToSMS]) {
+        return;  // These destinations doesn't need more setting.
+    }
+    
+    id<ANViewControllerSwitchProtocol> p = nil;
+    NSDictionary *option = nil;
+    
+    UINavigationController *destNavivation = (UINavigationController *)segue.destinationViewController;
+    if (destNavivation.viewControllers.count > 0) {
+        p = [destNavivation.viewControllers firstObject];
+    } else {
+        ANError(@"Can't find destination view controller.");
+        return;
+    }
+    
+    if ([segue.identifier isEqualToString:kSegueToSettings]) {
+        if ([sender isKindOfClass:[Gateway class]]) {
+            option = @{@"gateway": sender};
+        }
+        [p switchFromSender:self withOption:option];
+    } else if ([segue.identifier isEqualToString:kSegueToLogin]) {
+        [p switchFromSender:self withOption:nil];
+    }
+}
+
+-(NSDictionary *) webAuthConfig
+{
+    NSDictionary *option = nil;
+    Gateway *gateway = [self.model currentGateway];
+    __weak typeof(self) weakSelf = self;
+    void (^competion)(NSError *error, NSString *session, NSString *username, NSString *acsInfo) = ^(NSError *error, NSString *session, NSString *username, NSString *acsInfo) {
+        __strong typeof(weakSelf) strongSelf = weakSelf;
+        
+        ANInfo(@"Error: %@, Session:%@, username:%@, oauth acsInfo:%@", error, session, username, acsInfo);
+        
+        if (session && session.length > 0) {
+            if (acsInfo && acsInfo.length > 0) {
+                AAAManager *manager = [AAAManager sharedInstance];
+                [manager setOAuthAcsInfo:acsInfo];
+            }
+            if (self.webAuthUrl && [self.webAuthUrl length] > 0) {
+                [strongSelf.model loginWithSession:session andUsername:username andoAuthURL:self.webAuthUrl andcallbackURL:self.callbackUrl];
+            } else {
+                [strongSelf.model loginWithSession:session andUsername:username];
+            }
+        } else {
+            [strongSelf didFinishLogin:NO];
+        };
+        
+        if (error) {
+            NSString *message = NSLocalizedString(@"Connection to server failed", nil);
+            PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                          message:message];
+            [strongSelf presentViewController:dialog animated:YES completion:nil];
+        }
+    };
+    
+    option = @{@"host": gateway.host,
+               @"port": gateway.port,
+               @"alias": gateway.alias,
+               @"url": self.webAuthUrl,
+               @"completion": competion
+               };
+    
+    return option;
+}
+
+- (void)addButtonClicked:(id)sender {
+    [self performSegueWithIdentifier:kSegueToSettings sender:self];
+}
+
+- (void)moreButtonClicked:(id)sender {
+    YCXMenuItem *logItem = [YCXMenuItem menuItem:NSLocalizedString(@"Log", nil)
+                                           image:[UIImage imageNamed:@"GatewayLog"]
+                                             tag:kMenuIndexLog
+                                        userInfo:nil];
+    [logItem setForeColor:UIColorFromRGBA(0x666666, 1.0)];
+    
+    YCXMenuItem *aboutItem = [YCXMenuItem menuItem:NSLocalizedString(@"About", nil)
+                                             image:[UIImage imageNamed:@"GatewayAbout"]
+                                               tag:kMenuIndexAbout
+                                          userInfo:nil];
+    [aboutItem setForeColor:UIColorFromRGBA(0x666666, 1.0)];
+    NSArray *items = @[logItem, aboutItem];
+    
+    [YCXMenu setTintColor:[UIColor whiteColor]];
+    [YCXMenu setSeparatorColor:UIColorFromRGBA(0xe2e2e2, 1.0)];
+    [YCXMenu setSelectedColor:UIColorFromRGBA(0xe2e2e2, 1.0)];
+    [YCXMenu setCornerRadius:CGFLOAT_MIN];
+    if ([YCXMenu isShow]){
+        [YCXMenu dismissMenu];
+    } else {
+        [YCXMenu showMenuInView:self.view fromRect:CGRectMake(self.view.frame.size.width - 60, 0, 60, 0) menuItems:items selected:^(NSInteger index, YCXMenuItem *item) {
+            if (index == kMenuIndexLog) {
+                [self performSegueWithIdentifier:kSegueToLogSettings sender:nil];
+            } else if (index == kMenuIndexAbout) {
+                [self performSegueWithIdentifier:kSegueToAbout sender:nil];
+            }
+        }];
+    }
+}
+
+- (void)initNavigationBarAppearance {
+    // To make the black line under navigation bar disappear (for iOS11).
+    [[UINavigationBar appearance] setBackgroundImage:[[UIImage alloc] init] forBarMetrics:UIBarMetricsDefault];
+    [[UINavigationBar appearance] setShadowImage:[[UIImage alloc] init]];
+}
+
+- (void)initCollectionView {
+    // Register cells.
+    [self.collectionView registerNib:[UINib nibWithNibName:@"EmptyGatewayCell" bundle:nil]
+          forCellWithReuseIdentifier:kEmptyGatewayCellID];
+    [self.collectionView registerNib:[UINib nibWithNibName:@"GatewayCell" bundle:nil]
+          forCellWithReuseIdentifier:kGatewayCellID];
+    // Setup layout class.
+    [self.collectionView setCollectionViewLayout:[[GatewayViewLayout alloc] init]];
+    
+    self.collectionView.allowsSelection = YES;
+    self.collectionView.decelerationRate = 0.994;  // Between UIScrollViewDecelerationRateNormal and UIScrollViewDecelerationRateFast
+}
+
+- (void)initPageControl {
+    [self setPageControlAppearance];
+    self.pageControl.userInteractionEnabled = NO;
+    
+    NSInteger totalGateways = [self.model numberOfGateways];
+    if (totalGateways <= 0) {
+        self.pageControl.hidden = YES;
+    } else {
+        self.pageControl.hidden = NO;
+        self.pageControl.numberOfPages = totalGateways;
+        self.pageControl.currentPage = 0;
+    }
+}
+
+- (void)updatePageControlNumbers:(NSInteger)totalPages {
+    self.pageControl.hidden = totalPages > 0 ? NO : YES;
+    self.pageControl.numberOfPages = totalPages;
+}
+
+- (void)updatePageControlCurrentPage:(NSInteger)index {
+    NSInteger total = self.pageControl.numberOfPages;
+    if (index >= total || index < 0) {
+        ANDebug(@"Index \(%zi) of page control is out of page numbers \(%zi)", index, total);
+        return;
+    } else {
+        self.pageControl.currentPage = index;
+    }
+}
+
+- (void)updateCurrentGatewayIndex:(NSInteger)index {
+    [self.model selectGatewayAtIndex:index];
+    [Singleton sharedSingleton].currentPageNumber = index;
+}
+
+- (void)setGatewayCellAsSelectedWithIndex:(NSInteger)index {
+    [self clearGatewayCellsShadow];
+    
+    [self setCurrentCellShadowWithIndex:index];
+}
+
+- (void)clearGatewayCellsShadow {
+    for (UICollectionViewCell *cell in self.collectionView.visibleCells) {
+        if (cell) {
+            if ([cell respondsToSelector:@selector(clearShadow)]) {
+                [cell performSelector:@selector(clearShadow)];
+            }
+        }
+    }
+}
+
+- (void)setCurrentCellShadowWithIndex:(NSInteger)index {
+    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
+    GatewayCell *currentCell = (GatewayCell *)[self.collectionView cellForItemAtIndexPath:indexPath];
+    if (currentCell) {
+        if ([currentCell respondsToSelector:@selector(addShadow)]) {
+            [currentCell performSelector:@selector(addShadow)];
+        }
+    }
+}
+
+- (void)initButtonItems {
+    [self.addGatewayButton setTarget:self];
+    [self.addGatewayButton setAction:@selector(addButtonClicked:)];
+    
+    [self.moreButton setTarget:self];
+    [self.moreButton setAction:@selector(moreButtonClicked:)];
+}
+
+- (void)setPageControlAppearance {
+    self.pageControl.pageIndicatorTintColor = UIColorFromRGBA(0x999999, 1.0);
+    self.pageControl.currentPageIndicatorTintColor = MAIN_COLOR;
+}
+
+- (void)reloadWithAnimation {
+    [UIView transitionWithView:self.collectionView
+                      duration:0.3
+                       options:UIViewAnimationOptionTransitionCrossDissolve
+                    animations:^{
+                        [self.collectionView reloadData];
+                    }
+                    completion:nil];
+}
+
+- (void)deleteGateway {
+    [self.model deleteCurrentGateway];
+
+    NSInteger total = [self.model numberOfGateways];
+    if (total == 0) {
+        [self updateCurrentGatewayIndex:0];
+        [self reloadWithAnimation];
+    } else{
+        
+        NSInteger integer = 0;
+        if (self.pageControl.currentPage == total){
+            
+            integer = self.pageControl.currentPage - 1;
+        }else{
+            
+            integer = self.pageControl.currentPage;
+        }
+        
+        [self updateCurrentGatewayIndex:integer];
+        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.pageControl.currentPage inSection:0];
+        [self.collectionView deleteItemsAtIndexPaths:@[indexPath]];
+    }
+    
+    [SecuritySetting clearGesture];
+    [self updatePageControlNumbers:[self.model numberOfGateways]];
+}
+
+#pragma mark - UICollectionViewDataSource
+- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
+    NSInteger totalGateways = [self.model numberOfGateways];
+    
+    return totalGateways > 0 ? totalGateways : 1;
+}
+
+- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
+    UICollectionViewCell *cell = nil;
+    NSInteger totalGateways = [self.model numberOfGateways];
+    
+    if (totalGateways > 0) {
+        cell = [collectionView dequeueReusableCellWithReuseIdentifier:kGatewayCellID forIndexPath:indexPath];
+        Gateway *gateway = [self.model gatewayAtIndex:indexPath.row];
+        if (gateway) {
+            [(GatewayCell *)cell configureWithGateway:gateway delegate:self];
+        }
+    } else {
+        cell = [collectionView dequeueReusableCellWithReuseIdentifier:kEmptyGatewayCellID forIndexPath:indexPath];
+        EmptyGatewayCell *emptyCell = (EmptyGatewayCell *)cell;
+        [emptyCell.addGatewayButton addTarget:self action:@selector(addButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
+        [emptyCell.emptyGatewayButton addTarget:self action:@selector(addButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
+    }
+    
+    if ([cell respondsToSelector:@selector(changeLayoutForIphone5)]) {
+        [cell performSelector:@selector(changeLayoutForIphone5)];
+    }
+    
+    return cell;
+}
+
+#pragma mark - UICollectionViewDelegate
+- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
+    [collectionView deselectItemAtIndexPath:indexPath animated:YES];
+    
+    [self setGatewayCellAsSelectedWithIndex:indexPath.item];
+}
+
+#pragma mark - UIScrollViewDelegate
+- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
+    int page = (int)(scrollView.contentOffset.x / kCellWidth);
+    if (page != self.pageControl.currentPage) {
+        [self updatePageControlCurrentPage:page];
+        [self updateCurrentGatewayIndex:page];
+        [self setGatewayCellAsSelectedWithIndex:page];
+    }
+}
+
+#pragma mark - GatewaySettingDelegate
+- (void)didFinishedEdit:(BOOL)isNew {
+    NSInteger totalPages = [self.model numberOfGateways];
+    NSInteger currentPage = 0;
+    if (isNew) {
+        currentPage = totalPages-1;
+        [self updateCurrentGatewayIndex:currentPage];
+
+        if (totalPages == 1) {
+            [self reloadWithAnimation];
+        } else {
+            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:currentPage inSection:0];
+            [self.collectionView insertItemsAtIndexPaths:@[indexPath]];
+        }
+        
+        [self updatePageControlNumbers:totalPages];
+    } else {
+        currentPage = self.pageControl.currentPage;
+        [self updateCurrentGatewayIndex:currentPage];
+        
+        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:currentPage inSection:0];
+        [self.collectionView reloadItemsAtIndexPaths:@[indexPath]];
+    }
+    
+    [self setGatewayCellAsSelectedWithIndex:currentPage];
+    
+    if (isNew) {
+        
+        [self.collectionView setContentSize:CGSizeMake(currentPage * kScreenWidth, kScreenHeight)];
+        [self.collectionView setContentOffset:CGPointMake(currentPage * kScreenWidth, 0) animated:YES];
+    }
+}
+
+#pragma mark - GatewayCellDelegate
+- (void)didStartLogin:(NSString *)gatewayTitle cell:(UICollectionViewCell *)cell {
+    
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameGateway];
+    [userDefaults removeObjectForKey:KEY_OAUTH_URL];
+    [userDefaults removeObjectForKey:@"dns_list"];
+    
+    [AAAManager sharedInstance].resources = @"";
+    
+    self.webAuthUrl = @"";
+    self.isAutoLogin = NO;
+    self.isLocalDB = YES;
+    [Singleton sharedSingleton].isAuthentication = NO;
+    
+    if ([cell respondsToSelector:@selector(addShadow)]) {
+        [cell performSelector:@selector(addShadow)];
+    }
+    
+    _loginCell = (GatewayCell *)cell;
+    [self.collectionView setScrollEnabled:NO];
+    
+    Gateway *currentGateway = [self.model currentGateway];
+    if (!currentGateway.isWebAuthEnabled) {
+        [self.model login];
+    } else {
+        self.webAuthUrl = @"";
+        [self startWebAuth];
+    }
+}
+
+- (void)didCancelLogin:(NSString *)gatewayTitle {
+    _loginCell = nil;
+    [self.collectionView setScrollEnabled:YES];
+    [self.model cancelLogin];
+}
+
+- (void)willDeleteGateway:(NSString *)gatewayUrl {
+    if (!gatewayUrl) {
+        ANError(@"Gateway URL is nil, can't be deleted.");
+        return;
+    }
+    if (![gatewayUrl isEqualToString:[self.model currentGateway].url]) {
+        ANInfo(@"Gateway \"%@\" is not current gateway, don't delete.", gatewayUrl);
+        return;
+    }
+    
+    __weak typeof(self) weakSelf = self;
+    PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Delete", nil)
+                                                                  message:NSLocalizedString(@"Are you sure to delete this site?", nil)
+                                                            confirmAction:^{
+                                                                Gateway *gateway = [weakSelf.model currentGateway];
+                                                                if (!gateway) {
+                                                                    ANError(@"Can't find gateway named \"%@\".", gatewayUrl);
+                                                                    return;
+                                                                } else {
+                                                                    [weakSelf deleteGateway];
+                                                                }
+                                                            }
+                                                             cancelAction:nil];
+    [self presentViewController:popup animated:YES completion:nil];
+}
+
+- (void)willEditGateway:(NSString *)gatewayUrl andPort:(NSString *)gatewayPort {
+    Gateway *gateway = [self.model gatewayOfUrl:gatewayUrl andPort:gatewayPort];
+    [self performSegueWithIdentifier:kSegueToSettings sender:gateway];
+}
+
+#pragma mark - WebAuth
+- (void)startWebAuth {
+    [self webAuthConfig];
+    ZTWebAuthViewController *control = [[ZTWebAuthViewController alloc] init];
+    control.infoDic = [self webAuthConfig];
+    [self.navigationController pushViewController:control animated:YES];
+}
+
+#pragma mark - Login Handler
+- (void)didFinishLogin:(BOOL)success {
+    [_loginCell setAsNormal];
+    
+    [self.collectionView setScrollEnabled:YES];
+    
+    if (success) {
+        [self.model didAccessCurrentGateway];
+        
+        [_loginCell setAccessDate:[self.model currentGatewayAccessDate]];  // Update gateway cell after login.
+        
+        [self performSegueWithIdentifier:kSegueToResource sender:self];
+    }
+}
+
+- (void)continueLoginWithUrl:(NSString *)url callback:(NSString *)callback {
+    self.webAuthUrl = url;
+    self.callbackUrl = callback;
+    [_loginCell setAsLoggingIn];
+    
+    if (url) {
+        [self.model didAccessCurrentGateway];
+        
+        [_loginCell setAccessDate:[self.model currentGatewayAccessDate]];
+        [self startWebAuth];
+    }
+}
+
+#pragma mark - Auto Login Handler
+- (void)perpareForAutoLogin:(void (^)(void))completion {
+    completion();
+}
+
+- (void)didReceiveLoginRequest:(VPNAccount *)account {
+    if (!account) {
+        return;
+    }
+    
+    _loginAccount = account;
+    
+    __weak __typeof(self) weakSelf = self;
+    [self perpareForAutoLogin:^{
+        [weakSelf sendAutoLogoutNotification];
+        [weakSelf doRealAutoLogin];
+    }];
+    
+}
+
+- (void)didReceiveLoginRequest:(VPNAccount *)account oauthreq:(NSString *)request oauthcode:(NSString *)code {
+    NSString *urlString = nil;
+    if ([account.vsPort isEqualToString:@"443"]) {
+        urlString = [NSString stringWithFormat:@"https://%@%@%@?code=%@", account.vsHost, OAUTH_SESSION_URL, request, code];
+    } else {
+        urlString = [NSString stringWithFormat:@"https://%@:%@%@%@?code=%@", account.vsHost, account.vsPort, OAUTH_SESSION_URL, request, code];
+    }
+    ANInfo(@"didReceiveLoginRequest:continue login url=%@", urlString);
+    [self continueLoginWithUrl:urlString callback:account.autoLoginCallback];
+}
+
+- (void)handleVPNTunnelError:(NSNotification *)notification {
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    NSString *errMessage = [vpnWrapper getErrorMsgWithCode];
+    if (errMessage && errMessage.length > 0) {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:errMessage];
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+- (void)didReceiveLoginRequest:(VPNAccount *)account session:(NSString *)sess {
+    if (!sess || sess.length <= 0) {
+        ANWarn(@"Can't create secure tunnel with empty session.");
+        return;
+    }
+    
+    [self triggerNetworkFlowWithHost:account.vsHost andPort:account.vsPort];
+    
+    ANDebug(@"Secure tunnel will be created with session.");
+    AAAManager *manager = [AAAManager sharedInstance];
+    manager.account = account;
+    [manager setSessionID:sess];
+    
+#if TARGET_OS_IPHONE
+        //Reset connect fail reason.
+        NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameGateway];
+        [userDefaults removeObjectForKey:@"tunnel_result"];
+#endif
+    [[ArrayVPNWrapper sharedInstance] startSSLVPN];
+    
+#if TARGET_OS_IPHONE
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleVPNTunnelError:)
+                                                 name:kArrayVPNTunelErrorMsgGateway object:nil];
+#endif
+}
+
+- (void)doRealAutoLogin {
+    if (!_loginAccount) return;
+    
+    __weak __typeof(self) weakSelf = self;
+    [self.navigationController.view startLoadingWithMessage:@"Connecting..."
+                                                buttonTitle:NSLocalizedString(@"Cancel", nil)
+                                               cancelAction:^{
+                                                   [weakSelf.model cancelLogin];
+                                               }];
+    
+    [self.model autoLoginwithAccount:_loginAccount];
+}
+
+- (void)logoutThenLogin {
+    __weak __typeof(self) weakSelf = self;
+    
+    [self.model logoutCurrentSession:^{
+        ANDebug(@"Logout successfully, do login");
+        
+        [self sendAutoLogoutNotification];
+        // Wait 1 second for l3vpn thread to stop.
+        [weakSelf performSelector:@selector(doRealAutoLogin) withObject:nil afterDelay:1];
+    }];
+}
+
+- (void)autoLoginFailed:(NSString *)errorMessage {
+    if (!errorMessage) {
+        return;
+    }
+    
+    ANInfo(@"Login failed: %@", errorMessage);
+    
+    PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                   message:errorMessage
+                                                             confirmAction:nil
+                                                              cancelAction:nil];
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)didReceiveDisconnectRequest:(VPNAccount *)account IsLogout:(BOOL)islogout {
+    ANInfo(@"Receive logout request");
+    
+    [self sendAutoLogoutNotification];
+    
+    Gateway *gateway = [[GatewayManager sharedInstance] gatewayOfUrl:account.vsURL andport:account.vsPort];
+    if (!gateway) {  // MPP has been launched by URLScheme with session.
+        ANDebug(@"Secure tunnel will be destoryed with session.");
+        
+        [[ArrayVPNWrapper sharedInstance] stopSSLVPN];
+        if (islogout) {
+            NSInteger ret = [[AAAManager sharedInstance] logoutL3VPNSession];
+            if (ret != ERR_SUCCESS) {
+                ANError(@"Logout failed with error code: %zi.", ret);
+            }
+        }
+    }
+}
+
+- (void)sendAutoLogoutNotification {
+    [[NSNotificationCenter defaultCenter] postNotificationName:kAutoLogoutNotification object:nil];
+}
+
+/**
+ *  This method is meaningful only on first time launched by URLScheme with session after installed from AppStore.
+ *  Cuz it needs the user to allow MPP app to use network privilege, it MUST have network flow. So, it make
+ *  a simple "HEAD" http request here, and the result is not cared about.
+ */
+- (void)triggerNetworkFlowWithHost:(NSString *)host andPort:(NSString *)port {
+    NSString *realPort = @"443";
+    
+    if (!host || host.length == 0) {
+        return;
+    }
+    
+    if (port && port.length > 0) {
+        realPort = port;
+    }
+    
+    NSString *urlString = [NSString stringWithFormat:@"https://%@:%@", host, realPort];
+    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
+    request.HTTPMethod = @"HEAD";
+    NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:nil];
+    [connection start];
+    
+    ANDebug(@"A http request has been sent for auto-login. URL is: %@.", urlString);
+}
+
+- (void)autoConnectWithOauthCode:(NSNotification *)notification {
+    NSString *code =[notification.userInfo objectForKey:@"code"];
+    
+    if (code.length <= 0) {
+        ANError(@"autoConnectWithOauthCode: Get oAuth code failed.");
+        
+        return;
+    }
+    
+    ANInfo(@"autoConnectWithOauthCode: get oauth code successfully=%@", code);
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameGateway];
+    NSString *oauthUrl = [userDefaults valueForKey:KEY_OAUTH_URL];
+    if (oauthUrl.length <= 0) {
+        ANError(@"autoConnectWithOauthCode: Get saved oauth url failed.");
+        
+        return;
+    }
+    oauthUrl = [NSString stringWithFormat:@"%@%@", oauthUrl, code];
+    ANInfo(@"autoConnectWithOauthCode: connect with oauth url=%@", oauthUrl);
+    [self continueLoginWithUrl:oauthUrl callback:nil];
+}
+
+#pragma mark - GatewayModelDelegate
+- (void)needLoginInfo {
+    
+    BOOL isAuth = [Singleton sharedSingleton].isAuthentication;
+    Gateway *gateway = [self.model currentGateway];
+    
+    if (isAuth || gateway.isRadiusPWD){
+        
+        [self performSegueWithIdentifier:kSegueToLogin sender:self];
+    }else{
+        
+        [self checkVerifyMothod];
+    }
+}
+
+- (void)needRegister {
+    [self performSegueWithIdentifier:kSegueToLogin sender:self];
+}
+
+- (void)needConfirm:(NSString *)message {
+    __weak typeof(self) weakSelf = self;
+    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil message:message preferredStyle:UIAlertControllerStyleActionSheet];
+    UIAlertAction *alertActionDestructive = [UIAlertAction actionWithTitle:NSLocalizedString(@"Continue, but never show me this again", nil)
+                                                                     style:UIAlertActionStyleDestructive
+                                                                   handler:^(UIAlertAction *action){
+                                                                       [weakSelf.model suppressCheckServerCertForCurrentGateway];
+                                                                       [weakSelf.model continueLogin];
+                                                                   }];
+    UIAlertAction *alertActionDefault = [UIAlertAction actionWithTitle:NSLocalizedString(@"Continue", nil)
+                                                                 style:UIAlertActionStyleDefault
+                                                               handler:^(UIAlertAction *action){
+                                                                   [weakSelf.model continueLogin];
+                                                               }];
+    UIAlertAction *alertActionCancel = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
+                                                                style:UIAlertActionStyleCancel
+                                                              handler:^(UIAlertAction *action){
+                                                                  [weakSelf didFinishLogin:NO];
+                                                              }];
+    [alertController addAction:alertActionDestructive];
+    [alertController addAction:alertActionDefault];
+    [alertController addAction:alertActionCancel];
+    UIPopoverPresentationController *popover = alertController.popoverPresentationController;
+    if (popover){
+        popover.sourceView = self.view;
+        popover.sourceRect = CGRectMake(self.view.bounds.size.width/2.0, self.view.bounds.size.height, 1.0, 1.0);
+        popover.permittedArrowDirections = UIPopoverArrowDirectionAny;
+    }
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [self presentViewController:alertController animated:YES completion:nil];
+    });
+}
+
+- (void)needLogout {
+    ANInfo(@"Need logout current session");
+    
+    __weak typeof(self) weakSelf = self;
+    NSString *message = [NSString stringWithFormat:NSLocalizedString(@"There is currently an active connection to %@, you can disconnect the current session,\
+                                                                     and start a new connection, or display the active connection.", nil),
+                                                                    [AAAManager sharedInstance].account.vsHost];
+    PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+                                                                   message:message
+                                                              confirmTitle:NSLocalizedString(@"Active Connection",nil)
+                                                               cancelTitle:NSLocalizedString(@"New Connection", nil)
+                                                             confirmAction:^{
+                                                                 [weakSelf logoutThenLogin];
+                                                             }
+                                                              cancelAction:nil];
+    
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)needVDIAuth {
+    __weak typeof(self) weakSelf = self;
+    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"VDI Credential", nil)
+                                                                             message:NSLocalizedString(@"Please input username and password", nil)
+                                                                      preferredStyle:UIAlertControllerStyleAlert];
+    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
+                                                           style:UIAlertActionStyleCancel
+                                                         handler:^(UIAlertAction * _Nonnull action) {
+                                                             [weakSelf.model loginWithVDIUsername:nil password:nil];
+                                                         }];
+    UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
+                                                            style:UIAlertActionStyleDefault
+                                                          handler:^(UIAlertAction * _Nonnull action) {
+                                                              NSString *username = alertController.textFields[0].text;  // Username text field
+                                                              NSString *password = alertController.textFields[1].text;  // Password text field
+                                                              username = [username stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
+                                                              
+                                                              [weakSelf.model loginWithVDIUsername:username password:password];
+                                                          }];
+    
+    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = NSLocalizedString(@"Username", nil);
+    }];
+    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = NSLocalizedString(@"Password", nil);
+    }];
+    [alertController addAction:confirmAction];
+    [alertController addAction:cancelAction];
+    
+    [self presentViewController:alertController animated:YES completion:nil];
+}
+
+- (void)needDoPreLoginCV {
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{
+        [[RulesManager sharedInstance].interactionHandler takeAction];
+    });
+}
+
+- (void)loginError:(NSString *)message {
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [self didFinishLogin:NO];
+    });
+    if (!message) {
+        return;
+    }
+    
+    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:message];
+    
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)loginErrorOfTip:(NSString *)message {
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [self didFinishLogin:NO];
+    });
+    if (!message) {
+        return;
+    }
+    
+    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Tips",nil) message:message];
+    
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)loginFinished:(BOOL)success {
+    [self didFinishLogin:success];
+    
+    [self.navigationController.view stopLoading];
+}
+
+- (void)checkVerifyMothod {
+    Gateway *gateway = [self.model currentGateway];
+    NSString *username = gateway.username;
+    NSString *port = gateway.port;
+    
+    _realPasswords = @[@"", @"", @""];
+    NSDictionary *methodDic = [Singleton getCurrentGatewayMethod:[self.model currentGateway]];
+    NSString *lastName = [methodDic objectForKey:@"userName"] ?: @"";
+    if ([username isEqualToString:@""]){
+        
+        username = lastName;
+    }
+    
+    if (username != nil) {
+        if (!gateway.lastAccessedDate) {  // Prevent from getting saved password after reinstall.
+            [PasswordManager removePasswordsOfHost:gateway.host username:username port:port];
+        }
+        if ([username isEqualToString:lastName] && (gateway.isGestureEnabled || gateway.isFaceOrTouchIDEnabled)) {
+            
+            _realPasswords = [PasswordManager passwordsOfHost:gateway.host username:username port:port];
+            if (![_realPasswords isEqual:@[@"", @"", @""]]){
+                
+                [self mutilVerifyMothod];
+                return;
+            }
+        } else {
+            ANDebug(@"delete user \"%@\" password", username?username:@"nil");
+            [Singleton setCurrentGatewayMethod:@{} andKey:gateway];
+        }
+    }
+    [self performSegueWithIdentifier:kSegueToLogin sender:self];
+}
+
+#pragma mark - 生物认证 手势认证
+-(void) mutilVerifyMothod
+{
+    Gateway *gw = [self.model currentGateway];
+    if (gw.isFaceOrTouchIDEnabled || gw.isGestureEnabled){
+        
+        [Singleton sharedSingleton].isAuthentication = YES;
+        LocalAuthFinishBlockType completeBlock = ^(BOOL isAllow, SecuritySettingOption authType){
+            
+            [Singleton sharedSingleton].isAuthentication = isAllow;
+            if (isAllow){
+                
+                self.isAutoLogin = YES;
+                [self login];
+            }
+        };
+        UIViewController *control = [LocalAuthUtil getAuthVCWithCompletion:completeBlock];
+        control.modalPresentationStyle = UIModalPresentationFullScreen;
+        [self presentViewController:control animated:YES completion:nil];
+    }
+}
+
+- (void)login {
+    
+    VPNAccount *account = [self inputResult];
+    
+    if (account == nil) {
+        ANWarn(@"Cannot get account information");
+        return;
+    }
+    
+    InformationToSave *info = [InformationToSave sharedInstance];
+    
+    info.lastLoginAccount = account;
+    [info save];
+    
+    AAAManager *manager = [AAAManager sharedInstance];
+    manager.errorCode = 0; // Success
+    [manager continueVPNThreadWithAccount:account];
+}
+
+- (VPNAccount *)inputResult {
+    
+    AAAManager *manager = [AAAManager sharedInstance];
+    
+    VPNAccount * account = manager.account;
+    
+    NSDictionary *methodDic = [Singleton getCurrentGatewayMethod:[self.model currentGatewayUpInside]];
+    
+    NSString *methodType = [methodDic objectForKey:@"methodType"];
+    if ([methodType isEqualToString:@"0"]){
+        
+        [Singleton sharedSingleton].isSupportAuth = YES;
+    }else{
+        
+        [Singleton sharedSingleton].isSupportAuth = NO;
+    }
+    
+    account.loginMethod = [methodDic objectForKey:@"methodName"] ?: @"";
+    account.userName = [methodDic objectForKey:@"userName"] ?: @"";
+    
+    account.passWord  = _realPasswords[0]  ?: @"";
+    account.passWord2 = _realPasswords[1]  ?: @"";
+    account.passWord3 = _realPasswords[2]  ?: @"";
+    
+    UIDevice *devInfo = [UIDevice currentDevice];
+    account.deviceName =[NSString stringWithFormat:@"%@|Apple;%@;iOS %@", devInfo.name, devInfo.platformString, devInfo.systemVersion];
+    
+    return account;
+}
+
+-(void) cancelConnection
+{
+    [self didFinishLogin:NO];
+    [[AAAManager sharedInstance] cancelLoginTapped];
+}
+
+-(void) jumpToLoginIn
+{
+    [self performSegueWithIdentifier:kSegueToLogin sender:self];
+}
+
+- (void)handleVPNNotification:(NSNotification *)notification {
+    //only faceid/touchid/gestuer auth
+    if (!self.isAutoLogin){
+        
+        return;
+    }
+    
+    VPNMessage *message = notification.object;
+    AAAManager *manager = [AAAManager sharedInstance];
+    NSInteger error = manager.errorCode;
+    NSString *aMessage;
+    
+    switch (message.code) {
+        case VPN_CB_CONNECTED: {
+            if (!self.isLocalDB){
+                
+                [self pop];
+            }
+            [self didFinishLogin:YES];
+            break;
+        }
+        case VPN_CB_DISCONNECTING: {
+            if (!self.isLocalDB){
+                
+                [self pop];
+            }
+            self.isAutoLogin = NO;
+            [self didFinishLogin:NO];
+            break;
+        }
+        case VPN_CB_CHALLENGE: {
+            self.isLocalDB = NO;
+            [self performSegueWithIdentifier:kSegueToChallenge sender:nil];
+            break;
+        }
+        case VPN_CB_CONN_FAILED: {
+            switch (error) {
+                case ERR_WRONG_USER_PASS:
+                    aMessage = manager.errorInformation;
+                    break;
+                case ERR_AUTHORIZE_FAILED:
+                    aMessage = NSLocalizedString(@"Login failed", nil);
+                    break;
+                case ERR_CALLBACK_FAILED:
+                    break;
+                case ERR_INTERRUPTED:
+                    break;
+                case ERR_CLIENT_SECURITY:
+                    aMessage = NSLocalizedString(@"Client security is not supported", nil);
+                    break;
+                case ERR_SMS_GET_PHONE:
+                    aMessage = NSLocalizedString(@"The system failed to get your phone number to do OTP authentication", nil);
+                    break;
+                case ERR_SMS_SEND:
+                    aMessage = NSLocalizedString(@"The system failed to send message to your phone", nil);
+                    break;
+                case ERR_SMS_TOO_MANY_RETRY:
+                    aMessage = NSLocalizedString(@"Your attempt to sign in failed, because you have entered wrong SMS verification code for too many times", nil);
+                    break;
+                case ERR_HWID_DENY:
+                    aMessage = NSLocalizedString(@"The device is denied because of wrong hardware ID!", nil);
+                    break;
+                case ERR_HWID_PENDING:
+                    aMessage = NSLocalizedString(@"The hardware ID of this device is not approved yet!", nil);
+                    break;
+                default:
+                    ANError(@"Login failed with error message: %@", aMessage);
+                    break;
+            }
+            
+            Gateway *gw = [[[GatewayModel alloc] init] currentGatewayUpInside];
+            if (!gw.isShowLoginDialogEnabled) {
+                if (aMessage && aMessage.length > 0) {
+                    if (![aMessage containsString:@"<a href='"]) {
+                        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:aMessage];
+                        [self presentViewController:dialog animated:YES completion:nil];
+                    } else {
+                        ANInfo(@"Connect failed:Error message=%@", aMessage);
+                        NSRange subStrRange = [aMessage rangeOfString:@"<a href='"];
+                        NSMutableString *finalMessage = [NSMutableString stringWithString:aMessage];
+                        [finalMessage deleteCharactersInRange:NSMakeRange(subStrRange.location, (int)strlen("<a href='"))];
+                        NSString *displayMessage = [finalMessage substringToIndex:[finalMessage rangeOfString:@"'>"].location];
+                        ANInfo(@"Connect failed:Display message=%@", displayMessage);
+                        
+                        NSString *URLMessage = [aMessage substringFromIndex:(subStrRange.location + subStrRange.length)];
+                        URLMessage = [URLMessage substringToIndex:[URLMessage rangeOfString:@"'>"].location];
+                        ANInfo(@"URL message=%@", URLMessage);
+                        
+                        PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil) message:displayMessage confirmAction:^{
+                                                                    NSURL *url = [NSURL URLWithString:URLMessage];
+                                                                    OpenURL(url);
+                                                                    }
+                                                        cancelAction:nil];
+                        [self presentViewController:popup animated:YES completion:nil];
+                    }
+                }
+            }
+            
+            break;
+        }
+        case VPN_CB_LOGIN:{
+            if (error == ERR_WRONG_USER_PASS || error == ERR_USER_LOCKED) {
+                __weak typeof(self) weakSelf = self;
+                if (![manager.errorInformation containsString:@"<a href='"]) {
+                    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                                  message:[self loginFailedMessage:error]
+                                                                                   action:^{
+                                                                                       [weakSelf showLoginActivity:NO];
+                                                                                   }];
+                    [self presentViewController:dialog animated:YES completion:nil];
+                } else {
+                    ANInfo(@"Error message=%@", manager.errorInformation);
+                    NSRange subStrRange = [manager.errorInformation rangeOfString:@"<a href='"];
+                    NSMutableString *finalMessage = [NSMutableString stringWithString:manager.errorInformation];
+                    [finalMessage deleteCharactersInRange:NSMakeRange(subStrRange.location, (int)strlen("<a href='"))];
+                    NSString *displayMessage = [finalMessage substringToIndex:[finalMessage rangeOfString:@"'>"].location];
+                    ANInfo(@"Display message=%@", displayMessage);
+                    
+                    NSString *URLMessage = [manager.errorInformation substringFromIndex:(subStrRange.location + subStrRange.length)];
+                    URLMessage = [URLMessage substringToIndex:[URLMessage rangeOfString:@"'>"].location];
+                    ANInfo(@"URL message=%@", URLMessage);
+                    
+                    PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil) message:displayMessage confirmAction:^{
+                                                                NSURL *url = [NSURL URLWithString:URLMessage];
+                                                                OpenURL(url);
+                                                                [weakSelf showLoginActivity:NO];
+                        
+                                                                // If password is wrong, pop to root view.
+                                                                [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                }
+                                               cancelAction:^{
+                                                                [weakSelf showLoginActivity:NO];
+                                                                // If password is wrong, pop to root view.
+                                                                [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                }];
+                    [self presentViewController:popup animated:YES completion:nil];
+                }
+            } else if (error == ERR_AUTHORIZE_FAILED) {
+                PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@""
+                                                                              message:NSLocalizedString(@"Authorize failed",nil)];
+                [self presentViewController:dialog animated:YES completion:nil];
+                
+            }
+        }
+        case VPN_CB_SMS: {
+            self.isLocalDB = NO;
+            if ([self.navigationController.topViewController isKindOfClass:[SMSViewController class]]) {
+                [self refreshTopView];
+            } else {
+                [self performSegueWithIdentifier:kSegueToSMS sender:nil];
+            }
+            break;
+        }
+        case VPN_CB_CHANGPASSWORD: {
+            self.isLocalDB = NO;
+            [self performSegueWithIdentifier:kSegueToChangePassword sender:nil];
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+- (NSString *)loginFailedMessage:(NSInteger)errorCode {
+    AAAManager *manager = [AAAManager sharedInstance];
+    
+    if (errorCode == ERR_USER_LOCKED) {
+        NSString *errorMessage = manager.errorInformation;
+        if (errorMessage && errorMessage.length > 0) {
+            return errorMessage;
+        }
+    }
+    
+    NSString *errorMessage = manager.errorInformation;
+    if (errorMessage && errorMessage.length > 0) {
+        return errorMessage;
+    }
+    
+    // Return this string for all login error (incorrect username or password) except SMX auth.
+    return NSLocalizedString(@"Login failed, please check username and password", nil);
+}
+
+- (void)refreshTopView {
+    UIViewController *top = [self.navigationController topViewController];
+    SEL handler = NSSelectorFromString(@"refreshView");
+    if ([top respondsToSelector:handler]) {
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+        [top performSelector:handler];
+    }
+}
+
+- (void)pop {
+    if (self.navigationController.viewControllers.count > 1) {
+        [self.navigationController popViewControllerAnimated:YES];
+    }else{
+        [self dismissViewControllerAnimated:YES completion:nil];
+    }
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LogLevelViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LogLevelViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LogLevelViewController.h	(working copy)
@@ -0,0 +1,13 @@
+//
+//  LogLevelViewController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/11.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface LogLevelViewController : UITableViewController
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LogLevelViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LogLevelViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LogLevelViewController.m	(working copy)
@@ -0,0 +1,154 @@
+//
+//  LogLevelViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/11.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "ANLogger.h"
+#import "AAAManager.h"
+#import "LogLevelViewController.h"
+
+#define TOTAL_SECTION       1
+#define TOTAL_ROWS          4
+
+typedef NS_ENUM(NSInteger, LogLevelIndex) {
+    kLogLevelIndexDebug = 0,
+    kLogLevelIndexInfo,
+    kLogLevelIndexWarn,
+    kLogLevelIndexError,
+};
+
+@interface LogLevelViewController ()
+
+@property (nonatomic) NSInteger selectedIndex;
+@property (weak, nonatomic) IBOutlet UIImageView *debugImageView;
+@property (weak, nonatomic) IBOutlet UIImageView *infoImageView;
+@property (weak, nonatomic) IBOutlet UIImageView *warnImageView;
+@property (weak, nonatomic) IBOutlet UIImageView *errorImageView;
+
+@end
+
+@implementation LogLevelViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    
+    [self showLogLevel];
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (void)showLogLevel {
+    NSInteger currentLevel = [self getCurrentLogLevel];
+    
+    switch (currentLevel) {
+        case ArrayLogLevelDebug:
+            [self showLogLevelAsDebug];
+            break;
+        case ArrayLogLevelInfo:
+            [self showLogLevelAsInfo];
+            break;
+        case ArrayLogLevelWarn:
+            [self showLogLevelAsWarn];
+            break;
+        case ArrayLogLevelError:
+            [self showLogLevelAsError];
+            break;
+            
+        default:
+            break;
+    }
+}
+
+- (void)showLogLevelAsDebug {
+    self.debugImageView.hidden = NO;
+    self.infoImageView.hidden = YES;
+    self.warnImageView.hidden = YES;
+    self.errorImageView.hidden = YES;
+    
+    self.selectedIndex = kLogLevelIndexDebug;
+}
+
+- (void)showLogLevelAsInfo {
+    self.debugImageView.hidden = YES;
+    self.infoImageView.hidden = NO;
+    self.warnImageView.hidden = YES;
+    self.errorImageView.hidden = YES;
+    
+    self.selectedIndex = kLogLevelIndexInfo;
+}
+
+- (void)showLogLevelAsWarn {
+    self.debugImageView.hidden = YES;
+    self.infoImageView.hidden = YES;
+    self.warnImageView.hidden = NO;
+    self.errorImageView.hidden = YES;
+    
+    self.selectedIndex = kLogLevelIndexWarn;
+}
+
+- (void)showLogLevelAsError {
+    self.debugImageView.hidden = YES;
+    self.infoImageView.hidden = YES;
+    self.warnImageView.hidden = YES;
+    self.errorImageView.hidden = NO;
+    
+    self.selectedIndex = kLogLevelIndexError;
+}
+
+- (NSInteger)getCurrentLogLevel {
+    return [[ANLogger sharedInstance] currentLogLevel];
+}
+
+- (void)setLogLevel:(NSInteger)level {
+    [[ANLogger sharedInstance] setLogLevel:level];
+    [[AAAManager sharedInstance] setLogLevel:(int)level];
+}
+
+#pragma mark - Table view data source
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return TOTAL_SECTION;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return TOTAL_ROWS;
+}
+
+#pragma mark - UITableViewDelegate
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    return 15;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    switch (indexPath.row) {
+        case kLogLevelIndexDebug:
+            [self showLogLevelAsDebug];
+            break;
+        case kLogLevelIndexInfo:
+            [self showLogLevelAsInfo];
+            break;
+        case kLogLevelIndexWarn:
+            [self showLogLevelAsWarn];
+            break;
+        case kLogLevelIndexError:
+            [self showLogLevelAsError];
+            break;
+            
+        default:
+            break;
+    }
+    
+    [self setLogLevel:self.selectedIndex];
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LogSettingsViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LogSettingsViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LogSettingsViewController.h	(working copy)
@@ -0,0 +1,13 @@
+//
+//  LogSettingsViewController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/11.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface LogSettingsViewController : UITableViewController
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LogSettingsViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LogSettingsViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LogSettingsViewController.m	(working copy)
@@ -0,0 +1,113 @@
+//
+//  LogSettingsViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/11.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <MessageUI/MessageUI.h>
+#import "Global.h"
+#import "ANLogger.h"
+#import "ANPopupDialog.h"
+#import "LogSettingsViewController.h"
+
+#define TOTAL_SECTION       1
+#define TOTAL_ROWS          3
+
+typedef NS_ENUM(NSInteger, LogSettingsIndex) {
+    kLogSettingsEnable = 0,
+    kLogSettingsLevel,
+    kLogSettingsSend,
+};
+
+@interface LogSettingsViewController ()
+
+@property (weak, nonatomic) IBOutlet UISwitch *enableLogSwitch;
+@property (weak, nonatomic) IBOutlet UITableViewCell *logLevelCell;
+@property (weak, nonatomic) IBOutlet UITableViewCell *sendLogCell;
+
+@property (strong, nonatomic) UIActivityViewController *activityViewController;
+
+@end
+
+@implementation LogSettingsViewController
+
+@synthesize activityViewController;
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    
+    BOOL isEnabled = [ANLogger sharedInstance].enabled;
+    self.enableLogSwitch.on = isEnabled;
+    [self setLogLevelCellAsEnabled:isEnabled];
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (IBAction)enableLogSwitched:(id)sender {
+    BOOL isOn = self.enableLogSwitch.on;
+    [[ANLogger sharedInstance] setEnabled:isOn];
+    
+    [self setLogLevelCellAsEnabled:isOn];
+}
+
+- (void)setLogLevelCellAsEnabled:(BOOL)isEnabled {
+    self.logLevelCell.userInteractionEnabled = isEnabled;
+    self.logLevelCell.contentView.alpha = isEnabled ? 1.0 : 0.5;
+}
+
+#pragma mark - Table view data source
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return TOTAL_SECTION;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return TOTAL_ROWS;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    return 15;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+- (UIActivityViewController *)activityViewController {
+    NSString *anLog = [[ANLogger sharedInstance] pathToLogFile];
+    NSString *tunnelLogPath = [[[ANLogger sharedInstance] logDirectory] stringByAppendingPathComponent:kANTunnelFileName];
+    NSURL *anLogURL = [NSURL fileURLWithPath:anLog];
+    NSURL *tunneLogURL = [NSURL fileURLWithPath:tunnelLogPath];
+    NSArray *activityItems = @[anLogURL, tunneLogURL];
+    
+    activityViewController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil];
+    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
+        activityViewController.popoverPresentationController.sourceView = self.sendLogCell;
+    }
+    activityViewController.completionWithItemsHandler = ^(UIActivityType activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
+        ANInfo(@"Share log activityType: %@", activityType);
+        if (completed) {
+            ANInfo(@"Share log result: completed");
+        } else  {
+            ANInfo(@"Share log result: cancelled");
+        }
+    };
+    
+    return activityViewController;
+}
+
+#pragma mark - UITableViewDelegate
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
+    
+    if (indexPath.section == 0 && indexPath.row == kLogSettingsSend) {
+        [self presentViewController:self.activityViewController animated:YES completion:nil];
+    }
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LoginViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LoginViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LoginViewController.h	(working copy)
@@ -0,0 +1,23 @@
+//
+//  LoginViewController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/19.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "Global.h"
+
+@protocol LoginControllerDelegate <NSObject>
+
+- (void)didFinishLogin:(BOOL)success;
+- (void)continueLoginWithUrl:(NSString *)url callback:(NSString *)callback;
+
+@end
+
+@interface LoginViewController : UIViewController <ANViewControllerSwitchProtocol>
+
+@property (weak, nonatomic) id<LoginControllerDelegate> delegate;
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LoginViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LoginViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LoginViewController.m	(working copy)
@@ -0,0 +1,1342 @@
+//
+//  LoginViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/19.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "ANLogger.h"
+#import "AAAManager.h"
+#import "GatewayManager.h"
+#import "ArrayVPNWrapper.h"
+#import "PasswordManager.h"
+#import "InformationToSave.h"
+#import "DropMenuView.h"
+#import "ANPopupDialog.h"
+#import "FilterTypeModel.h"
+#import "UIDevice+Hardware.h"
+#import "SMSViewController.h"
+#import "SyferLockLoginViewController.h"
+#import "UIViewController+Activity.h"
+#import "UIViewController+HideKeyboard.h"
+#import "LoginViewController.h"
+#import "GatewayModel.h"
+#import "Singleton.h"
+
+static NSString * const methodCellID = @"LoginMethodCell";
+static NSString * const usernameCellID = @"LoginUsernameCell";
+static NSString * const passwordCellID = @"LoginPasswordCell";
+
+static NSString * const kSegueToChangePassword = @"LoginToChangePassword";
+static NSString * const kSegueToRegister = @"LoginToRegister";
+static NSString * const kSegueToChallenge = @"LoginToChallenge";
+static NSString * const kSegueToSMS = @"LoginToSMS";
+static NSString * const kSegueToSMX = @"LoginToSMX";
+static NSString * const kSegueToSMXChangePassword = @"LoginToSMXChangePassword";
+static NSString * const kSegueToSMXConfirmPassword = @"LoginToSMXConfirmPassword";
+static NSString * const kSegueToSyferLock = @"LoginToSyferLock";
+
+NSString * const kAppGroupNameLogin = @"group.net.arraynetworks.MotionProPlus";
+
+#define VIEW_CONTROLLER_ID_SMX_LOGIN            @"SMXLoginViewControllerID"
+#define VIEW_CONTROLLER_ID_SMX_NEWPASS          @"SMXNewPasswordViewControllerID"
+#define VIEW_CONTROLLER_ID_SMX_CONFIRM          @"SMXConfirmPasswordViewControllerID"
+
+#define TABLEVIEW_HEADER_HEIGHT         15
+#define TABLEVIEW_FOOTER_HEIGHT         CGFLOAT_MIN
+#define TABLEVIEW_CELL_HEIGHT           60
+#define TABLEVIEW_CELL_PADDING          10
+
+#define LABEL_TAG_ON_METHOD_CELL        1
+#define IMAGE_VIEW_TAG_ON_METHOD_CELL   2
+#define TEXTFIELD_TAG_ON_USERNAME_CELL  1
+#define TEXTFIELD_TAG_ON_PASSWORD_CELL  1
+
+#define DUMMY_PASSWD                    @"##&&**"
+#define OAUTH_SESSION_URL               @"/prx/000/http/localh/"
+#define RADIUS_SAVE_PWD                 @"radius_save_pwd"
+
+typedef enum {
+    kLoginCellMethodIndex = 0,
+    kLoginCellUsernameIndex,
+    kLoginCellPasswordIndex,
+    kLoginCellPassword2Index,
+    kLoginCellPassword3Index
+} LoginCellIndex;
+
+#define LOGIN_TABLE_SECTIONS    1
+
+@interface LoginViewController () <DropMenuDelegate, DropMenuDataSource, UITableViewDelegate, UITextFieldDelegate> {
+    DropMenuView    *_methodMenu;
+    
+    BOOL            _isMultiMethods;
+    BOOL            _isOAuthMethods;
+
+    NSArray         *_allMethodNames;
+    NSArray         *_allMethodDescs;
+    NSArray         *_currentTableCells;
+    
+    NSArray         *_realPasswords;
+    
+    VPNAccount      *_account;
+    BOOL            _isSMX;
+    BOOL            _isSyferLock;
+}
+
+@property (nonatomic, readonly) NSString    *currentMethod;
+@property (nonatomic)           NSUInteger  currentMethodIndex;
+@property (nonatomic, readonly) NSArray     *currentTableCells;
+@property (nonatomic, readonly) NSArray     *allMethodNames;
+@property (nonatomic, readonly) NSArray     *allMethodDescs;
+@property (nonatomic, strong)   NSArray     *methodActions;
+@property (nonatomic, strong)   NSArray     *methodRequests;
+@property (nonatomic, strong)   AAAManager  *model;
+@property (nonatomic, strong)   UITextField *usernameTextField;
+@property (nonatomic, strong)   UITextField *password1TextField;
+@property (nonatomic, strong)   UITextField *password2TextField;
+@property (nonatomic, strong)   UITextField *password3TextField;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *tableViewHeightConstraint;
+
+@property (weak, nonatomic) IBOutlet UITableView *tableView;
+@property (weak, nonatomic) IBOutlet UIButton *loginButton;
+
+@property (strong, nonatomic) UIAlertController *alertController;
+@property (weak, nonatomic) IBOutlet UILabel *methodNameLable;
+@property (nonatomic, strong) Gateway *gateWay;
+@property (assign, nonatomic) auth_type_t currentMethodType;
+
+@end
+
+@implementation LoginViewController
+
+- (void)dealloc {
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+    
+    self.model = nil;
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    
+    self.model = [AAAManager sharedInstance];
+    self.gateWay = [[[GatewayModel alloc] init] currentGatewayUpInside];
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleVPNNotification:) name:kVPNMessageNotification object:nil];
+    
+    [self enableHideKeyboard];
+    [self setLoginButtonAppearance];
+    
+    [self getSavedPassword];
+    [self initMethodView];
+    [self tryToAutoLogin];
+    
+    //iOS15新特性
+    if (@available(iOS 15.0, *)) {
+        
+        self.tableView.sectionHeaderTopPadding = 0;
+    }
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (IBAction)loginButtonClicked:(id)sender {
+    NSArray *allDescs = self.allMethodDescs;
+    if (allDescs && allDescs.count > 0) {
+        NSString *methodDesc = [allDescs objectAtIndex:_currentMethodIndex];
+        NSArray *parsedMethodDesc = [self parseMethodDesc:methodDesc];
+        if (parsedMethodDesc.count > 1) {
+            NSString *methodInfo;
+            for (int i = 0; i < parsedMethodDesc.count; i++) {
+                if ([[parsedMethodDesc objectAtIndex:i] containsString:KEY_METHOD_OAUTH]) {
+                    methodInfo = [parsedMethodDesc objectAtIndex:i];
+                    break;
+                }
+            }
+            
+            self.methodActions = [self parseMethodAction:methodInfo];
+            self.methodRequests = [self parseMethodRequest:methodInfo];
+            ANInfo(@"Oauth method action=%@, request =%@", self.methodActions, self.methodRequests);
+            NSString *oAuthurlInfo;
+            
+            for (int i = 0; i < self.methodActions.count; i++) {
+                int iAction = [[self.methodActions objectAtIndex:i] intValue] - 1;
+                if (iAction < self.methodRequests.count) {
+                    oAuthurlInfo = [self.methodRequests objectAtIndex:iAction];
+                    ANInfo(@"Oauth url info=%@", oAuthurlInfo);
+                }
+                
+                if ([oAuthurlInfo length] <= 0) {
+                    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                                  message:NSLocalizedString(@"Login failed, get oAuth info failed.",nil)];
+                    [self presentViewController:dialog animated:YES completion:nil];
+                    return;
+                }
+                if ([oAuthurlInfo containsString:@"http://"] || [oAuthurlInfo containsString:@"https://"]) {
+                    OpenURL([NSURL URLWithString:oAuthurlInfo]);  // Install app.
+                    return;
+                }
+                if ([self saveOAuthCodeLoginInfo:oAuthurlInfo]) {
+                    ANInfo(@"launch customer app and save oauth code info.");
+                    break;
+                }
+            }
+            
+            [self showLoginActivity:NO];
+            [self finishLogin:NO];
+            
+            [[AAAManager sharedInstance] cancelLoginTapped];
+            
+            [self dismissViewControllerAnimated:YES completion:nil];
+            return;
+        }
+    }
+    
+    NSInteger passwordCount = _isMultiMethods ? _currentTableCells.count - 2 : _currentTableCells.count - 1; // Substract method & username fields.
+    if (passwordCount > 0) {
+        if (![self checkPasswordFieldWithPasswordCount:passwordCount]) {
+            return;
+        }
+    }
+    
+    [self login];
+}
+
+- (IBAction)exitButtonClicked:(id)sender {
+    [self showLoginActivity:NO];
+    [self finishLogin:NO];
+    
+    [[AAAManager sharedInstance] cancelLoginTapped];
+    
+    [self dismissViewControllerAnimated:YES completion:nil];
+}
+
+- (void)setLoginButtonAppearance {
+    self.loginButton.layer.cornerRadius = 2.5;
+    self.loginButton.layer.shadowOffset = CGSizeMake(5.0, 5.0);
+    self.loginButton.layer.shadowColor = MAIN_COLOR.CGColor;
+    self.loginButton.layer.shadowOpacity = 0.25;
+}
+
+- (void)initMethodView {
+    if ([self allAAAMethods].count == 0) {
+        __weak typeof(self) weakSelf = self;
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                      message:NSLocalizedString(@"Incorrect server configuration!",nil)
+                                                                       action:^{
+                                                                           [weakSelf cancelLogin];
+                                                                       }];
+        [self presentViewController:dialog animated:YES completion:nil];
+    } else if ([self allAAAMethods].count > 1) {
+        _isMultiMethods = YES;
+    }else if ([self allAAAMethods].count > 0 && self.model.isOAuthType){ //认证方式
+        
+        _isMultiMethods = YES;
+    }
+    
+    _currentMethodIndex = 0;
+    _currentTableCells = [self cellsForMethodIndex:_currentMethodIndex];
+    if (_currentTableCells.count == 0) {
+        // Only deviceID auth, auto login.
+        __weak typeof(self) weakSelf = self;
+        dispatch_async(dispatch_get_main_queue(), ^{
+            [weakSelf login];
+        });
+    }
+}
+
+- (NSArray *)allAAAMethods {
+    return [self.model allAAAMehtods];
+}
+
+#pragma mark - Properties
+
+- (NSString *)currentMethod {
+    NSArray *allNames = self.allMethodNames;
+    if (!allNames || allNames.count == 0) {
+        return nil;
+    } else {
+        return [allNames objectAtIndex:_currentMethodIndex];
+    }
+}
+
+-(auth_type_t) currentMethodType{
+    
+    NSArray *typeArray = [self allAAAMethods];
+    
+    if (!typeArray || typeArray.count == 0) {
+        return -1;
+    } else {
+        
+        AAAMethod *method = [typeArray objectAtIndex:_currentMethodIndex];
+        if (method != nil){
+            
+            return method.authType;
+        }
+    }
+    return -1;
+}
+
+- (void)setCurrentMethodIndex:(NSUInteger)currentMethodIndex {
+    if (_currentMethodIndex == currentMethodIndex) {
+        return;
+    }
+    
+    _currentMethodIndex = currentMethodIndex;
+    _currentTableCells = [self cellsForMethodIndex:_currentMethodIndex];
+}
+
+- (NSArray*)allMethodNames {
+    if (_allMethodNames != nil) {
+        return _allMethodNames;
+    }
+    
+    NSMutableArray *names = [[NSMutableArray alloc] init];
+    
+    for (AAAMethod *method in [self allAAAMethods]) {
+        [names addObject:method.name];
+    }
+    
+    _allMethodNames = names;
+    
+    return _allMethodNames;
+}
+
+- (NSArray*)allMethodDescs {
+    if (_allMethodDescs != nil) {
+        return _allMethodDescs;
+    }
+    
+    NSMutableArray *descs = [[NSMutableArray alloc] init];
+    
+    for (AAAMethod *method in [self allAAAMethods]) {
+        [descs addObject:method.methodDescription];
+    }
+    
+    _allMethodDescs = descs;
+    
+    return _allMethodDescs;
+}
+
+#pragma mark - Parse Method
+
+- (NSArray *)parseMethodDesc:(NSString *)methodDesc {
+    NSMutableArray *methodParsed = [[NSMutableArray alloc] init];
+    
+    if ([methodDesc containsString:KEY_METHOD_OAUTH] && [methodDesc containsString:KEY_METHOD_MOBILE_ENABLE]) {
+        NSCharacterSet *delimiters = [NSCharacterSet characterSetWithCharactersInString:@"()"];
+        return [methodDesc componentsSeparatedByCharactersInSet:delimiters];
+    } else {
+        [methodParsed addObject:methodDesc];
+    }
+    
+    return methodParsed;
+}
+
+- (NSArray *)parseMethodAction:(NSString *)methodInfo {
+    NSString *methodAction;
+    NSMutableArray *actionArray = [[NSMutableArray alloc] init];
+    
+    if (methodInfo && [methodInfo containsString:KEY_METHOD_MOBILE_ENABLE]) {
+        NSArray *methodInfoArray = [methodInfo componentsSeparatedByString:@"@"];
+        for (int i = 0; i < methodInfoArray.count; i++) {
+            methodInfo = [methodInfoArray objectAtIndex:i];
+            if ([methodInfo containsString:KEY_METHOD_ACTION]) {
+                NSRange range = [methodInfo rangeOfString:KEY_METHOD_ACTION];
+                methodInfo = [methodInfo substringFromIndex:range.location + range.length];
+                NSArray *methodActionArray = [methodInfo componentsSeparatedByString:@"&"];
+                for(int j = 0; j < methodActionArray.count; j++) {
+                    methodInfo = [methodActionArray objectAtIndex:j];
+                    if ([methodInfo containsString:KEY_METHOD_MOBILE]) {
+                        range = [methodInfo rangeOfString:KEY_METHOD_MOBILE];
+                        methodAction = [methodInfo substringFromIndex:range.location + range.length];
+                        
+                        break;
+                    }
+                }
+            }
+        }
+        
+        if (methodAction.length > 0) {
+            for (int i = 0; i < methodAction.length; i ++) {
+                NSString *temp = [methodAction substringWithRange:NSMakeRange(i, 1)];
+                [actionArray addObject:temp];
+            }
+        }
+    }
+    
+    return actionArray;
+}
+
+- (NSArray *)parseMethodRequest:(NSString *)methodInfo {
+    NSMutableArray *methodRequestArray = [[NSMutableArray alloc] init];
+    NSString *methodBuf;
+    NSArray *methodReqArrayBuf;
+    
+    if (methodInfo && [methodInfo containsString:KEY_METHOD_MOBILE_ENABLE]) {
+        NSArray *methodInfoArray = [methodInfo componentsSeparatedByString:@"@"];
+        for (int i = 0; i < methodInfoArray.count; i++) {
+            methodBuf = [methodInfoArray objectAtIndex:i];
+            if ([methodBuf containsString:@"request"]) {
+                methodReqArrayBuf = [methodBuf componentsSeparatedByString:@"&"];
+                break;
+            }
+        }
+        
+        for (int i = 0; i < methodReqArrayBuf.count; i ++) {
+            NSString *req = [methodReqArrayBuf objectAtIndex:i];
+            req = [req substringFromIndex:9];
+            [methodRequestArray addObject:req];
+        }
+    }
+    
+    return methodRequestArray;
+}
+
+- (BOOL)saveOAuthCodeLoginInfo:(NSString *)oauthInfo {
+    if (![oauthInfo containsString:KEY_METHOD_RELIAO]) {
+        return NO;
+    }
+    
+    NSString *reliaoURL = @"reliao://f/vpn?action=login&callback=motionproplus%3a%2f%2fsetcode%3fcode%3d";
+    NSURL *url = [NSURL URLWithString:reliaoURL];
+    
+    if (![[UIApplication sharedApplication] canOpenURL:url]) {
+        return NO;
+    }
+    
+    oauthInfo = [oauthInfo substringToIndex:[oauthInfo rangeOfString:KEY_METHOD_RELIAO].location];
+    Gateway *gateway = [self currentGateway];
+    NSString *urlString = nil;
+    if ([gateway.port isEqualToString:@"443"]) {
+        urlString = [NSString stringWithFormat:@"https://%@%@%@", gateway.host, OAUTH_SESSION_URL, oauthInfo];
+    } else {
+        urlString = [NSString stringWithFormat:@"https://%@:%@%@%@", gateway.host, gateway.port, OAUTH_SESSION_URL, oauthInfo];
+    }
+    ANInfo(@"continue login url=%@", urlString);
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameLogin];
+    [userDefaults setValue:urlString forKey:KEY_OAUTH_URL];
+    
+    return YES;
+}
+
+#pragma mark - Login Related
+- (void)login {
+    ANInfo(@"------------>Start login...<------------");
+    
+    [self.view endEditing:YES];
+    
+    [self getCurrentMethod];
+    
+    VPNAccount *account = [self inputResult];
+    NSLog(@"vpn account on login: %@",account);
+    
+    if (account == nil) {
+        ANWarn(@"Cannot get account information");
+        return;
+    }
+    
+    InformationToSave *info = [InformationToSave sharedInstance];
+    
+    info.lastLoginAccount = account;
+    [info save];
+    
+    self.model.errorCode = 0; // Success
+    [self.model continueVPNThreadWithAccount:account];
+    
+    [self showLoginActivity:YES];
+}
+
+- (void)cancelLogin {
+    [self showLoginActivity:NO];
+    
+    [self.model cancelLoginTapped];
+}
+
+- (VPNAccount *)inputResult {
+    VPNAccount * account = self.model.account;
+    
+    account.loginMethod = self.currentMethod;
+    account.userName = self.usernameTextField.text;
+    
+    //Get account passwords
+    if ([self.password1TextField.text isEqualToString:DUMMY_PASSWD]) {
+        account.passWord = _realPasswords[0];
+    } else {
+        account.passWord = self.password1TextField.text;
+    }
+    
+    if ([self.password2TextField.text isEqualToString:DUMMY_PASSWD]) {
+        account.passWord2 = _realPasswords[1];
+    } else {
+        account.passWord2 = self.password2TextField.text;
+    }
+    
+    if ([self.password3TextField.text isEqualToString:DUMMY_PASSWD]) {
+        account.passWord3 = _realPasswords[2];
+    } else {
+        account.passWord3 = self.password3TextField.text;
+    }
+    
+    UIDevice *devInfo = [UIDevice currentDevice];
+    account.deviceName =[NSString stringWithFormat:@"%@|Apple;%@;iOS %@", devInfo.name, devInfo.platformString, devInfo.systemVersion];
+    
+    return account;
+}
+
+//Get all cells for the given method
+- (NSArray *)cellsForMethodIndex:(NSUInteger)index {
+    NSArray *methods = [self allAAAMethods];
+    if (methods == nil || methods.count == 0) {
+        ANError(@"No method found for login.");
+        return nil;
+    }
+    
+    AAAMethod *method = [methods objectAtIndex:index];
+    if (method == nil) {
+        return nil;
+    }
+    
+    NSMutableArray *cells = [[NSMutableArray alloc] init];
+    
+    for (InputField *field in method.inputFields) {
+        UITableViewCell *cell = [self cellForInputField:field];
+        if (cell == nil) {
+            ANError(@"Unknow inputField type %d", field.type);
+            continue;
+        }
+        
+        if (field.type == FieldTypeUsernameText) {
+            // Make sure Username is above password
+            [cells insertObject:cell atIndex:0];
+        } else {
+            [cells addObject:cell];
+        }
+    }
+    
+    NSString *infoDesc;
+    if (_isMultiMethods) {
+        //Display the method names
+        UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:methodCellID];
+        [self initMethodMenuWithCell:cell];
+        _methodMenu.titleLabel =  (UILabel *)[cell viewWithTag:1];
+        NSArray *pasedMethodDesc = [self parseMethodDesc:method.methodDescription];
+        if (pasedMethodDesc.count > 0) {
+            infoDesc = [pasedMethodDesc objectAtIndex:0];
+        } else {
+            infoDesc = method.methodDescription;
+        }
+        _methodMenu.titleLabel.text = infoDesc;
+        //Method cell shoud be at the top.
+        if (cell != nil) {
+            [cells insertObject:cell atIndex:0];
+        }
+    }
+    
+    return cells;
+}
+
+// Create a cell for the inputed field.
+- (UITableViewCell *)cellForInputField:(InputField *)field {
+    UITableViewCell *cell = nil;
+    
+    Gateway *gateway = [self currentGateway];
+    
+    NSString *username = self.model.account.userName;
+    if (!username || username.length == 0) {
+        username = gateway.username;
+    }
+    
+    NSString *passwd;
+    
+    switch (field.type) {
+        case FieldTypeUsernameText: {
+            //username field
+            cell = [self.tableView dequeueReusableCellWithIdentifier:usernameCellID];
+            self.usernameTextField = (UITextField *)[cell viewWithTag:TEXTFIELD_TAG_ON_USERNAME_CELL];
+            if (field.inputString) {
+                self.usernameTextField.text = field.inputString;
+            } else {
+                self.usernameTextField.text = username;
+            }
+            break;
+        }
+        case FieldTypePasswordText: {
+            switch (field.passwordIndex) {
+                case INDEX_PASSWORD1: {
+                    cell = [self.tableView dequeueReusableCellWithIdentifier:passwordCellID];
+                    self.password1TextField = (UITextField *) [cell viewWithTag:TEXTFIELD_TAG_ON_PASSWORD_CELL];
+                    self.password1TextField.placeholder = [NSString stringWithFormat:@"%@(%@)", NSLocalizedString(@"Password", nil), field.fieldDescription ?: @""];
+                    
+                    passwd = _realPasswords[0];
+                    if (passwd.length > 0) {
+                        self.password1TextField.text = DUMMY_PASSWD;
+                    }
+                    break;
+                }
+                case INDEX_PASSWORD2: {
+                    cell = [self.tableView dequeueReusableCellWithIdentifier:passwordCellID];
+                    self.password2TextField = (UITextField *) [cell viewWithTag:TEXTFIELD_TAG_ON_PASSWORD_CELL];
+                    self.password2TextField.placeholder = [NSString stringWithFormat:@"%@(%@)", NSLocalizedString(@"Password", nil), field.fieldDescription ?: @""];
+                    
+                    passwd = _realPasswords[1];
+                    if (passwd.length > 0) {
+                        self.password2TextField.text = DUMMY_PASSWD;
+                    }
+                    break;
+                }
+                case INDEX_PASSWORD3: {
+                    cell = [self.tableView dequeueReusableCellWithIdentifier:passwordCellID];
+                    self.password3TextField = (UITextField *) [cell viewWithTag:TEXTFIELD_TAG_ON_PASSWORD_CELL];
+                    self.password3TextField.placeholder = [NSString stringWithFormat:@"%@(%@)", NSLocalizedString(@"Password", nil), field.fieldDescription ?: @""];
+                    
+                    passwd = _realPasswords[0];
+                    if (passwd.length > 0) {
+                        self.password3TextField.text = DUMMY_PASSWD;
+                    }
+                    break;
+                }
+                default:
+                    break;
+            }
+            break;
+        }
+        default:
+            break;
+    }
+    
+    return cell;
+}
+
+- (Gateway *)currentGateway {
+    NSString *url = self.model.account.vsURL;
+    NSString *port = self.model.account.vsPort;
+    Gateway *gateway = [[GatewayManager sharedInstance] gatewayOfUrl:url andport:port];
+    
+    return gateway;
+}
+
+- (void)getSavedPassword {
+    Gateway *gateway = [self currentGateway];
+    NSString *username = gateway.username;
+    
+    _realPasswords = @[@"", @"", @""];
+    if (username != nil) {
+        if (!gateway.lastAccessedDate) {  // Prevent from getting saved password after reinstall.
+            [PasswordManager removePasswordsOfHost:gateway.host username:username port:gateway.port];
+        }
+        
+        if (gateway.isSavePasswordEnabled) {
+            _realPasswords = [PasswordManager passwordsOfHost:gateway.host username:username port:gateway.port];
+        } else {
+            ANDebug(@"delete user \"%@\" password", username?username:@"nil");
+            
+            if (!gateway.isFaceOrTouchIDEnabled && !gateway.isGestureEnabled){
+                
+                [self deleteMethodName];
+                [self.model.account deleteAllPasswords];
+            }
+        }
+    }
+}
+
+- (void)tryToAutoLogin {
+    Gateway *gateway = [self currentGateway];
+    BOOL showLoginDialog = gateway.isShowLoginDialogEnabled;
+    
+    if (gateway.isSavePasswordEnabled) {
+        if (!showLoginDialog && (_currentTableCells.count == 1 || ![_realPasswords isEqual:@[@"", @"", @""]])) {
+            dispatch_async(dispatch_get_main_queue(), ^{
+                [self login];
+            });
+        }
+    }
+}
+
+#pragma mark - Table view data source
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return LOGIN_TABLE_SECTIONS;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    NSInteger totalCells = _currentTableCells.count;
+    [self updateTableViewHeightWithCellsNumber:totalCells];
+    return _currentTableCells.count;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    return _currentTableCells[indexPath.row];
+}
+
+- (void)updateTableViewHeightWithCellsNumber:(NSInteger)cells {
+    self.tableViewHeightConstraint.constant = cells * TABLEVIEW_CELL_HEIGHT + TABLEVIEW_CELL_PADDING;
+}
+
+#pragma mark - SyferLock switch
+- (BOOL)isSyferLockEnabled {
+    Gateway *gateway = [self currentGateway];
+    if (!gateway) {
+        ANInfo(@"Current gateway is nil, no syferlock can be enabled.");
+        return NO;
+    } else {
+        return gateway.isSyferLockEnabled;
+    }
+}
+
+#pragma mark - UITableViewDelegate
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    
+    if (@available(iOS 15.0, *)){
+           
+        return 0.1;
+    }
+    
+    return TABLEVIEW_HEADER_HEIGHT;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return TABLEVIEW_FOOTER_HEIGHT;
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    [tableView deselectRowAtIndexPath:indexPath animated:YES];
+    
+    if (indexPath.section == 0 && indexPath.row == kLoginCellMethodIndex && _isMultiMethods) {  // Deal with method drop-down menu.
+        [_methodMenu showMenuOnView:self.view];
+    }
+}
+
+- (BOOL)checkPasswordFieldWithPasswordCount:(NSInteger)count {
+    enum PasswordCount {
+        kPasswordOne = 1,
+        kPasswordTwo = 2,
+        kPasswordThree = 3
+    };
+    
+    BOOL result = YES;
+    
+    switch (count) {
+        case kPasswordOne:
+            if ([self.password1TextField.text isEqualToString:@""]) {
+                result = NO;
+            }
+            break;
+        case kPasswordTwo:
+            if ([self.password1TextField.text isEqualToString:@""] ||
+                [self.password2TextField.text isEqualToString:@""]) {
+                result = NO;
+            }
+            break;
+        case kPasswordThree:
+            if ([self.password1TextField.text isEqualToString:@""] ||
+                [self.password2TextField.text isEqualToString:@""] ||
+                [self.password3TextField.text isEqualToString:@""]) {
+                result = NO;
+            }
+            break;
+        default:
+            break;
+    }
+    
+    if (!result) {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                      message:NSLocalizedString(@"Login failed, please check username and password",nil)];
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+    
+    return result;
+}
+
+- (void)initMethodMenuWithCell:(UITableViewCell *)cell {
+    if (!_methodMenu) {
+        _methodMenu = [[DropMenuView alloc] initWithOrigin:CGPointMake(0, cell.frame.size.height+TABLEVIEW_HEADER_HEIGHT)];
+        _methodMenu.delegate = self;
+        _methodMenu.dataSource = self;
+        _methodMenu.transformImageView = [cell viewWithTag:IMAGE_VIEW_TAG_ON_METHOD_CELL];
+        _methodMenu.titleLabel = nil;
+    }
+    
+    [_methodMenu reloadData];
+}
+
+#pragma mark menuDelegate
+
+- (NSMutableArray<FilterTypeModel *> *)menu_filterDataArray {
+    NSMutableArray *array = nil;
+    NSArray *descs = self.allMethodDescs;
+    NSString *methodDesc;
+    
+    NSInteger index = -1;
+    array = [NSMutableArray arrayWithCapacity:descs.count];
+    for (NSString *desc in descs) {
+        ++index;
+        methodDesc = desc;
+        NSArray *pasedMethodDesc = [self parseMethodDesc:desc];
+        if (pasedMethodDesc.count > 0) {
+            methodDesc = [pasedMethodDesc objectAtIndex:0];
+        }
+        
+        FilterTypeModel *model = [[FilterTypeModel alloc] initWithName:methodDesc andId:[NSString stringWithFormat:@"%zi", index]];
+        [array addObject:model];
+    }
+    
+    return array;
+}
+
+- (void)menu:(DropMenuView *)menu tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    self.currentMethodIndex = indexPath.row;
+    
+    [self.tableView reloadData];
+}
+
+//VPN notifications handler
+- (void)handleVPNNotification:(NSNotification *)notification {
+    VPNMessage *message = notification.object;
+    AAAManager *manager = [AAAManager sharedInstance];
+    NSInteger error = manager.errorCode;
+    NSString *aMessage;
+    BOOL showAlert = YES;
+    
+    switch (message.code) {
+        case VPN_CB_CONNECTED: {
+            if (!_isSMX) {
+                // Save passwords for non-SMX login.
+                [self savePasswordsOfAccount:manager.account];
+            }
+            [self finishLogin:YES];
+            break;
+        }
+        case VPN_CB_DISCONNECTING: {
+            [self finishLogin:NO];
+            break;
+        }
+        case VPN_CB_DEVID_REG: {
+            if (!_isSMX) {
+                // Save the current account
+                // In SMX, the account has been saved.
+                _account = [manager.account copy];
+            } else {
+                // SMX, clean the saved password, since it is useless after register.
+                manager.account.passWord = nil;
+            }
+            
+            [self performSegueWithIdentifier:kSegueToRegister sender:nil];
+            break;
+        }
+        case VPN_CB_CHALLENGE: {
+            [self performSegueWithIdentifier:kSegueToChallenge sender:nil];
+            break;
+        }
+        case VPN_CB_CONN_FAILED: {
+            switch (error) {
+                case ERR_DEVID_APPROVE_PENDING:
+                    aMessage = NSLocalizedString(@"Your device is registering, please request manager approval",nil);
+                    break;
+                case ERR_DEVID_APPROVE_DENY:
+                    aMessage = NSLocalizedString(@"Register device deny, not allow register device auto approve",nil);
+                    break;
+                case ERR_DEVID_USER_LIMIT:
+                    aMessage = NSLocalizedString(@"User for this device has reached his or her limit",nil);
+                    break;
+                case ERR_DEVID_DEV_LIMIT:
+                    aMessage = NSLocalizedString(@"Device has reached its limit",nil);
+                    break;
+                case ERR_WRONG_USER_PASS:
+                    if (!_isSyferLock) {  // DON'T remove saved password if SyferLock is enabled.
+                        [self deleteMethodName];
+                        [manager.account deleteAllPasswords];
+                    }
+                    aMessage = manager.errorInformation;
+                    //aMessage = NSLocalizedString(@"Login failed, please check username and password",nil);
+                    break;
+                case ERR_AUTHORIZE_FAILED:
+                    aMessage = NSLocalizedString(@"Login failed", nil);
+                    break;
+                case ERR_CALLBACK_FAILED:
+                    break;
+                case ERR_INTERRUPTED:
+                    break;
+                case ERR_CLIENT_SECURITY:
+                    aMessage = NSLocalizedString(@"Client security is not supported", nil);
+                    break;
+                case ERR_CERT_NO:
+                    aMessage = NSLocalizedString(@"Client certificate not supply", nil);
+                    break;
+                case ERR_CERT_INVALID_SIGNTURE:
+                    aMessage = NSLocalizedString(@"Client certificate invalid signture", nil);
+                    break;
+                case ERR_CERT_UNTRUSTED:
+                    aMessage = NSLocalizedString(@"Client certificate untrusted", nil);
+                    break;
+                case ERR_CERT_EXPIRED:
+                    aMessage = NSLocalizedString(@"Client certificate expired", nil);
+                    break;
+                case ERR_CERT_INVALID:
+                    aMessage = NSLocalizedString(@"Client certificate invalid", nil);
+                    break;
+                case ERR_CERT_REVOKED:
+                    aMessage = NSLocalizedString(@"Client certificate revoked", nil);
+                    break;
+                case ERR_SMS_GET_PHONE:
+                    aMessage = NSLocalizedString(@"The system failed to get your phone number to do OTP authentication", nil);
+                    break;
+                case ERR_SMS_SEND:
+                    aMessage = NSLocalizedString(@"The system failed to send message to your phone", nil);
+                    break;
+                case ERR_SMS_TOO_MANY_RETRY:
+                    aMessage = NSLocalizedString(@"Your attempt to sign in failed, because you have entered wrong SMS verification code for too many times", nil);
+                    break;
+                case ERR_HWID_DENY:
+                    aMessage = NSLocalizedString(@"The device is denied because of wrong hardware ID!", nil);
+                    break;
+                case ERR_HWID_PENDING:
+                    aMessage = NSLocalizedString(@"The hardware ID of this device is not approved yet!", nil);
+                    break;
+                default:
+                    ANError(@"Login failed with error message: %@", aMessage);
+                    break;
+            }
+            
+            // Try to show error message, only valid on viewcontroller still exists.
+            if (![self currentGateway].isShowLoginDialogEnabled) {
+                if (aMessage && aMessage.length > 0) {
+                    if (![aMessage containsString:@"<a href='"]) {
+                        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:aMessage];
+                        [self presentViewController:dialog animated:YES completion:nil];
+                    } else {
+                        ANInfo(@"Connect failed:Error message=%@", aMessage);
+                        NSRange subStrRange = [aMessage rangeOfString:@"<a href='"];
+                        NSMutableString *finalMessage = [NSMutableString stringWithString:aMessage];
+                        [finalMessage deleteCharactersInRange:NSMakeRange(subStrRange.location, (int)strlen("<a href='"))];
+                        NSString *displayMessage = [finalMessage substringToIndex:[finalMessage rangeOfString:@"'>"].location];
+                        ANInfo(@"Connect failed:Display message=%@", displayMessage);
+                        
+                        NSString *URLMessage = [aMessage substringFromIndex:(subStrRange.location + subStrRange.length)];
+                        URLMessage = [URLMessage substringToIndex:[URLMessage rangeOfString:@"'>"].location];
+                        ANInfo(@"URL message=%@", URLMessage);
+                        
+                        PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil) message:displayMessage confirmAction:^{
+                                                                    NSURL *url = [NSURL URLWithString:URLMessage];
+                                                                    OpenURL(url);
+                                                                    }
+                                                        cancelAction:nil];
+                        [self presentViewController:popup animated:YES completion:nil];
+                    }
+                }
+            }
+            
+            break;
+        }
+        case VPN_CB_LOGIN:
+        case VPN_CB_SYFERLOCK_AUTH: {
+            if (error == ERR_WRONG_USER_PASS || error == ERR_USER_LOCKED) {
+                __weak typeof(self) weakSelf = self;
+                if (![manager.errorInformation containsString:@"<a href='"]) {
+                    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                                  message:[self loginFailedMessage:error]
+                                                                                   action:^{
+                                                                                       [weakSelf showLoginActivity:NO];
+                                                                                       
+                                                                                       // If password is wrong, pop to root view.
+                                                                                       [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                                   }];
+                    [self presentViewController:dialog animated:YES completion:nil];
+                } else {
+                    ANInfo(@"Error message=%@", manager.errorInformation);
+                    NSRange subStrRange = [manager.errorInformation rangeOfString:@"<a href='"];
+                    NSMutableString *finalMessage = [NSMutableString stringWithString:manager.errorInformation];
+                    [finalMessage deleteCharactersInRange:NSMakeRange(subStrRange.location, (int)strlen("<a href='"))];
+                    NSString *displayMessage = [finalMessage substringToIndex:[finalMessage rangeOfString:@"'>"].location];
+                    ANInfo(@"Display message=%@", displayMessage);
+                    
+                    NSString *URLMessage = [manager.errorInformation substringFromIndex:(subStrRange.location + subStrRange.length)];
+                    URLMessage = [URLMessage substringToIndex:[URLMessage rangeOfString:@"'>"].location];
+                    ANInfo(@"URL message=%@", URLMessage);
+                    
+                    PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil) message:displayMessage confirmAction:^{
+                                                                NSURL *url = [NSURL URLWithString:URLMessage];
+                                                                OpenURL(url);
+                                                                [weakSelf showLoginActivity:NO];
+                        
+                                                                // If password is wrong, pop to root view.
+                                                                [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                }
+                                               cancelAction:^{
+                                                                [weakSelf showLoginActivity:NO];
+                                                                // If password is wrong, pop to root view.
+                                                                [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                }];
+                    [self presentViewController:popup animated:YES completion:nil];
+                }
+                
+                if (!_isSyferLock) {
+                    [self removePasswordsOfAccount:manager.account];
+                }
+                
+                ANError(@"Error message: %@", manager.errorInformation);
+            } else if (error == ERR_AUTHORIZE_FAILED) {
+                PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@""
+                                                                              message:NSLocalizedString(@"Authorize failed",nil)];
+                [self presentViewController:dialog animated:YES completion:nil];
+                
+                [self removePasswordsOfAccount:manager.account];
+            } else if (error == ERR_SUCCESS) {
+                //After register, we need to login again. Using the account we have saved.
+                if (!_account) {
+                    _account = [AAAManager sharedInstance].account;
+                }
+                [manager continueVPNThreadWithAccount:_account];
+                
+                break;
+            }
+            break;
+        }
+        case VPN_CB_SMX: {
+            _isSMX = YES;
+            
+            // Save password(s) for multi-step auth.
+            [self savePasswordsOfAccount:manager.account];
+            // Save current account, and use it to login after registering.
+            _account = [manager.account copy];
+            
+            // Clean passwords
+            _account.passWord = nil;
+            
+            ANDebug(@"message.code VPN_CB_SMX %zi", error);
+            
+            vpn_smx_info_t *smx_info = manager.smx_info;
+            if (smx_info != NULL) {
+                ANDebug(@"smx_info->action: %d", smx_info->action);
+                switch (smx_info->action) {
+                    case SMX_ACTION_INPUT_PASS:
+                    case SMX_ACTION_INPUT_OLD_PASS:
+                        if ([self.navigationController.topViewController.restorationIdentifier isEqualToString:VIEW_CONTROLLER_ID_SMX_LOGIN]) {
+                            //If the top controller is login controller, do nothing but send the status to it.
+                            [self refreshTopView];
+                            showAlert = YES;
+                        } else {
+                            [self performSegueWithIdentifier:kSegueToSMX sender:nil];
+                            showAlert = NO;
+                        }
+                        break;
+                    case SMX_ACTION_INPUT_NEW_PASS:
+                        if ([self.navigationController.topViewController.restorationIdentifier isEqualToString:VIEW_CONTROLLER_ID_SMX_NEWPASS]) {
+                            //If the top controller is new password controller, do nothing but send the status to it.
+                            [self refreshTopView];
+                            showAlert = YES;
+                            break;
+                        } else {
+                            [self performSegueWithIdentifier:kSegueToSMXChangePassword sender:nil];
+                            showAlert = NO;
+                        }
+                        break;
+                        
+                    case SMX_ACTION_PASS_CONFIRM:
+                        [self performSegueWithIdentifier:kSegueToSMXConfirmPassword sender:nil];
+                        showAlert = NO;
+                        break;
+                        
+                    default:
+                        break;
+                }
+                
+                if (showAlert && smx_info->errmsg[0] != '\0') {
+                    NSString *errorMessage = [NSString stringWithUTF8String:smx_info->errmsg];
+                    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@"" message:errorMessage];
+                    
+                    [self presentViewController:dialog animated:YES completion:nil];
+                }
+            }
+            break;
+        }
+        case VPN_CB_VDI_AUTH: {
+            [self handleVDIAuth];
+            break;
+        }
+        case VPN_CB_SMS: {
+            if ([self.navigationController.topViewController isKindOfClass:[SMSViewController class]]) {
+                [self refreshTopView];
+            } else {
+                [self performSegueWithIdentifier:kSegueToSMS sender:nil];
+            }
+            break;
+        }
+        case VPN_CB_CHANGPASSWORD: {
+            [self performSegueWithIdentifier:kSegueToChangePassword sender:nil];
+            break;
+        }
+        case VPN_CB_SYFERLOCK_LOGIN: {
+            _isSyferLock = YES;
+            if ([self.navigationController.topViewController isKindOfClass:[SyferLockLoginViewController class]]) {
+                [self refreshTopView];
+            } else {
+                [self performSegueWithIdentifier:kSegueToSyferLock sender:nil];
+            }
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+- (void)refreshTopView {
+    UIViewController *top = [self.navigationController topViewController];
+    SEL handler = NSSelectorFromString(@"refreshView");
+    if ([top respondsToSelector:handler]) {
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+        [top performSelector:handler];
+    }
+}
+
+// If last login method contains SMX.
+- (BOOL)isSMXAuth {
+    AAAManager *manager = [AAAManager sharedInstance];
+    
+    VPNAccount *account = _account;
+    if (!account) {
+        account = manager.account;
+    }
+    
+    NSString *currentMethod = account.loginMethod;
+    
+    NSArray *methods = [self allAAAMethods];
+    for (AAAMethod *method in methods) {
+        if ([method.name isEqualToString:currentMethod]) {
+            return method.isSmx;
+        }
+    }
+    
+    return NO;
+}
+
+- (NSString *)loginFailedMessage:(NSInteger)errorCode {
+    AAAManager *manager = [AAAManager sharedInstance];
+    
+    if ([self isSMXAuth]) {
+        // Get error message for SMX auth
+        NSString *errorMessage = manager.errorInformation;
+        if (errorMessage && errorMessage.length > 0) {
+            return errorMessage;
+        }
+        
+        vpn_smx_info_t *smx_info = manager.smx_info;
+        if (smx_info && strlen(smx_info->errmsg) != 0 && [self isValidSMXAction]) {
+            errorMessage = [NSString stringWithUTF8String:smx_info->errmsg];
+            if (errorMessage && ![errorMessage isEqualToString:@"OK"]) {
+                return errorMessage;
+            }
+        }
+    }
+    
+    if (errorCode == ERR_USER_LOCKED) {
+        NSString *errorMessage = manager.errorInformation;
+        if (errorMessage && errorMessage.length > 0) {
+            return errorMessage;
+        }
+    }
+    
+    NSString *errorMessage = manager.errorInformation;
+    if (errorMessage && errorMessage.length > 0) {
+        return errorMessage;
+    }
+    
+    // Return this string for all login error (incorrect username or password) except SMX auth.
+    return NSLocalizedString(@"Login failed, please check username and password", nil);
+}
+
+- (BOOL)isValidSMXAction {
+    vpn_smx_info_t *smx_info = [AAAManager sharedInstance].smx_info;
+    
+    return  (smx_info->action >= SMX_ACTION_UNKNOWN && smx_info->action <= SMX_ACTION_PASS_CONFIRM);
+}
+
+- (void)handleVDIAuth {
+    __weak typeof(self) weakSelf = self;
+    self.alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"VDI Credential", nil)
+                                                               message:NSLocalizedString(@"Please input username and password", nil)
+                                                        preferredStyle:UIAlertControllerStyleAlert];
+    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
+                                                           style:UIAlertActionStyleCancel
+                                                         handler:^(UIAlertAction * _Nonnull action) {
+                                                             VPNAccount *account = [[VPNAccount alloc] init];
+                                                             account.userName = nil;
+                                                             account.passWord = nil;
+                                                             
+                                                             [[AAAManager sharedInstance] continueVPNThreadWithVDIAccount:account];
+                                                         }];
+    UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
+                                                            style:UIAlertActionStyleDefault
+                                                          handler:^(UIAlertAction * _Nonnull action) {
+                                                              NSString *username = weakSelf.alertController.textFields[0].text;  // Username text field
+                                                              NSString *password = weakSelf.alertController.textFields[1].text;  // Password text field
+                                                              username = [username stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
+                                                              VPNAccount *account = [[VPNAccount alloc] init];
+                                                              account.userName = username;
+                                                              account.passWord = password;
+                                                              
+                                                              [[AAAManager sharedInstance] continueVPNThreadWithVDIAccount:account];
+                                                          }];
+    
+    [self.alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = NSLocalizedString(@"Username", nil);
+    }];
+    [self.alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = NSLocalizedString(@"Password", nil);
+    }];
+    [self.alertController addAction:confirmAction];
+    [self.alertController addAction:cancelAction];
+    
+    [self presentViewController:self.alertController animated:YES completion:nil];
+}
+
+- (void)finishLogin:(BOOL)success {
+    self.alertController = nil;
+    
+    __weak typeof(self) weakSelf = self;
+    [self dismissViewControllerAnimated:YES completion:^{
+        [weakSelf.delegate didFinishLogin:success];
+    }];
+}
+
+#pragma mark - Passwords
+- (void)savePasswordsOfAccount:(VPNAccount *)account {
+    Gateway *gateway = [self currentGateway];
+    if (![account.userName isEqualToString:gateway.username]){
+        
+        gateway.username = account.userName;
+        [[[GatewayManager alloc] init] updateGateway:gateway];
+    }
+    
+    if (account.userName){
+        
+        [self saveMethodName];
+        [self savePassWord:account];
+        return;
+    }
+    
+    if (gateway.username) {  // Only remember password when username is configured.
+        
+        [self savePassWord:account];
+    } else {
+        ANDebug(@"Password will be deleted, because the login user is different from the one in settings.");
+        
+        [self deleteMethodName];
+        [account deleteAllPasswords];
+    }
+}
+
+-(void) savePassWord: (VPNAccount *) account
+{
+    NSMutableArray *passwords = [[NSMutableArray alloc] init];
+    if (account.passWord) {
+        [passwords addObject:[account.passWord copy]];
+    }
+    
+    Gateway *gateway = [self currentGateway];
+
+    if (![self isRadiusSavePass:account.loginMethod]){
+        
+        gateway.isRadiusPWD = NO;
+        if (account.passWord2) {
+            [passwords addObject:[account.passWord2 copy]];
+        }
+        if (account.passWord3) {
+            [passwords addObject:[account.passWord3 copy]];
+        }
+    }else{
+        
+        gateway.isRadiusPWD = YES;
+    }
+    
+    [PasswordManager savePasswords:passwords forHost:account.vsHost username:account.userName port:account.vsPort];
+}
+
+-(BOOL) isRadiusSavePass: (NSString *) methodName
+{
+    if (self.allMethodDescs.count < 1 || ISNULLSTR(methodName)){
+        
+        return NO;
+    }
+    
+    NSInteger acount = [self.allMethodNames indexOfObject:methodName];
+    
+    if (acount < 0){
+        
+        return NO;
+    }
+    
+    NSString *methodDesc = [_allMethodDescs objectAtIndex:acount];
+    if ([methodDesc rangeOfString:RADIUS_SAVE_PWD].location != NSNotFound){
+        
+        ANInfo(@"LoginView-isRadiusSavePass- did not save pwd");
+        return YES;
+    }
+    
+    return NO;
+}
+
+-(void) saveMethodName
+{
+    NSString *methodName = self.currentMethod ?: (_methodMenu.titleLabel.text ?: @"");
+    NSString *userName = _usernameTextField.text ?: @"";
+    if ([methodName isEqualToString:@""]){
+        
+        methodName = @"ldb";
+    }
+    
+    NSString *methodType = [Singleton sharedSingleton].isSupportAuth ? @"0" : @"1";
+    NSDictionary *verifyDic = @{@"methodName" : methodName, @"userName" : userName, @"methodType" : methodType};
+    [Singleton setCurrentGatewayMethod:verifyDic andKey:self.gateWay];
+}
+
+-(void) getCurrentMethod
+{
+    auth_type_t type = self.currentMethodType;
+    if (type == AUTH_LOCALDB || type == AUTH_LDAP || type == AUTH_RADIUS || type == AUTH_RADIUS_ACCOUNT ||
+        type == AUTH_DEVID || type == AUTH_HTTP || type == AUTH_CERTIFICATE){
+        
+        [Singleton sharedSingleton].isSupportAuth = YES;
+    }else{
+        
+        [Singleton sharedSingleton].isSupportAuth = NO;
+    }
+    
+    if (type == AUTH_CERTIFICATE){
+        
+        _usernameTextField.text = @"";
+    }
+}
+
+-(void) deleteMethodName
+{
+    [Singleton setCurrentGatewayMethod:@{} andKey:self.gateWay];
+}
+
+- (void)removePasswordsOfAccount:(VPNAccount *)account {
+    [PasswordManager removePasswordsOfHost:account.vsHost username:account.userName port:account.vsPort];
+}
+
+#pragma mark - UITextFieldDelegate
+- (BOOL)textFieldShouldReturn:(UITextField *)textField {
+    if (textField == self.usernameTextField) {
+        [self.usernameTextField resignFirstResponder];
+        if (_currentTableCells.count > 1) {
+            [self.password1TextField becomeFirstResponder];
+        }
+    }
+    
+    return YES;
+}
+
+#pragma mark - ANViewControllerSwitchProtocol
+- (void)switchFromSender:(id)sender withOption:(NSDictionary *)option {
+    if (sender) {
+        self.delegate = sender;
+    }
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LoginViewController.m.InfosecEnterprise
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LoginViewController.m.InfosecEnterprise	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LoginViewController.m.InfosecEnterprise	(working copy)
@@ -0,0 +1,1346 @@
+//
+//  LoginViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/19.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "ANLogger.h"
+#import "AAAManager.h"
+#import "GatewayManager.h"
+#import "ArrayVPNWrapper.h"
+#import "PasswordManager.h"
+#import "InformationToSave.h"
+#import "DropMenuView.h"
+#import "ANPopupDialog.h"
+#import "FilterTypeModel.h"
+#import "UIDevice+Hardware.h"
+#import "SMSViewController.h"
+#import "SyferLockLoginViewController.h"
+#import "UIViewController+Activity.h"
+#import "UIViewController+HideKeyboard.h"
+#import "LoginViewController.h"
+#import "GatewayModel.h"
+#import "Singleton.h"
+
+static NSString * const methodCellID = @"LoginMethodCell";
+static NSString * const usernameCellID = @"LoginUsernameCell";
+static NSString * const passwordCellID = @"LoginPasswordCell";
+
+static NSString * const kSegueToChangePassword = @"LoginToChangePassword";
+static NSString * const kSegueToRegister = @"LoginToRegister";
+static NSString * const kSegueToChallenge = @"LoginToChallenge";
+static NSString * const kSegueToSMS = @"LoginToSMS";
+static NSString * const kSegueToSMX = @"LoginToSMX";
+static NSString * const kSegueToSMXChangePassword = @"LoginToSMXChangePassword";
+static NSString * const kSegueToSMXConfirmPassword = @"LoginToSMXConfirmPassword";
+static NSString * const kSegueToSyferLock = @"LoginToSyferLock";
+
+#if TARGET_OS_IPHONE
+NSString * const kAppGroupNameLogin = @"group.net.infosec.groupenterprise";
+#elif TARGET_OS_MAC
+NSString * const kAppGroupNameLogin = @"5VZLZ3YQ9P.net.arraynetworks.MacTunnel";
+#endif
+
+#define VIEW_CONTROLLER_ID_SMX_LOGIN            @"SMXLoginViewControllerID"
+#define VIEW_CONTROLLER_ID_SMX_NEWPASS          @"SMXNewPasswordViewControllerID"
+#define VIEW_CONTROLLER_ID_SMX_CONFIRM          @"SMXConfirmPasswordViewControllerID"
+
+#define TABLEVIEW_HEADER_HEIGHT         15
+#define TABLEVIEW_FOOTER_HEIGHT         CGFLOAT_MIN
+#define TABLEVIEW_CELL_HEIGHT           60
+#define TABLEVIEW_CELL_PADDING          10
+
+#define LABEL_TAG_ON_METHOD_CELL        1
+#define IMAGE_VIEW_TAG_ON_METHOD_CELL   2
+#define TEXTFIELD_TAG_ON_USERNAME_CELL  1
+#define TEXTFIELD_TAG_ON_PASSWORD_CELL  1
+
+#define DUMMY_PASSWD                    @"##&&**"
+#define OAUTH_SESSION_URL               @"/prx/000/http/localh/"
+#define RADIUS_SAVE_PWD                 @"radius_save_pwd"
+
+typedef enum {
+    kLoginCellMethodIndex = 0,
+    kLoginCellUsernameIndex,
+    kLoginCellPasswordIndex,
+    kLoginCellPassword2Index,
+    kLoginCellPassword3Index
+} LoginCellIndex;
+
+#define LOGIN_TABLE_SECTIONS    1
+
+@interface LoginViewController () <DropMenuDelegate, DropMenuDataSource, UITableViewDelegate, UITextFieldDelegate> {
+    DropMenuView    *_methodMenu;
+    
+    BOOL            _isMultiMethods;
+    BOOL            _isOAuthMethods;
+
+    NSArray         *_allMethodNames;
+    NSArray         *_allMethodDescs;
+    NSArray         *_currentTableCells;
+    
+    NSArray         *_realPasswords;
+    
+    VPNAccount      *_account;
+    BOOL            _isSMX;
+    BOOL            _isSyferLock;
+}
+
+@property (nonatomic, readonly) NSString    *currentMethod;
+@property (nonatomic)           NSUInteger  currentMethodIndex;
+@property (nonatomic, readonly) NSArray     *currentTableCells;
+@property (nonatomic, readonly) NSArray     *allMethodNames;
+@property (nonatomic, readonly) NSArray     *allMethodDescs;
+@property (nonatomic, strong)   NSArray     *methodActions;
+@property (nonatomic, strong)   NSArray     *methodRequests;
+@property (nonatomic, strong)   AAAManager  *model;
+@property (nonatomic, strong)   UITextField *usernameTextField;
+@property (nonatomic, strong)   UITextField *password1TextField;
+@property (nonatomic, strong)   UITextField *password2TextField;
+@property (nonatomic, strong)   UITextField *password3TextField;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *tableViewHeightConstraint;
+
+@property (weak, nonatomic) IBOutlet UITableView *tableView;
+@property (weak, nonatomic) IBOutlet UIButton *loginButton;
+
+@property (strong, nonatomic) UIAlertController *alertController;
+@property (weak, nonatomic) IBOutlet UILabel *methodNameLable;
+@property (nonatomic, strong) Gateway *gateWay;
+@property (assign, nonatomic) auth_type_t currentMethodType;
+
+@end
+
+@implementation LoginViewController
+
+- (void)dealloc {
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+    
+    self.model = nil;
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    
+    self.model = [AAAManager sharedInstance];
+    self.gateWay = [[[GatewayModel alloc] init] currentGatewayUpInside];
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleVPNNotification:) name:kVPNMessageNotification object:nil];
+    
+    [self enableHideKeyboard];
+    [self setLoginButtonAppearance];
+    
+    [self getSavedPassword];
+    [self initMethodView];
+    [self tryToAutoLogin];
+    
+    //iOS15新特性
+    if (@available(iOS 15.0, *)) {
+        
+        self.tableView.sectionHeaderTopPadding = 0;
+    }
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (IBAction)loginButtonClicked:(id)sender {
+    NSArray *allDescs = self.allMethodDescs;
+    if (allDescs && allDescs.count > 0) {
+        NSString *methodDesc = [allDescs objectAtIndex:_currentMethodIndex];
+        NSArray *parsedMethodDesc = [self parseMethodDesc:methodDesc];
+        if (parsedMethodDesc.count > 1) {
+            NSString *methodInfo;
+            for (int i = 0; i < parsedMethodDesc.count; i++) {
+                if ([[parsedMethodDesc objectAtIndex:i] containsString:KEY_METHOD_OAUTH]) {
+                    methodInfo = [parsedMethodDesc objectAtIndex:i];
+                    break;
+                }
+            }
+            
+            self.methodActions = [self parseMethodAction:methodInfo];
+            self.methodRequests = [self parseMethodRequest:methodInfo];
+            ANInfo(@"Oauth method action=%@, request =%@", self.methodActions, self.methodRequests);
+            NSString *oAuthurlInfo;
+            
+            for (int i = 0; i < self.methodActions.count; i++) {
+                int iAction = [[self.methodActions objectAtIndex:i] intValue] - 1;
+                if (iAction < self.methodRequests.count) {
+                    oAuthurlInfo = [self.methodRequests objectAtIndex:iAction];
+                    ANInfo(@"Oauth url info=%@", oAuthurlInfo);
+                }
+                
+                if ([oAuthurlInfo length] <= 0) {
+                    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                                  message:NSLocalizedString(@"Login failed, get oAuth info failed.",nil)];
+                    [self presentViewController:dialog animated:YES completion:nil];
+                    return;
+                }
+                if ([oAuthurlInfo containsString:@"http://"] || [oAuthurlInfo containsString:@"https://"]) {
+                    OpenURL([NSURL URLWithString:oAuthurlInfo]);  // Install app.
+                    return;
+                }
+                if ([self saveOAuthCodeLoginInfo:oAuthurlInfo]) {
+                    ANInfo(@"launch customer app and save oauth code info.");
+                    break;
+                }
+            }
+            
+            [self showLoginActivity:NO];
+            [self finishLogin:NO];
+            
+            [[AAAManager sharedInstance] cancelLoginTapped];
+            
+            [self dismissViewControllerAnimated:YES completion:nil];
+            return;
+        }
+    }
+    
+    NSInteger passwordCount = _isMultiMethods ? _currentTableCells.count - 2 : _currentTableCells.count - 1; // Substract method & username fields.
+    if (passwordCount > 0) {
+        if (![self checkPasswordFieldWithPasswordCount:passwordCount]) {
+            return;
+        }
+    }
+    
+    [self login];
+}
+
+- (IBAction)exitButtonClicked:(id)sender {
+    [self showLoginActivity:NO];
+    [self finishLogin:NO];
+    
+    [[AAAManager sharedInstance] cancelLoginTapped];
+    
+    [self dismissViewControllerAnimated:YES completion:nil];
+}
+
+- (void)setLoginButtonAppearance {
+    self.loginButton.layer.cornerRadius = 2.5;
+    self.loginButton.layer.shadowOffset = CGSizeMake(5.0, 5.0);
+    self.loginButton.layer.shadowColor = MAIN_COLOR.CGColor;
+    self.loginButton.layer.shadowOpacity = 0.25;
+}
+
+- (void)initMethodView {
+    if ([self allAAAMethods].count == 0) {
+        __weak typeof(self) weakSelf = self;
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                      message:NSLocalizedString(@"Incorrect server configuration!",nil)
+                                                                       action:^{
+                                                                           [weakSelf cancelLogin];
+                                                                       }];
+        [self presentViewController:dialog animated:YES completion:nil];
+    } else if ([self allAAAMethods].count > 1) {
+        _isMultiMethods = YES;
+    }else if ([self allAAAMethods].count > 0 && self.model.isOAuthType){ //认证方式
+        
+        _isMultiMethods = YES;
+    }
+    
+    _currentMethodIndex = 0;
+    _currentTableCells = [self cellsForMethodIndex:_currentMethodIndex];
+    if (_currentTableCells.count == 0) {
+        // Only deviceID auth, auto login.
+        __weak typeof(self) weakSelf = self;
+        dispatch_async(dispatch_get_main_queue(), ^{
+            [weakSelf login];
+        });
+    }
+}
+
+- (NSArray *)allAAAMethods {
+    return [self.model allAAAMehtods];
+}
+
+#pragma mark - Properties
+
+- (NSString *)currentMethod {
+    NSArray *allNames = self.allMethodNames;
+    if (!allNames || allNames.count == 0) {
+        return nil;
+    } else {
+        return [allNames objectAtIndex:_currentMethodIndex];
+    }
+}
+
+-(auth_type_t) currentMethodType{
+    
+    NSArray *typeArray = [self allAAAMethods];
+    
+    if (!typeArray || typeArray.count == 0) {
+        return -1;
+    } else {
+        
+        AAAMethod *method = [typeArray objectAtIndex:_currentMethodIndex];
+        if (method != nil){
+            
+            return method.authType;
+        }
+    }
+    return -1;
+}
+
+- (void)setCurrentMethodIndex:(NSUInteger)currentMethodIndex {
+    if (_currentMethodIndex == currentMethodIndex) {
+        return;
+    }
+    
+    _currentMethodIndex = currentMethodIndex;
+    _currentTableCells = [self cellsForMethodIndex:_currentMethodIndex];
+}
+
+- (NSArray*)allMethodNames {
+    if (_allMethodNames != nil) {
+        return _allMethodNames;
+    }
+    
+    NSMutableArray *names = [[NSMutableArray alloc] init];
+    
+    for (AAAMethod *method in [self allAAAMethods]) {
+        [names addObject:method.name];
+    }
+    
+    _allMethodNames = names;
+    
+    return _allMethodNames;
+}
+
+- (NSArray*)allMethodDescs {
+    if (_allMethodDescs != nil) {
+        return _allMethodDescs;
+    }
+    
+    NSMutableArray *descs = [[NSMutableArray alloc] init];
+    
+    for (AAAMethod *method in [self allAAAMethods]) {
+        [descs addObject:method.methodDescription];
+    }
+    
+    _allMethodDescs = descs;
+    
+    return _allMethodDescs;
+}
+
+#pragma mark - Parse Method
+
+- (NSArray *)parseMethodDesc:(NSString *)methodDesc {
+    NSMutableArray *methodParsed = [[NSMutableArray alloc] init];
+    
+    if ([methodDesc containsString:KEY_METHOD_OAUTH] && [methodDesc containsString:KEY_METHOD_MOBILE_ENABLE]) {
+        NSCharacterSet *delimiters = [NSCharacterSet characterSetWithCharactersInString:@"()"];
+        return [methodDesc componentsSeparatedByCharactersInSet:delimiters];
+    } else {
+        [methodParsed addObject:methodDesc];
+    }
+    
+    return methodParsed;
+}
+
+- (NSArray *)parseMethodAction:(NSString *)methodInfo {
+    NSString *methodAction;
+    NSMutableArray *actionArray = [[NSMutableArray alloc] init];
+    
+    if (methodInfo && [methodInfo containsString:KEY_METHOD_MOBILE_ENABLE]) {
+        NSArray *methodInfoArray = [methodInfo componentsSeparatedByString:@"@"];
+        for (int i = 0; i < methodInfoArray.count; i++) {
+            methodInfo = [methodInfoArray objectAtIndex:i];
+            if ([methodInfo containsString:KEY_METHOD_ACTION]) {
+                NSRange range = [methodInfo rangeOfString:KEY_METHOD_ACTION];
+                methodInfo = [methodInfo substringFromIndex:range.location + range.length];
+                NSArray *methodActionArray = [methodInfo componentsSeparatedByString:@"&"];
+                for(int j = 0; j < methodActionArray.count; j++) {
+                    methodInfo = [methodActionArray objectAtIndex:j];
+                    if ([methodInfo containsString:KEY_METHOD_MOBILE]) {
+                        range = [methodInfo rangeOfString:KEY_METHOD_MOBILE];
+                        methodAction = [methodInfo substringFromIndex:range.location + range.length];
+                        
+                        break;
+                    }
+                }
+            }
+        }
+        
+        if (methodAction.length > 0) {
+            for (int i = 0; i < methodAction.length; i ++) {
+                NSString *temp = [methodAction substringWithRange:NSMakeRange(i, 1)];
+                [actionArray addObject:temp];
+            }
+        }
+    }
+    
+    return actionArray;
+}
+
+- (NSArray *)parseMethodRequest:(NSString *)methodInfo {
+    NSMutableArray *methodRequestArray = [[NSMutableArray alloc] init];
+    NSString *methodBuf;
+    NSArray *methodReqArrayBuf;
+    
+    if (methodInfo && [methodInfo containsString:KEY_METHOD_MOBILE_ENABLE]) {
+        NSArray *methodInfoArray = [methodInfo componentsSeparatedByString:@"@"];
+        for (int i = 0; i < methodInfoArray.count; i++) {
+            methodBuf = [methodInfoArray objectAtIndex:i];
+            if ([methodBuf containsString:@"request"]) {
+                methodReqArrayBuf = [methodBuf componentsSeparatedByString:@"&"];
+                break;
+            }
+        }
+        
+        for (int i = 0; i < methodReqArrayBuf.count; i ++) {
+            NSString *req = [methodReqArrayBuf objectAtIndex:i];
+            req = [req substringFromIndex:9];
+            [methodRequestArray addObject:req];
+        }
+    }
+    
+    return methodRequestArray;
+}
+
+- (BOOL)saveOAuthCodeLoginInfo:(NSString *)oauthInfo {
+    if (![oauthInfo containsString:KEY_METHOD_RELIAO]) {
+        return NO;
+    }
+    
+    NSString *reliaoURL = @"reliao://f/vpn?action=login&callback=motionproplus%3a%2f%2fsetcode%3fcode%3d";
+    NSURL *url = [NSURL URLWithString:reliaoURL];
+    
+    if (!OpenURL(url)) {
+        return NO;
+    }
+    
+    oauthInfo = [oauthInfo substringToIndex:[oauthInfo rangeOfString:KEY_METHOD_RELIAO].location];
+    Gateway *gateway = [self currentGateway];
+    NSString *urlString = nil;
+    if ([gateway.port isEqualToString:@"443"]) {
+        urlString = [NSString stringWithFormat:@"https://%@%@%@", gateway.host, OAUTH_SESSION_URL, oauthInfo];
+    } else {
+        urlString = [NSString stringWithFormat:@"https://%@:%@%@%@", gateway.host, gateway.port, OAUTH_SESSION_URL, oauthInfo];
+    }
+    ANInfo(@"continue login url=%@", urlString);
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameLogin];
+    [userDefaults setValue:urlString forKey:KEY_OAUTH_URL];
+    
+    return YES;
+}
+
+#pragma mark - Login Related
+- (void)login {
+    ANInfo(@"------------>Start login...<------------");
+    
+    [self.view endEditing:YES];
+    
+    [self getCurrentMethod];
+    
+    VPNAccount *account = [self inputResult];
+    NSLog(@"vpn account on login: %@",account);
+    
+    if (account == nil) {
+        ANWarn(@"Cannot get account information");
+        return;
+    }
+    
+    InformationToSave *info = [InformationToSave sharedInstance];
+    
+    info.lastLoginAccount = account;
+    [info save];
+    
+    self.model.errorCode = 0; // Success
+    [self.model continueVPNThreadWithAccount:account];
+    
+    [self showLoginActivity:YES];
+}
+
+- (void)cancelLogin {
+    [self showLoginActivity:NO];
+    
+    [self.model cancelLoginTapped];
+}
+
+- (VPNAccount *)inputResult {
+    VPNAccount * account = self.model.account;
+    
+    account.loginMethod = self.currentMethod;
+    account.userName = self.usernameTextField.text;
+    
+    //Get account passwords
+    if ([self.password1TextField.text isEqualToString:DUMMY_PASSWD]) {
+        account.passWord = _realPasswords[0];
+    } else {
+        account.passWord = self.password1TextField.text;
+    }
+    
+    if ([self.password2TextField.text isEqualToString:DUMMY_PASSWD]) {
+        account.passWord2 = _realPasswords[1];
+    } else {
+        account.passWord2 = self.password2TextField.text;
+    }
+    
+    if ([self.password3TextField.text isEqualToString:DUMMY_PASSWD]) {
+        account.passWord3 = _realPasswords[2];
+    } else {
+        account.passWord3 = self.password3TextField.text;
+    }
+    
+    UIDevice *devInfo = [UIDevice currentDevice];
+    account.deviceName =[NSString stringWithFormat:@"%@|Apple;%@;iOS %@", devInfo.name, devInfo.platformString, devInfo.systemVersion];
+    
+    return account;
+}
+
+//Get all cells for the given method
+- (NSArray *)cellsForMethodIndex:(NSUInteger)index {
+    NSArray *methods = [self allAAAMethods];
+    if (methods == nil || methods.count == 0) {
+        ANError(@"No method found for login.");
+        return nil;
+    }
+    
+    AAAMethod *method = [methods objectAtIndex:index];
+    if (method == nil) {
+        return nil;
+    }
+    
+    NSMutableArray *cells = [[NSMutableArray alloc] init];
+    
+    for (InputField *field in method.inputFields) {
+        UITableViewCell *cell = [self cellForInputField:field];
+        if (cell == nil) {
+            ANError(@"Unknow inputField type %d", field.type);
+            continue;
+        }
+        
+        if (field.type == FieldTypeUsernameText) {
+            // Make sure Username is above password
+            [cells insertObject:cell atIndex:0];
+        } else {
+            [cells addObject:cell];
+        }
+    }
+    
+    NSString *infoDesc;
+    if (_isMultiMethods) {
+        //Display the method names
+        UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:methodCellID];
+        [self initMethodMenuWithCell:cell];
+        _methodMenu.titleLabel =  (UILabel *)[cell viewWithTag:1];
+        NSArray *pasedMethodDesc = [self parseMethodDesc:method.methodDescription];
+        if (pasedMethodDesc.count > 0) {
+            infoDesc = [pasedMethodDesc objectAtIndex:0];
+        } else {
+            infoDesc = method.methodDescription;
+        }
+        _methodMenu.titleLabel.text = infoDesc;
+        //Method cell shoud be at the top.
+        if (cell != nil) {
+            [cells insertObject:cell atIndex:0];
+        }
+    }
+    
+    return cells;
+}
+
+// Create a cell for the inputed field.
+- (UITableViewCell *)cellForInputField:(InputField *)field {
+    UITableViewCell *cell = nil;
+    
+    Gateway *gateway = [self currentGateway];
+    
+    NSString *username = self.model.account.userName;
+    if (!username || username.length == 0) {
+        username = gateway.username;
+    }
+    
+    NSString *passwd;
+    
+    switch (field.type) {
+        case FieldTypeUsernameText: {
+            //username field
+            cell = [self.tableView dequeueReusableCellWithIdentifier:usernameCellID];
+            self.usernameTextField = (UITextField *)[cell viewWithTag:TEXTFIELD_TAG_ON_USERNAME_CELL];
+            if (field.inputString) {
+                self.usernameTextField.text = field.inputString;
+            } else {
+                self.usernameTextField.text = username;
+            }
+            break;
+        }
+        case FieldTypePasswordText: {
+            switch (field.passwordIndex) {
+                case INDEX_PASSWORD1: {
+                    cell = [self.tableView dequeueReusableCellWithIdentifier:passwordCellID];
+                    self.password1TextField = (UITextField *) [cell viewWithTag:TEXTFIELD_TAG_ON_PASSWORD_CELL];
+                    self.password1TextField.placeholder = [NSString stringWithFormat:@"%@(%@)", NSLocalizedString(@"Password", nil), field.fieldDescription ?: @""];
+                    
+                    passwd = _realPasswords[0];
+                    if (passwd.length > 0) {
+                        self.password1TextField.text = DUMMY_PASSWD;
+                    }
+                    break;
+                }
+                case INDEX_PASSWORD2: {
+                    cell = [self.tableView dequeueReusableCellWithIdentifier:passwordCellID];
+                    self.password2TextField = (UITextField *) [cell viewWithTag:TEXTFIELD_TAG_ON_PASSWORD_CELL];
+                    self.password2TextField.placeholder = [NSString stringWithFormat:@"%@(%@)", NSLocalizedString(@"Password", nil), field.fieldDescription ?: @""];
+                    
+                    passwd = _realPasswords[1];
+                    if (passwd.length > 0) {
+                        self.password2TextField.text = DUMMY_PASSWD;
+                    }
+                    break;
+                }
+                case INDEX_PASSWORD3: {
+                    cell = [self.tableView dequeueReusableCellWithIdentifier:passwordCellID];
+                    self.password3TextField = (UITextField *) [cell viewWithTag:TEXTFIELD_TAG_ON_PASSWORD_CELL];
+                    self.password3TextField.placeholder = [NSString stringWithFormat:@"%@(%@)", NSLocalizedString(@"Password", nil), field.fieldDescription ?: @""];
+                    
+                    passwd = _realPasswords[0];
+                    if (passwd.length > 0) {
+                        self.password3TextField.text = DUMMY_PASSWD;
+                    }
+                    break;
+                }
+                default:
+                    break;
+            }
+            break;
+        }
+        default:
+            break;
+    }
+    
+    return cell;
+}
+
+- (Gateway *)currentGateway {
+    NSString *url = self.model.account.vsURL;
+    NSString *port = self.model.account.vsPort;
+    Gateway *gateway = [[GatewayManager sharedInstance] gatewayOfUrl:url andport:port];
+    
+    return gateway;
+}
+
+- (void)getSavedPassword {
+    Gateway *gateway = [self currentGateway];
+    NSString *username = gateway.username;
+    
+    _realPasswords = @[@"", @"", @""];
+    if (username != nil) {
+        if (!gateway.lastAccessedDate) {  // Prevent from getting saved password after reinstall.
+            [PasswordManager removePasswordsOfHost:gateway.host username:username port:gateway.port];
+        }
+        
+        if (gateway.isSavePasswordEnabled) {
+            _realPasswords = [PasswordManager passwordsOfHost:gateway.host username:username port:gateway.port];
+        } else {
+            ANDebug(@"delete user \"%@\" password", username?username:@"nil");
+            
+            if (!gateway.isFaceOrTouchIDEnabled && !gateway.isGestureEnabled){
+                
+                [self deleteMethodName];
+                [self.model.account deleteAllPasswords];
+            }
+        }
+    }
+}
+
+- (void)tryToAutoLogin {
+    Gateway *gateway = [self currentGateway];
+    BOOL showLoginDialog = gateway.isShowLoginDialogEnabled;
+    
+    if (gateway.isSavePasswordEnabled) {
+        if (!showLoginDialog && (_currentTableCells.count == 1 || ![_realPasswords isEqual:@[@"", @"", @""]])) {
+            dispatch_async(dispatch_get_main_queue(), ^{
+                [self login];
+            });
+        }
+    }
+}
+
+#pragma mark - Table view data source
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return LOGIN_TABLE_SECTIONS;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    NSInteger totalCells = _currentTableCells.count;
+    [self updateTableViewHeightWithCellsNumber:totalCells];
+    return _currentTableCells.count;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    return _currentTableCells[indexPath.row];
+}
+
+- (void)updateTableViewHeightWithCellsNumber:(NSInteger)cells {
+    self.tableViewHeightConstraint.constant = cells * TABLEVIEW_CELL_HEIGHT + TABLEVIEW_CELL_PADDING;
+}
+
+#pragma mark - SyferLock switch
+- (BOOL)isSyferLockEnabled {
+    Gateway *gateway = [self currentGateway];
+    if (!gateway) {
+        ANInfo(@"Current gateway is nil, no syferlock can be enabled.");
+        return NO;
+    } else {
+        return gateway.isSyferLockEnabled;
+    }
+}
+
+#pragma mark - UITableViewDelegate
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    
+    if (@available(iOS 15.0, *)){
+           
+        return 0.1;
+    }
+    
+    return TABLEVIEW_HEADER_HEIGHT;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return TABLEVIEW_FOOTER_HEIGHT;
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    [tableView deselectRowAtIndexPath:indexPath animated:YES];
+    
+    if (indexPath.section == 0 && indexPath.row == kLoginCellMethodIndex && _isMultiMethods) {  // Deal with method drop-down menu.
+        [_methodMenu showMenuOnView:self.view];
+    }
+}
+
+- (BOOL)checkPasswordFieldWithPasswordCount:(NSInteger)count {
+    enum PasswordCount {
+        kPasswordOne = 1,
+        kPasswordTwo = 2,
+        kPasswordThree = 3
+    };
+    
+    BOOL result = YES;
+    
+    switch (count) {
+        case kPasswordOne:
+            if ([self.password1TextField.text isEqualToString:@""]) {
+                result = NO;
+            }
+            break;
+        case kPasswordTwo:
+            if ([self.password1TextField.text isEqualToString:@""] ||
+                [self.password2TextField.text isEqualToString:@""]) {
+                result = NO;
+            }
+            break;
+        case kPasswordThree:
+            if ([self.password1TextField.text isEqualToString:@""] ||
+                [self.password2TextField.text isEqualToString:@""] ||
+                [self.password3TextField.text isEqualToString:@""]) {
+                result = NO;
+            }
+            break;
+        default:
+            break;
+    }
+    
+    if (!result) {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                      message:NSLocalizedString(@"Login failed, please check username and password",nil)];
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+    
+    return result;
+}
+
+- (void)initMethodMenuWithCell:(UITableViewCell *)cell {
+    if (!_methodMenu) {
+        _methodMenu = [[DropMenuView alloc] initWithOrigin:CGPointMake(0, cell.frame.size.height+TABLEVIEW_HEADER_HEIGHT)];
+        _methodMenu.delegate = self;
+        _methodMenu.dataSource = self;
+        _methodMenu.transformImageView = [cell viewWithTag:IMAGE_VIEW_TAG_ON_METHOD_CELL];
+        _methodMenu.titleLabel = nil;
+    }
+    
+    [_methodMenu reloadData];
+}
+
+#pragma mark menuDelegate
+
+- (NSMutableArray<FilterTypeModel *> *)menu_filterDataArray {
+    NSMutableArray *array = nil;
+    NSArray *descs = self.allMethodDescs;
+    NSString *methodDesc;
+    
+    NSInteger index = -1;
+    array = [NSMutableArray arrayWithCapacity:descs.count];
+    for (NSString *desc in descs) {
+        ++index;
+        methodDesc = desc;
+        NSArray *pasedMethodDesc = [self parseMethodDesc:desc];
+        if (pasedMethodDesc.count > 0) {
+            methodDesc = [pasedMethodDesc objectAtIndex:0];
+        }
+        
+        FilterTypeModel *model = [[FilterTypeModel alloc] initWithName:methodDesc andId:[NSString stringWithFormat:@"%zi", index]];
+        [array addObject:model];
+    }
+    
+    return array;
+}
+
+- (void)menu:(DropMenuView *)menu tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    self.currentMethodIndex = indexPath.row;
+    
+    [self.tableView reloadData];
+}
+
+//VPN notifications handler
+- (void)handleVPNNotification:(NSNotification *)notification {
+    VPNMessage *message = notification.object;
+    AAAManager *manager = [AAAManager sharedInstance];
+    NSInteger error = manager.errorCode;
+    NSString *aMessage;
+    BOOL showAlert = YES;
+    
+    switch (message.code) {
+        case VPN_CB_CONNECTED: {
+            if (!_isSMX) {
+                // Save passwords for non-SMX login.
+                [self savePasswordsOfAccount:manager.account];
+            }
+            [self finishLogin:YES];
+            break;
+        }
+        case VPN_CB_DISCONNECTING: {
+            [self finishLogin:NO];
+            break;
+        }
+        case VPN_CB_DEVID_REG: {
+            if (!_isSMX) {
+                // Save the current account
+                // In SMX, the account has been saved.
+                _account = [manager.account copy];
+            } else {
+                // SMX, clean the saved password, since it is useless after register.
+                manager.account.passWord = nil;
+            }
+            
+            [self performSegueWithIdentifier:kSegueToRegister sender:nil];
+            break;
+        }
+        case VPN_CB_CHALLENGE: {
+            [self performSegueWithIdentifier:kSegueToChallenge sender:nil];
+            break;
+        }
+        case VPN_CB_CONN_FAILED: {
+            switch (error) {
+                case ERR_DEVID_APPROVE_PENDING:
+                    aMessage = NSLocalizedString(@"Your device is registering, please request manager approval",nil);
+                    break;
+                case ERR_DEVID_APPROVE_DENY:
+                    aMessage = NSLocalizedString(@"Register device deny, not allow register device auto approve",nil);
+                    break;
+                case ERR_DEVID_USER_LIMIT:
+                    aMessage = NSLocalizedString(@"User for this device has reached his or her limit",nil);
+                    break;
+                case ERR_DEVID_DEV_LIMIT:
+                    aMessage = NSLocalizedString(@"Device has reached its limit",nil);
+                    break;
+                case ERR_WRONG_USER_PASS:
+                    if (!_isSyferLock) {  // DON'T remove saved password if SyferLock is enabled.
+                        [self deleteMethodName];
+                        [manager.account deleteAllPasswords];
+                    }
+                    aMessage = manager.errorInformation;
+                    //aMessage = NSLocalizedString(@"Login failed, please check username and password",nil);
+                    break;
+                case ERR_AUTHORIZE_FAILED:
+                    aMessage = NSLocalizedString(@"Login failed", nil);
+                    break;
+                case ERR_CALLBACK_FAILED:
+                    break;
+                case ERR_INTERRUPTED:
+                    break;
+                case ERR_CLIENT_SECURITY:
+                    aMessage = NSLocalizedString(@"Client security is not supported", nil);
+                    break;
+                case ERR_CERT_NO:
+                    aMessage = NSLocalizedString(@"Client certificate not supply", nil);
+                    break;
+                case ERR_CERT_INVALID_SIGNTURE:
+                    aMessage = NSLocalizedString(@"Client certificate invalid signture", nil);
+                    break;
+                case ERR_CERT_UNTRUSTED:
+                    aMessage = NSLocalizedString(@"Client certificate untrusted", nil);
+                    break;
+                case ERR_CERT_EXPIRED:
+                    aMessage = NSLocalizedString(@"Client certificate expired", nil);
+                    break;
+                case ERR_CERT_INVALID:
+                    aMessage = NSLocalizedString(@"Client certificate invalid", nil);
+                    break;
+                case ERR_CERT_REVOKED:
+                    aMessage = NSLocalizedString(@"Client certificate revoked", nil);
+                    break;
+                case ERR_SMS_GET_PHONE:
+                    aMessage = NSLocalizedString(@"The system failed to get your phone number to do OTP authentication", nil);
+                    break;
+                case ERR_SMS_SEND:
+                    aMessage = NSLocalizedString(@"The system failed to send message to your phone", nil);
+                    break;
+                case ERR_SMS_TOO_MANY_RETRY:
+                    aMessage = NSLocalizedString(@"Your attempt to sign in failed, because you have entered wrong SMS verification code for too many times", nil);
+                    break;
+                case ERR_HWID_DENY:
+                    aMessage = NSLocalizedString(@"The device is denied because of wrong hardware ID!", nil);
+                    break;
+                case ERR_HWID_PENDING:
+                    aMessage = NSLocalizedString(@"The hardware ID of this device is not approved yet!", nil);
+                    break;
+                default:
+                    ANError(@"Login failed with error message: %@", aMessage);
+                    break;
+            }
+            
+            // Try to show error message, only valid on viewcontroller still exists.
+            if (![self currentGateway].isShowLoginDialogEnabled) {
+                if (aMessage && aMessage.length > 0) {
+                    if (![aMessage containsString:@"<a href='"]) {
+                        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:aMessage];
+                        [self presentViewController:dialog animated:YES completion:nil];
+                    } else {
+                        ANInfo(@"Connect failed:Error message=%@", aMessage);
+                        NSRange subStrRange = [aMessage rangeOfString:@"<a href='"];
+                        NSMutableString *finalMessage = [NSMutableString stringWithString:aMessage];
+                        [finalMessage deleteCharactersInRange:NSMakeRange(subStrRange.location, (int)strlen("<a href='"))];
+                        NSString *displayMessage = [finalMessage substringToIndex:[finalMessage rangeOfString:@"'>"].location];
+                        ANInfo(@"Connect failed:Display message=%@", displayMessage);
+                        
+                        NSString *URLMessage = [aMessage substringFromIndex:(subStrRange.location + subStrRange.length)];
+                        URLMessage = [URLMessage substringToIndex:[URLMessage rangeOfString:@"'>"].location];
+                        ANInfo(@"URL message=%@", URLMessage);
+                        
+                        PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil) message:displayMessage confirmAction:^{
+                                                                    NSURL *url = [NSURL URLWithString:URLMessage];
+                                                                    OpenURL(url);
+                                                                    }
+                                                        cancelAction:nil];
+                        [self presentViewController:popup animated:YES completion:nil];
+                    }
+                }
+            }
+            
+            break;
+        }
+        case VPN_CB_LOGIN:
+        case VPN_CB_SYFERLOCK_AUTH: {
+            if (error == ERR_WRONG_USER_PASS || error == ERR_USER_LOCKED) {
+                __weak typeof(self) weakSelf = self;
+                if (![manager.errorInformation containsString:@"<a href='"]) {
+                    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                                  message:[self loginFailedMessage:error]
+                                                                                   action:^{
+                                                                                       [weakSelf showLoginActivity:NO];
+                                                                                       
+                                                                                       // If password is wrong, pop to root view.
+                                                                                       [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                                   }];
+                    [self presentViewController:dialog animated:YES completion:nil];
+                } else {
+                    ANInfo(@"Error message=%@", manager.errorInformation);
+                    NSRange subStrRange = [manager.errorInformation rangeOfString:@"<a href='"];
+                    NSMutableString *finalMessage = [NSMutableString stringWithString:manager.errorInformation];
+                    [finalMessage deleteCharactersInRange:NSMakeRange(subStrRange.location, (int)strlen("<a href='"))];
+                    NSString *displayMessage = [finalMessage substringToIndex:[finalMessage rangeOfString:@"'>"].location];
+                    ANInfo(@"Display message=%@", displayMessage);
+                    
+                    NSString *URLMessage = [manager.errorInformation substringFromIndex:(subStrRange.location + subStrRange.length)];
+                    URLMessage = [URLMessage substringToIndex:[URLMessage rangeOfString:@"'>"].location];
+                    ANInfo(@"URL message=%@", URLMessage);
+                    
+                    PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil) message:displayMessage confirmAction:^{
+                                                                NSURL *url = [NSURL URLWithString:URLMessage];
+                                                                OpenURL(url);
+                                                                [weakSelf showLoginActivity:NO];
+                        
+                                                                // If password is wrong, pop to root view.
+                                                                [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                }
+                                               cancelAction:^{
+                                                                [weakSelf showLoginActivity:NO];
+                                                                // If password is wrong, pop to root view.
+                                                                [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                }];
+                    [self presentViewController:popup animated:YES completion:nil];
+                }
+                
+                if (!_isSyferLock) {
+                    [self removePasswordsOfAccount:manager.account];
+                }
+                
+                ANError(@"Error message: %@", manager.errorInformation);
+            } else if (error == ERR_AUTHORIZE_FAILED) {
+                PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@""
+                                                                              message:NSLocalizedString(@"Authorize failed",nil)];
+                [self presentViewController:dialog animated:YES completion:nil];
+                
+                [self removePasswordsOfAccount:manager.account];
+            } else if (error == ERR_SUCCESS) {
+                //After register, we need to login again. Using the account we have saved.
+                if (!_account) {
+                    _account = [AAAManager sharedInstance].account;
+                }
+                [manager continueVPNThreadWithAccount:_account];
+                
+                break;
+            }
+            break;
+        }
+        case VPN_CB_SMX: {
+            _isSMX = YES;
+            
+            // Save password(s) for multi-step auth.
+            [self savePasswordsOfAccount:manager.account];
+            // Save current account, and use it to login after registering.
+            _account = [manager.account copy];
+            
+            // Clean passwords
+            _account.passWord = nil;
+            
+            ANDebug(@"message.code VPN_CB_SMX %zi", error);
+            
+            vpn_smx_info_t *smx_info = manager.smx_info;
+            if (smx_info != NULL) {
+                ANDebug(@"smx_info->action: %d", smx_info->action);
+                switch (smx_info->action) {
+                    case SMX_ACTION_INPUT_PASS:
+                    case SMX_ACTION_INPUT_OLD_PASS:
+                        if ([self.navigationController.topViewController.restorationIdentifier isEqualToString:VIEW_CONTROLLER_ID_SMX_LOGIN]) {
+                            //If the top controller is login controller, do nothing but send the status to it.
+                            [self refreshTopView];
+                            showAlert = YES;
+                        } else {
+                            [self performSegueWithIdentifier:kSegueToSMX sender:nil];
+                            showAlert = NO;
+                        }
+                        break;
+                    case SMX_ACTION_INPUT_NEW_PASS:
+                        if ([self.navigationController.topViewController.restorationIdentifier isEqualToString:VIEW_CONTROLLER_ID_SMX_NEWPASS]) {
+                            //If the top controller is new password controller, do nothing but send the status to it.
+                            [self refreshTopView];
+                            showAlert = YES;
+                            break;
+                        } else {
+                            [self performSegueWithIdentifier:kSegueToSMXChangePassword sender:nil];
+                            showAlert = NO;
+                        }
+                        break;
+                        
+                    case SMX_ACTION_PASS_CONFIRM:
+                        [self performSegueWithIdentifier:kSegueToSMXConfirmPassword sender:nil];
+                        showAlert = NO;
+                        break;
+                        
+                    default:
+                        break;
+                }
+                
+                if (showAlert && smx_info->errmsg[0] != '\0') {
+                    NSString *errorMessage = [NSString stringWithUTF8String:smx_info->errmsg];
+                    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@"" message:errorMessage];
+                    
+                    [self presentViewController:dialog animated:YES completion:nil];
+                }
+            }
+            break;
+        }
+        case VPN_CB_VDI_AUTH: {
+            [self handleVDIAuth];
+            break;
+        }
+        case VPN_CB_SMS: {
+            if ([self.navigationController.topViewController isKindOfClass:[SMSViewController class]]) {
+                [self refreshTopView];
+            } else {
+                [self performSegueWithIdentifier:kSegueToSMS sender:nil];
+            }
+            break;
+        }
+        case VPN_CB_CHANGPASSWORD: {
+            [self performSegueWithIdentifier:kSegueToChangePassword sender:nil];
+            break;
+        }
+        case VPN_CB_SYFERLOCK_LOGIN: {
+            _isSyferLock = YES;
+            if ([self.navigationController.topViewController isKindOfClass:[SyferLockLoginViewController class]]) {
+                [self refreshTopView];
+            } else {
+                [self performSegueWithIdentifier:kSegueToSyferLock sender:nil];
+            }
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+- (void)refreshTopView {
+    UIViewController *top = [self.navigationController topViewController];
+    SEL handler = NSSelectorFromString(@"refreshView");
+    if ([top respondsToSelector:handler]) {
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+        [top performSelector:handler];
+    }
+}
+
+// If last login method contains SMX.
+- (BOOL)isSMXAuth {
+    AAAManager *manager = [AAAManager sharedInstance];
+    
+    VPNAccount *account = _account;
+    if (!account) {
+        account = manager.account;
+    }
+    
+    NSString *currentMethod = account.loginMethod;
+    
+    NSArray *methods = [self allAAAMethods];
+    for (AAAMethod *method in methods) {
+        if ([method.name isEqualToString:currentMethod]) {
+            return method.isSmx;
+        }
+    }
+    
+    return NO;
+}
+
+- (NSString *)loginFailedMessage:(NSInteger)errorCode {
+    AAAManager *manager = [AAAManager sharedInstance];
+    
+    if ([self isSMXAuth]) {
+        // Get error message for SMX auth
+        NSString *errorMessage = manager.errorInformation;
+        if (errorMessage && errorMessage.length > 0) {
+            return errorMessage;
+        }
+        
+        vpn_smx_info_t *smx_info = manager.smx_info;
+        if (smx_info && strlen(smx_info->errmsg) != 0 && [self isValidSMXAction]) {
+            errorMessage = [NSString stringWithUTF8String:smx_info->errmsg];
+            if (errorMessage && ![errorMessage isEqualToString:@"OK"]) {
+                return errorMessage;
+            }
+        }
+    }
+    
+    if (errorCode == ERR_USER_LOCKED) {
+        NSString *errorMessage = manager.errorInformation;
+        if (errorMessage && errorMessage.length > 0) {
+            return errorMessage;
+        }
+    }
+    
+    NSString *errorMessage = manager.errorInformation;
+    if (errorMessage && errorMessage.length > 0) {
+        return errorMessage;
+    }
+    
+    // Return this string for all login error (incorrect username or password) except SMX auth.
+    return NSLocalizedString(@"Login failed, please check username and password", nil);
+}
+
+- (BOOL)isValidSMXAction {
+    vpn_smx_info_t *smx_info = [AAAManager sharedInstance].smx_info;
+    
+    return  (smx_info->action >= SMX_ACTION_UNKNOWN && smx_info->action <= SMX_ACTION_PASS_CONFIRM);
+}
+
+- (void)handleVDIAuth {
+    __weak typeof(self) weakSelf = self;
+    self.alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"VDI Credential", nil)
+                                                               message:NSLocalizedString(@"Please input username and password", nil)
+                                                        preferredStyle:UIAlertControllerStyleAlert];
+    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
+                                                           style:UIAlertActionStyleCancel
+                                                         handler:^(UIAlertAction * _Nonnull action) {
+                                                             VPNAccount *account = [[VPNAccount alloc] init];
+                                                             account.userName = nil;
+                                                             account.passWord = nil;
+                                                             
+                                                             [[AAAManager sharedInstance] continueVPNThreadWithVDIAccount:account];
+                                                         }];
+    UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
+                                                            style:UIAlertActionStyleDefault
+                                                          handler:^(UIAlertAction * _Nonnull action) {
+                                                              NSString *username = weakSelf.alertController.textFields[0].text;  // Username text field
+                                                              NSString *password = weakSelf.alertController.textFields[1].text;  // Password text field
+                                                              username = [username stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
+                                                              VPNAccount *account = [[VPNAccount alloc] init];
+                                                              account.userName = username;
+                                                              account.passWord = password;
+                                                              
+                                                              [[AAAManager sharedInstance] continueVPNThreadWithVDIAccount:account];
+                                                          }];
+    
+    [self.alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = NSLocalizedString(@"Username", nil);
+    }];
+    [self.alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = NSLocalizedString(@"Password", nil);
+    }];
+    [self.alertController addAction:confirmAction];
+    [self.alertController addAction:cancelAction];
+    
+    [self presentViewController:self.alertController animated:YES completion:nil];
+}
+
+- (void)finishLogin:(BOOL)success {
+    self.alertController = nil;
+    
+    __weak typeof(self) weakSelf = self;
+    [self dismissViewControllerAnimated:YES completion:^{
+        [weakSelf.delegate didFinishLogin:success];
+    }];
+}
+
+#pragma mark - Passwords
+- (void)savePasswordsOfAccount:(VPNAccount *)account {
+    Gateway *gateway = [self currentGateway];
+    if (![account.userName isEqualToString:gateway.username]){
+        
+        gateway.username = account.userName;
+        [[[GatewayManager alloc] init] updateGateway:gateway];
+    }
+    
+    if (account.userName){
+        
+        [self saveMethodName];
+        [self savePassWord:account];
+        return;
+    }
+    
+    if (gateway.username) {  // Only remember password when username is configured.
+        
+        [self savePassWord:account];
+    } else {
+        ANDebug(@"Password will be deleted, because the login user is different from the one in settings.");
+        
+        [self deleteMethodName];
+        [account deleteAllPasswords];
+    }
+}
+
+-(void) savePassWord: (VPNAccount *) account
+{
+    NSMutableArray *passwords = [[NSMutableArray alloc] init];
+    if (account.passWord) {
+        [passwords addObject:[account.passWord copy]];
+    }
+    
+    Gateway *gateway = [self currentGateway];
+
+    if (![self isRadiusSavePass:account.loginMethod]){
+        
+        gateway.isRadiusPWD = NO;
+        if (account.passWord2) {
+            [passwords addObject:[account.passWord2 copy]];
+        }
+        if (account.passWord3) {
+            [passwords addObject:[account.passWord3 copy]];
+        }
+    }else{
+        
+        gateway.isRadiusPWD = YES;
+    }
+    
+    [PasswordManager savePasswords:passwords forHost:account.vsHost username:account.userName port:account.vsPort];
+}
+
+-(BOOL) isRadiusSavePass: (NSString *) methodName
+{
+    if (self.allMethodDescs.count < 1){
+        
+        return NO;
+    }
+    
+    NSInteger acount = [self.allMethodNames indexOfObject:methodName];
+    
+    if (acount < 0){
+        
+        return NO;
+    }
+    
+    NSString *methodDesc = [_allMethodDescs objectAtIndex:acount];
+    if ([methodDesc rangeOfString:RADIUS_SAVE_PWD].location != NSNotFound){
+        
+        ANInfo(@"LoginView-isRadiusSavePass- did not save pwd");
+        return YES;
+    }
+    
+    return NO;
+}
+
+-(void) saveMethodName
+{
+    NSString *methodName = self.currentMethod ?: (_methodMenu.titleLabel.text ?: @"");
+    NSString *userName = _usernameTextField.text ?: @"";
+    if ([methodName isEqualToString:@""]){
+        
+        methodName = @"ldb";
+    }
+    
+    NSString *methodType = [Singleton sharedSingleton].isSupportAuth ? @"0" : @"1";
+    NSDictionary *verifyDic = @{@"methodName" : methodName, @"userName" : userName, @"methodType" : methodType};
+    [Singleton setCurrentGatewayMethod:verifyDic andKey:self.gateWay];
+}
+
+-(void) getCurrentMethod
+{
+    auth_type_t type = self.currentMethodType;
+    if (type == AUTH_LOCALDB || type == AUTH_LDAP || type == AUTH_RADIUS || type == AUTH_RADIUS_ACCOUNT ||
+        type == AUTH_DEVID || type == AUTH_HTTP || type == AUTH_CERTIFICATE){
+        
+        [Singleton sharedSingleton].isSupportAuth = YES;
+    }else{
+        
+        [Singleton sharedSingleton].isSupportAuth = NO;
+    }
+    
+    if (type == AUTH_CERTIFICATE){
+        
+        _usernameTextField.text = @"";
+    }
+}
+
+-(void) deleteMethodName
+{
+    [Singleton setCurrentGatewayMethod:@{} andKey:self.gateWay];
+}
+
+- (void)removePasswordsOfAccount:(VPNAccount *)account {
+    [PasswordManager removePasswordsOfHost:account.vsHost username:account.userName port:account.vsPort];
+}
+
+#pragma mark - UITextFieldDelegate
+- (BOOL)textFieldShouldReturn:(UITextField *)textField {
+    if (textField == self.usernameTextField) {
+        [self.usernameTextField resignFirstResponder];
+        if (_currentTableCells.count > 1) {
+            [self.password1TextField becomeFirstResponder];
+        }
+    }
+    
+    return YES;
+}
+
+#pragma mark - ANViewControllerSwitchProtocol
+- (void)switchFromSender:(id)sender withOption:(NSDictionary *)option {
+    if (sender) {
+        self.delegate = sender;
+    }
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LoginViewController.m.InfosecStore
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LoginViewController.m.InfosecStore	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LoginViewController.m.InfosecStore	(working copy)
@@ -0,0 +1,1346 @@
+//
+//  LoginViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/19.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "ANLogger.h"
+#import "AAAManager.h"
+#import "GatewayManager.h"
+#import "ArrayVPNWrapper.h"
+#import "PasswordManager.h"
+#import "InformationToSave.h"
+#import "DropMenuView.h"
+#import "ANPopupDialog.h"
+#import "FilterTypeModel.h"
+#import "UIDevice+Hardware.h"
+#import "SMSViewController.h"
+#import "SyferLockLoginViewController.h"
+#import "UIViewController+Activity.h"
+#import "UIViewController+HideKeyboard.h"
+#import "LoginViewController.h"
+#import "GatewayModel.h"
+#import "Singleton.h"
+
+static NSString * const methodCellID = @"LoginMethodCell";
+static NSString * const usernameCellID = @"LoginUsernameCell";
+static NSString * const passwordCellID = @"LoginPasswordCell";
+
+static NSString * const kSegueToChangePassword = @"LoginToChangePassword";
+static NSString * const kSegueToRegister = @"LoginToRegister";
+static NSString * const kSegueToChallenge = @"LoginToChallenge";
+static NSString * const kSegueToSMS = @"LoginToSMS";
+static NSString * const kSegueToSMX = @"LoginToSMX";
+static NSString * const kSegueToSMXChangePassword = @"LoginToSMXChangePassword";
+static NSString * const kSegueToSMXConfirmPassword = @"LoginToSMXConfirmPassword";
+static NSString * const kSegueToSyferLock = @"LoginToSyferLock";
+
+#if TARGET_OS_IPHONE
+NSString * const kAppGroupNameLogin = @"group.net.infosec.MotionPro";
+#elif TARGET_OS_MAC
+NSString * const kAppGroupNameLogin = @"5VZLZ3YQ9P.net.arraynetworks.MacTunnel";
+#endif
+
+#define VIEW_CONTROLLER_ID_SMX_LOGIN            @"SMXLoginViewControllerID"
+#define VIEW_CONTROLLER_ID_SMX_NEWPASS          @"SMXNewPasswordViewControllerID"
+#define VIEW_CONTROLLER_ID_SMX_CONFIRM          @"SMXConfirmPasswordViewControllerID"
+
+#define TABLEVIEW_HEADER_HEIGHT         15
+#define TABLEVIEW_FOOTER_HEIGHT         CGFLOAT_MIN
+#define TABLEVIEW_CELL_HEIGHT           60
+#define TABLEVIEW_CELL_PADDING          10
+
+#define LABEL_TAG_ON_METHOD_CELL        1
+#define IMAGE_VIEW_TAG_ON_METHOD_CELL   2
+#define TEXTFIELD_TAG_ON_USERNAME_CELL  1
+#define TEXTFIELD_TAG_ON_PASSWORD_CELL  1
+
+#define DUMMY_PASSWD                    @"##&&**"
+#define OAUTH_SESSION_URL               @"/prx/000/http/localh/"
+#define RADIUS_SAVE_PWD                 @"radius_save_pwd"
+
+typedef enum {
+    kLoginCellMethodIndex = 0,
+    kLoginCellUsernameIndex,
+    kLoginCellPasswordIndex,
+    kLoginCellPassword2Index,
+    kLoginCellPassword3Index
+} LoginCellIndex;
+
+#define LOGIN_TABLE_SECTIONS    1
+
+@interface LoginViewController () <DropMenuDelegate, DropMenuDataSource, UITableViewDelegate, UITextFieldDelegate> {
+    DropMenuView    *_methodMenu;
+    
+    BOOL            _isMultiMethods;
+    BOOL            _isOAuthMethods;
+
+    NSArray         *_allMethodNames;
+    NSArray         *_allMethodDescs;
+    NSArray         *_currentTableCells;
+    
+    NSArray         *_realPasswords;
+    
+    VPNAccount      *_account;
+    BOOL            _isSMX;
+    BOOL            _isSyferLock;
+}
+
+@property (nonatomic, readonly) NSString    *currentMethod;
+@property (nonatomic)           NSUInteger  currentMethodIndex;
+@property (nonatomic, readonly) NSArray     *currentTableCells;
+@property (nonatomic, readonly) NSArray     *allMethodNames;
+@property (nonatomic, readonly) NSArray     *allMethodDescs;
+@property (nonatomic, strong)   NSArray     *methodActions;
+@property (nonatomic, strong)   NSArray     *methodRequests;
+@property (nonatomic, strong)   AAAManager  *model;
+@property (nonatomic, strong)   UITextField *usernameTextField;
+@property (nonatomic, strong)   UITextField *password1TextField;
+@property (nonatomic, strong)   UITextField *password2TextField;
+@property (nonatomic, strong)   UITextField *password3TextField;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *tableViewHeightConstraint;
+
+@property (weak, nonatomic) IBOutlet UITableView *tableView;
+@property (weak, nonatomic) IBOutlet UIButton *loginButton;
+
+@property (strong, nonatomic) UIAlertController *alertController;
+@property (weak, nonatomic) IBOutlet UILabel *methodNameLable;
+@property (nonatomic, strong) Gateway *gateWay;
+@property (assign, nonatomic) auth_type_t currentMethodType;
+
+@end
+
+@implementation LoginViewController
+
+- (void)dealloc {
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+    
+    self.model = nil;
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    
+    self.model = [AAAManager sharedInstance];
+    self.gateWay = [[[GatewayModel alloc] init] currentGatewayUpInside];
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleVPNNotification:) name:kVPNMessageNotification object:nil];
+    
+    [self enableHideKeyboard];
+    [self setLoginButtonAppearance];
+    
+    [self getSavedPassword];
+    [self initMethodView];
+    [self tryToAutoLogin];
+    
+    //iOS15新特性
+    if (@available(iOS 15.0, *)) {
+        
+        self.tableView.sectionHeaderTopPadding = 0;
+    }
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (IBAction)loginButtonClicked:(id)sender {
+    NSArray *allDescs = self.allMethodDescs;
+    if (allDescs && allDescs.count > 0) {
+        NSString *methodDesc = [allDescs objectAtIndex:_currentMethodIndex];
+        NSArray *parsedMethodDesc = [self parseMethodDesc:methodDesc];
+        if (parsedMethodDesc.count > 1) {
+            NSString *methodInfo;
+            for (int i = 0; i < parsedMethodDesc.count; i++) {
+                if ([[parsedMethodDesc objectAtIndex:i] containsString:KEY_METHOD_OAUTH]) {
+                    methodInfo = [parsedMethodDesc objectAtIndex:i];
+                    break;
+                }
+            }
+            
+            self.methodActions = [self parseMethodAction:methodInfo];
+            self.methodRequests = [self parseMethodRequest:methodInfo];
+            ANInfo(@"Oauth method action=%@, request =%@", self.methodActions, self.methodRequests);
+            NSString *oAuthurlInfo;
+            
+            for (int i = 0; i < self.methodActions.count; i++) {
+                int iAction = [[self.methodActions objectAtIndex:i] intValue] - 1;
+                if (iAction < self.methodRequests.count) {
+                    oAuthurlInfo = [self.methodRequests objectAtIndex:iAction];
+                    ANInfo(@"Oauth url info=%@", oAuthurlInfo);
+                }
+                
+                if ([oAuthurlInfo length] <= 0) {
+                    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                                  message:NSLocalizedString(@"Login failed, get oAuth info failed.",nil)];
+                    [self presentViewController:dialog animated:YES completion:nil];
+                    return;
+                }
+                if ([oAuthurlInfo containsString:@"http://"] || [oAuthurlInfo containsString:@"https://"]) {
+                    OpenURL([NSURL URLWithString:oAuthurlInfo]);  // Install app.
+                    return;
+                }
+                if ([self saveOAuthCodeLoginInfo:oAuthurlInfo]) {
+                    ANInfo(@"launch customer app and save oauth code info.");
+                    break;
+                }
+            }
+            
+            [self showLoginActivity:NO];
+            [self finishLogin:NO];
+            
+            [[AAAManager sharedInstance] cancelLoginTapped];
+            
+            [self dismissViewControllerAnimated:YES completion:nil];
+            return;
+        }
+    }
+    
+    NSInteger passwordCount = _isMultiMethods ? _currentTableCells.count - 2 : _currentTableCells.count - 1; // Substract method & username fields.
+    if (passwordCount > 0) {
+        if (![self checkPasswordFieldWithPasswordCount:passwordCount]) {
+            return;
+        }
+    }
+    
+    [self login];
+}
+
+- (IBAction)exitButtonClicked:(id)sender {
+    [self showLoginActivity:NO];
+    [self finishLogin:NO];
+    
+    [[AAAManager sharedInstance] cancelLoginTapped];
+    
+    [self dismissViewControllerAnimated:YES completion:nil];
+}
+
+- (void)setLoginButtonAppearance {
+    self.loginButton.layer.cornerRadius = 2.5;
+    self.loginButton.layer.shadowOffset = CGSizeMake(5.0, 5.0);
+    self.loginButton.layer.shadowColor = MAIN_COLOR.CGColor;
+    self.loginButton.layer.shadowOpacity = 0.25;
+}
+
+- (void)initMethodView {
+    if ([self allAAAMethods].count == 0) {
+        __weak typeof(self) weakSelf = self;
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                      message:NSLocalizedString(@"Incorrect server configuration!",nil)
+                                                                       action:^{
+                                                                           [weakSelf cancelLogin];
+                                                                       }];
+        [self presentViewController:dialog animated:YES completion:nil];
+    } else if ([self allAAAMethods].count > 1) {
+        _isMultiMethods = YES;
+    }else if ([self allAAAMethods].count > 0 && self.model.isOAuthType){ //认证方式
+        
+        _isMultiMethods = YES;
+    }
+    
+    _currentMethodIndex = 0;
+    _currentTableCells = [self cellsForMethodIndex:_currentMethodIndex];
+    if (_currentTableCells.count == 0) {
+        // Only deviceID auth, auto login.
+        __weak typeof(self) weakSelf = self;
+        dispatch_async(dispatch_get_main_queue(), ^{
+            [weakSelf login];
+        });
+    }
+}
+
+- (NSArray *)allAAAMethods {
+    return [self.model allAAAMehtods];
+}
+
+#pragma mark - Properties
+
+- (NSString *)currentMethod {
+    NSArray *allNames = self.allMethodNames;
+    if (!allNames || allNames.count == 0) {
+        return nil;
+    } else {
+        return [allNames objectAtIndex:_currentMethodIndex];
+    }
+}
+
+-(auth_type_t) currentMethodType{
+    
+    NSArray *typeArray = [self allAAAMethods];
+    
+    if (!typeArray || typeArray.count == 0) {
+        return -1;
+    } else {
+        
+        AAAMethod *method = [typeArray objectAtIndex:_currentMethodIndex];
+        if (method != nil){
+            
+            return method.authType;
+        }
+    }
+    return -1;
+}
+
+- (void)setCurrentMethodIndex:(NSUInteger)currentMethodIndex {
+    if (_currentMethodIndex == currentMethodIndex) {
+        return;
+    }
+    
+    _currentMethodIndex = currentMethodIndex;
+    _currentTableCells = [self cellsForMethodIndex:_currentMethodIndex];
+}
+
+- (NSArray*)allMethodNames {
+    if (_allMethodNames != nil) {
+        return _allMethodNames;
+    }
+    
+    NSMutableArray *names = [[NSMutableArray alloc] init];
+    
+    for (AAAMethod *method in [self allAAAMethods]) {
+        [names addObject:method.name];
+    }
+    
+    _allMethodNames = names;
+    
+    return _allMethodNames;
+}
+
+- (NSArray*)allMethodDescs {
+    if (_allMethodDescs != nil) {
+        return _allMethodDescs;
+    }
+    
+    NSMutableArray *descs = [[NSMutableArray alloc] init];
+    
+    for (AAAMethod *method in [self allAAAMethods]) {
+        [descs addObject:method.methodDescription];
+    }
+    
+    _allMethodDescs = descs;
+    
+    return _allMethodDescs;
+}
+
+#pragma mark - Parse Method
+
+- (NSArray *)parseMethodDesc:(NSString *)methodDesc {
+    NSMutableArray *methodParsed = [[NSMutableArray alloc] init];
+    
+    if ([methodDesc containsString:KEY_METHOD_OAUTH] && [methodDesc containsString:KEY_METHOD_MOBILE_ENABLE]) {
+        NSCharacterSet *delimiters = [NSCharacterSet characterSetWithCharactersInString:@"()"];
+        return [methodDesc componentsSeparatedByCharactersInSet:delimiters];
+    } else {
+        [methodParsed addObject:methodDesc];
+    }
+    
+    return methodParsed;
+}
+
+- (NSArray *)parseMethodAction:(NSString *)methodInfo {
+    NSString *methodAction;
+    NSMutableArray *actionArray = [[NSMutableArray alloc] init];
+    
+    if (methodInfo && [methodInfo containsString:KEY_METHOD_MOBILE_ENABLE]) {
+        NSArray *methodInfoArray = [methodInfo componentsSeparatedByString:@"@"];
+        for (int i = 0; i < methodInfoArray.count; i++) {
+            methodInfo = [methodInfoArray objectAtIndex:i];
+            if ([methodInfo containsString:KEY_METHOD_ACTION]) {
+                NSRange range = [methodInfo rangeOfString:KEY_METHOD_ACTION];
+                methodInfo = [methodInfo substringFromIndex:range.location + range.length];
+                NSArray *methodActionArray = [methodInfo componentsSeparatedByString:@"&"];
+                for(int j = 0; j < methodActionArray.count; j++) {
+                    methodInfo = [methodActionArray objectAtIndex:j];
+                    if ([methodInfo containsString:KEY_METHOD_MOBILE]) {
+                        range = [methodInfo rangeOfString:KEY_METHOD_MOBILE];
+                        methodAction = [methodInfo substringFromIndex:range.location + range.length];
+                        
+                        break;
+                    }
+                }
+            }
+        }
+        
+        if (methodAction.length > 0) {
+            for (int i = 0; i < methodAction.length; i ++) {
+                NSString *temp = [methodAction substringWithRange:NSMakeRange(i, 1)];
+                [actionArray addObject:temp];
+            }
+        }
+    }
+    
+    return actionArray;
+}
+
+- (NSArray *)parseMethodRequest:(NSString *)methodInfo {
+    NSMutableArray *methodRequestArray = [[NSMutableArray alloc] init];
+    NSString *methodBuf;
+    NSArray *methodReqArrayBuf;
+    
+    if (methodInfo && [methodInfo containsString:KEY_METHOD_MOBILE_ENABLE]) {
+        NSArray *methodInfoArray = [methodInfo componentsSeparatedByString:@"@"];
+        for (int i = 0; i < methodInfoArray.count; i++) {
+            methodBuf = [methodInfoArray objectAtIndex:i];
+            if ([methodBuf containsString:@"request"]) {
+                methodReqArrayBuf = [methodBuf componentsSeparatedByString:@"&"];
+                break;
+            }
+        }
+        
+        for (int i = 0; i < methodReqArrayBuf.count; i ++) {
+            NSString *req = [methodReqArrayBuf objectAtIndex:i];
+            req = [req substringFromIndex:9];
+            [methodRequestArray addObject:req];
+        }
+    }
+    
+    return methodRequestArray;
+}
+
+- (BOOL)saveOAuthCodeLoginInfo:(NSString *)oauthInfo {
+    if (![oauthInfo containsString:KEY_METHOD_RELIAO]) {
+        return NO;
+    }
+    
+    NSString *reliaoURL = @"reliao://f/vpn?action=login&callback=motionproplus%3a%2f%2fsetcode%3fcode%3d";
+    NSURL *url = [NSURL URLWithString:reliaoURL];
+    
+    if (!OpenURL(url)) {
+        return NO;
+    }
+    
+    oauthInfo = [oauthInfo substringToIndex:[oauthInfo rangeOfString:KEY_METHOD_RELIAO].location];
+    Gateway *gateway = [self currentGateway];
+    NSString *urlString = nil;
+    if ([gateway.port isEqualToString:@"443"]) {
+        urlString = [NSString stringWithFormat:@"https://%@%@%@", gateway.host, OAUTH_SESSION_URL, oauthInfo];
+    } else {
+        urlString = [NSString stringWithFormat:@"https://%@:%@%@%@", gateway.host, gateway.port, OAUTH_SESSION_URL, oauthInfo];
+    }
+    ANInfo(@"continue login url=%@", urlString);
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameLogin];
+    [userDefaults setValue:urlString forKey:KEY_OAUTH_URL];
+    
+    return YES;
+}
+
+#pragma mark - Login Related
+- (void)login {
+    ANInfo(@"------------>Start login...<------------");
+    
+    [self.view endEditing:YES];
+    
+    [self getCurrentMethod];
+    
+    VPNAccount *account = [self inputResult];
+    NSLog(@"vpn account on login: %@",account);
+    
+    if (account == nil) {
+        ANWarn(@"Cannot get account information");
+        return;
+    }
+    
+    InformationToSave *info = [InformationToSave sharedInstance];
+    
+    info.lastLoginAccount = account;
+    [info save];
+    
+    self.model.errorCode = 0; // Success
+    [self.model continueVPNThreadWithAccount:account];
+    
+    [self showLoginActivity:YES];
+}
+
+- (void)cancelLogin {
+    [self showLoginActivity:NO];
+    
+    [self.model cancelLoginTapped];
+}
+
+- (VPNAccount *)inputResult {
+    VPNAccount * account = self.model.account;
+    
+    account.loginMethod = self.currentMethod;
+    account.userName = self.usernameTextField.text;
+    
+    //Get account passwords
+    if ([self.password1TextField.text isEqualToString:DUMMY_PASSWD]) {
+        account.passWord = _realPasswords[0];
+    } else {
+        account.passWord = self.password1TextField.text;
+    }
+    
+    if ([self.password2TextField.text isEqualToString:DUMMY_PASSWD]) {
+        account.passWord2 = _realPasswords[1];
+    } else {
+        account.passWord2 = self.password2TextField.text;
+    }
+    
+    if ([self.password3TextField.text isEqualToString:DUMMY_PASSWD]) {
+        account.passWord3 = _realPasswords[2];
+    } else {
+        account.passWord3 = self.password3TextField.text;
+    }
+    
+    UIDevice *devInfo = [UIDevice currentDevice];
+    account.deviceName =[NSString stringWithFormat:@"%@|Apple;%@;iOS %@", devInfo.name, devInfo.platformString, devInfo.systemVersion];
+    
+    return account;
+}
+
+//Get all cells for the given method
+- (NSArray *)cellsForMethodIndex:(NSUInteger)index {
+    NSArray *methods = [self allAAAMethods];
+    if (methods == nil || methods.count == 0) {
+        ANError(@"No method found for login.");
+        return nil;
+    }
+    
+    AAAMethod *method = [methods objectAtIndex:index];
+    if (method == nil) {
+        return nil;
+    }
+    
+    NSMutableArray *cells = [[NSMutableArray alloc] init];
+    
+    for (InputField *field in method.inputFields) {
+        UITableViewCell *cell = [self cellForInputField:field];
+        if (cell == nil) {
+            ANError(@"Unknow inputField type %d", field.type);
+            continue;
+        }
+        
+        if (field.type == FieldTypeUsernameText) {
+            // Make sure Username is above password
+            [cells insertObject:cell atIndex:0];
+        } else {
+            [cells addObject:cell];
+        }
+    }
+    
+    NSString *infoDesc;
+    if (_isMultiMethods) {
+        //Display the method names
+        UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:methodCellID];
+        [self initMethodMenuWithCell:cell];
+        _methodMenu.titleLabel =  (UILabel *)[cell viewWithTag:1];
+        NSArray *pasedMethodDesc = [self parseMethodDesc:method.methodDescription];
+        if (pasedMethodDesc.count > 0) {
+            infoDesc = [pasedMethodDesc objectAtIndex:0];
+        } else {
+            infoDesc = method.methodDescription;
+        }
+        _methodMenu.titleLabel.text = infoDesc;
+        //Method cell shoud be at the top.
+        if (cell != nil) {
+            [cells insertObject:cell atIndex:0];
+        }
+    }
+    
+    return cells;
+}
+
+// Create a cell for the inputed field.
+- (UITableViewCell *)cellForInputField:(InputField *)field {
+    UITableViewCell *cell = nil;
+    
+    Gateway *gateway = [self currentGateway];
+    
+    NSString *username = self.model.account.userName;
+    if (!username || username.length == 0) {
+        username = gateway.username;
+    }
+    
+    NSString *passwd;
+    
+    switch (field.type) {
+        case FieldTypeUsernameText: {
+            //username field
+            cell = [self.tableView dequeueReusableCellWithIdentifier:usernameCellID];
+            self.usernameTextField = (UITextField *)[cell viewWithTag:TEXTFIELD_TAG_ON_USERNAME_CELL];
+            if (field.inputString) {
+                self.usernameTextField.text = field.inputString;
+            } else {
+                self.usernameTextField.text = username;
+            }
+            break;
+        }
+        case FieldTypePasswordText: {
+            switch (field.passwordIndex) {
+                case INDEX_PASSWORD1: {
+                    cell = [self.tableView dequeueReusableCellWithIdentifier:passwordCellID];
+                    self.password1TextField = (UITextField *) [cell viewWithTag:TEXTFIELD_TAG_ON_PASSWORD_CELL];
+                    self.password1TextField.placeholder = [NSString stringWithFormat:@"%@(%@)", NSLocalizedString(@"Password", nil), field.fieldDescription ?: @""];
+                    
+                    passwd = _realPasswords[0];
+                    if (passwd.length > 0) {
+                        self.password1TextField.text = DUMMY_PASSWD;
+                    }
+                    break;
+                }
+                case INDEX_PASSWORD2: {
+                    cell = [self.tableView dequeueReusableCellWithIdentifier:passwordCellID];
+                    self.password2TextField = (UITextField *) [cell viewWithTag:TEXTFIELD_TAG_ON_PASSWORD_CELL];
+                    self.password2TextField.placeholder = [NSString stringWithFormat:@"%@(%@)", NSLocalizedString(@"Password", nil), field.fieldDescription ?: @""];
+                    
+                    passwd = _realPasswords[1];
+                    if (passwd.length > 0) {
+                        self.password2TextField.text = DUMMY_PASSWD;
+                    }
+                    break;
+                }
+                case INDEX_PASSWORD3: {
+                    cell = [self.tableView dequeueReusableCellWithIdentifier:passwordCellID];
+                    self.password3TextField = (UITextField *) [cell viewWithTag:TEXTFIELD_TAG_ON_PASSWORD_CELL];
+                    self.password3TextField.placeholder = [NSString stringWithFormat:@"%@(%@)", NSLocalizedString(@"Password", nil), field.fieldDescription ?: @""];
+                    
+                    passwd = _realPasswords[0];
+                    if (passwd.length > 0) {
+                        self.password3TextField.text = DUMMY_PASSWD;
+                    }
+                    break;
+                }
+                default:
+                    break;
+            }
+            break;
+        }
+        default:
+            break;
+    }
+    
+    return cell;
+}
+
+- (Gateway *)currentGateway {
+    NSString *url = self.model.account.vsURL;
+    NSString *port = self.model.account.vsPort;
+    Gateway *gateway = [[GatewayManager sharedInstance] gatewayOfUrl:url andport:port];
+    
+    return gateway;
+}
+
+- (void)getSavedPassword {
+    Gateway *gateway = [self currentGateway];
+    NSString *username = gateway.username;
+    
+    _realPasswords = @[@"", @"", @""];
+    if (username != nil) {
+        if (!gateway.lastAccessedDate) {  // Prevent from getting saved password after reinstall.
+            [PasswordManager removePasswordsOfHost:gateway.host username:username port:gateway.port];
+        }
+        
+        if (gateway.isSavePasswordEnabled) {
+            _realPasswords = [PasswordManager passwordsOfHost:gateway.host username:username port:gateway.port];
+        } else {
+            ANDebug(@"delete user \"%@\" password", username?username:@"nil");
+            
+            if (!gateway.isFaceOrTouchIDEnabled && !gateway.isGestureEnabled){
+                
+                [self deleteMethodName];
+                [self.model.account deleteAllPasswords];
+            }
+        }
+    }
+}
+
+- (void)tryToAutoLogin {
+    Gateway *gateway = [self currentGateway];
+    BOOL showLoginDialog = gateway.isShowLoginDialogEnabled;
+    
+    if (gateway.isSavePasswordEnabled) {
+        if (!showLoginDialog && (_currentTableCells.count == 1 || ![_realPasswords isEqual:@[@"", @"", @""]])) {
+            dispatch_async(dispatch_get_main_queue(), ^{
+                [self login];
+            });
+        }
+    }
+}
+
+#pragma mark - Table view data source
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return LOGIN_TABLE_SECTIONS;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    NSInteger totalCells = _currentTableCells.count;
+    [self updateTableViewHeightWithCellsNumber:totalCells];
+    return _currentTableCells.count;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    return _currentTableCells[indexPath.row];
+}
+
+- (void)updateTableViewHeightWithCellsNumber:(NSInteger)cells {
+    self.tableViewHeightConstraint.constant = cells * TABLEVIEW_CELL_HEIGHT + TABLEVIEW_CELL_PADDING;
+}
+
+#pragma mark - SyferLock switch
+- (BOOL)isSyferLockEnabled {
+    Gateway *gateway = [self currentGateway];
+    if (!gateway) {
+        ANInfo(@"Current gateway is nil, no syferlock can be enabled.");
+        return NO;
+    } else {
+        return gateway.isSyferLockEnabled;
+    }
+}
+
+#pragma mark - UITableViewDelegate
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    
+    if (@available(iOS 15.0, *)){
+           
+        return 0.1;
+    }
+    
+    return TABLEVIEW_HEADER_HEIGHT;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return TABLEVIEW_FOOTER_HEIGHT;
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    [tableView deselectRowAtIndexPath:indexPath animated:YES];
+    
+    if (indexPath.section == 0 && indexPath.row == kLoginCellMethodIndex && _isMultiMethods) {  // Deal with method drop-down menu.
+        [_methodMenu showMenuOnView:self.view];
+    }
+}
+
+- (BOOL)checkPasswordFieldWithPasswordCount:(NSInteger)count {
+    enum PasswordCount {
+        kPasswordOne = 1,
+        kPasswordTwo = 2,
+        kPasswordThree = 3
+    };
+    
+    BOOL result = YES;
+    
+    switch (count) {
+        case kPasswordOne:
+            if ([self.password1TextField.text isEqualToString:@""]) {
+                result = NO;
+            }
+            break;
+        case kPasswordTwo:
+            if ([self.password1TextField.text isEqualToString:@""] ||
+                [self.password2TextField.text isEqualToString:@""]) {
+                result = NO;
+            }
+            break;
+        case kPasswordThree:
+            if ([self.password1TextField.text isEqualToString:@""] ||
+                [self.password2TextField.text isEqualToString:@""] ||
+                [self.password3TextField.text isEqualToString:@""]) {
+                result = NO;
+            }
+            break;
+        default:
+            break;
+    }
+    
+    if (!result) {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                      message:NSLocalizedString(@"Login failed, please check username and password",nil)];
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+    
+    return result;
+}
+
+- (void)initMethodMenuWithCell:(UITableViewCell *)cell {
+    if (!_methodMenu) {
+        _methodMenu = [[DropMenuView alloc] initWithOrigin:CGPointMake(0, cell.frame.size.height+TABLEVIEW_HEADER_HEIGHT)];
+        _methodMenu.delegate = self;
+        _methodMenu.dataSource = self;
+        _methodMenu.transformImageView = [cell viewWithTag:IMAGE_VIEW_TAG_ON_METHOD_CELL];
+        _methodMenu.titleLabel = nil;
+    }
+    
+    [_methodMenu reloadData];
+}
+
+#pragma mark menuDelegate
+
+- (NSMutableArray<FilterTypeModel *> *)menu_filterDataArray {
+    NSMutableArray *array = nil;
+    NSArray *descs = self.allMethodDescs;
+    NSString *methodDesc;
+    
+    NSInteger index = -1;
+    array = [NSMutableArray arrayWithCapacity:descs.count];
+    for (NSString *desc in descs) {
+        ++index;
+        methodDesc = desc;
+        NSArray *pasedMethodDesc = [self parseMethodDesc:desc];
+        if (pasedMethodDesc.count > 0) {
+            methodDesc = [pasedMethodDesc objectAtIndex:0];
+        }
+        
+        FilterTypeModel *model = [[FilterTypeModel alloc] initWithName:methodDesc andId:[NSString stringWithFormat:@"%zi", index]];
+        [array addObject:model];
+    }
+    
+    return array;
+}
+
+- (void)menu:(DropMenuView *)menu tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    self.currentMethodIndex = indexPath.row;
+    
+    [self.tableView reloadData];
+}
+
+//VPN notifications handler
+- (void)handleVPNNotification:(NSNotification *)notification {
+    VPNMessage *message = notification.object;
+    AAAManager *manager = [AAAManager sharedInstance];
+    NSInteger error = manager.errorCode;
+    NSString *aMessage;
+    BOOL showAlert = YES;
+    
+    switch (message.code) {
+        case VPN_CB_CONNECTED: {
+            if (!_isSMX) {
+                // Save passwords for non-SMX login.
+                [self savePasswordsOfAccount:manager.account];
+            }
+            [self finishLogin:YES];
+            break;
+        }
+        case VPN_CB_DISCONNECTING: {
+            [self finishLogin:NO];
+            break;
+        }
+        case VPN_CB_DEVID_REG: {
+            if (!_isSMX) {
+                // Save the current account
+                // In SMX, the account has been saved.
+                _account = [manager.account copy];
+            } else {
+                // SMX, clean the saved password, since it is useless after register.
+                manager.account.passWord = nil;
+            }
+            
+            [self performSegueWithIdentifier:kSegueToRegister sender:nil];
+            break;
+        }
+        case VPN_CB_CHALLENGE: {
+            [self performSegueWithIdentifier:kSegueToChallenge sender:nil];
+            break;
+        }
+        case VPN_CB_CONN_FAILED: {
+            switch (error) {
+                case ERR_DEVID_APPROVE_PENDING:
+                    aMessage = NSLocalizedString(@"Your device is registering, please request manager approval",nil);
+                    break;
+                case ERR_DEVID_APPROVE_DENY:
+                    aMessage = NSLocalizedString(@"Register device deny, not allow register device auto approve",nil);
+                    break;
+                case ERR_DEVID_USER_LIMIT:
+                    aMessage = NSLocalizedString(@"User for this device has reached his or her limit",nil);
+                    break;
+                case ERR_DEVID_DEV_LIMIT:
+                    aMessage = NSLocalizedString(@"Device has reached its limit",nil);
+                    break;
+                case ERR_WRONG_USER_PASS:
+                    if (!_isSyferLock) {  // DON'T remove saved password if SyferLock is enabled.
+                        [self deleteMethodName];
+                        [manager.account deleteAllPasswords];
+                    }
+                    aMessage = manager.errorInformation;
+                    //aMessage = NSLocalizedString(@"Login failed, please check username and password",nil);
+                    break;
+                case ERR_AUTHORIZE_FAILED:
+                    aMessage = NSLocalizedString(@"Login failed", nil);
+                    break;
+                case ERR_CALLBACK_FAILED:
+                    break;
+                case ERR_INTERRUPTED:
+                    break;
+                case ERR_CLIENT_SECURITY:
+                    aMessage = NSLocalizedString(@"Client security is not supported", nil);
+                    break;
+                case ERR_CERT_NO:
+                    aMessage = NSLocalizedString(@"Client certificate not supply", nil);
+                    break;
+                case ERR_CERT_INVALID_SIGNTURE:
+                    aMessage = NSLocalizedString(@"Client certificate invalid signture", nil);
+                    break;
+                case ERR_CERT_UNTRUSTED:
+                    aMessage = NSLocalizedString(@"Client certificate untrusted", nil);
+                    break;
+                case ERR_CERT_EXPIRED:
+                    aMessage = NSLocalizedString(@"Client certificate expired", nil);
+                    break;
+                case ERR_CERT_INVALID:
+                    aMessage = NSLocalizedString(@"Client certificate invalid", nil);
+                    break;
+                case ERR_CERT_REVOKED:
+                    aMessage = NSLocalizedString(@"Client certificate revoked", nil);
+                    break;
+                case ERR_SMS_GET_PHONE:
+                    aMessage = NSLocalizedString(@"The system failed to get your phone number to do OTP authentication", nil);
+                    break;
+                case ERR_SMS_SEND:
+                    aMessage = NSLocalizedString(@"The system failed to send message to your phone", nil);
+                    break;
+                case ERR_SMS_TOO_MANY_RETRY:
+                    aMessage = NSLocalizedString(@"Your attempt to sign in failed, because you have entered wrong SMS verification code for too many times", nil);
+                    break;
+                case ERR_HWID_DENY:
+                    aMessage = NSLocalizedString(@"The device is denied because of wrong hardware ID!", nil);
+                    break;
+                case ERR_HWID_PENDING:
+                    aMessage = NSLocalizedString(@"The hardware ID of this device is not approved yet!", nil);
+                    break;
+                default:
+                    ANError(@"Login failed with error message: %@", aMessage);
+                    break;
+            }
+            
+            // Try to show error message, only valid on viewcontroller still exists.
+            if (![self currentGateway].isShowLoginDialogEnabled) {
+                if (aMessage && aMessage.length > 0) {
+                    if (![aMessage containsString:@"<a href='"]) {
+                        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:aMessage];
+                        [self presentViewController:dialog animated:YES completion:nil];
+                    } else {
+                        ANInfo(@"Connect failed:Error message=%@", aMessage);
+                        NSRange subStrRange = [aMessage rangeOfString:@"<a href='"];
+                        NSMutableString *finalMessage = [NSMutableString stringWithString:aMessage];
+                        [finalMessage deleteCharactersInRange:NSMakeRange(subStrRange.location, (int)strlen("<a href='"))];
+                        NSString *displayMessage = [finalMessage substringToIndex:[finalMessage rangeOfString:@"'>"].location];
+                        ANInfo(@"Connect failed:Display message=%@", displayMessage);
+                        
+                        NSString *URLMessage = [aMessage substringFromIndex:(subStrRange.location + subStrRange.length)];
+                        URLMessage = [URLMessage substringToIndex:[URLMessage rangeOfString:@"'>"].location];
+                        ANInfo(@"URL message=%@", URLMessage);
+                        
+                        PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil) message:displayMessage confirmAction:^{
+                                                                    NSURL *url = [NSURL URLWithString:URLMessage];
+                                                                    OpenURL(url);
+                                                                    }
+                                                        cancelAction:nil];
+                        [self presentViewController:popup animated:YES completion:nil];
+                    }
+                }
+            }
+            
+            break;
+        }
+        case VPN_CB_LOGIN:
+        case VPN_CB_SYFERLOCK_AUTH: {
+            if (error == ERR_WRONG_USER_PASS || error == ERR_USER_LOCKED) {
+                __weak typeof(self) weakSelf = self;
+                if (![manager.errorInformation containsString:@"<a href='"]) {
+                    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                                  message:[self loginFailedMessage:error]
+                                                                                   action:^{
+                                                                                       [weakSelf showLoginActivity:NO];
+                                                                                       
+                                                                                       // If password is wrong, pop to root view.
+                                                                                       [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                                   }];
+                    [self presentViewController:dialog animated:YES completion:nil];
+                } else {
+                    ANInfo(@"Error message=%@", manager.errorInformation);
+                    NSRange subStrRange = [manager.errorInformation rangeOfString:@"<a href='"];
+                    NSMutableString *finalMessage = [NSMutableString stringWithString:manager.errorInformation];
+                    [finalMessage deleteCharactersInRange:NSMakeRange(subStrRange.location, (int)strlen("<a href='"))];
+                    NSString *displayMessage = [finalMessage substringToIndex:[finalMessage rangeOfString:@"'>"].location];
+                    ANInfo(@"Display message=%@", displayMessage);
+                    
+                    NSString *URLMessage = [manager.errorInformation substringFromIndex:(subStrRange.location + subStrRange.length)];
+                    URLMessage = [URLMessage substringToIndex:[URLMessage rangeOfString:@"'>"].location];
+                    ANInfo(@"URL message=%@", URLMessage);
+                    
+                    PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil) message:displayMessage confirmAction:^{
+                                                                NSURL *url = [NSURL URLWithString:URLMessage];
+                                                                OpenURL(url);
+                                                                [weakSelf showLoginActivity:NO];
+                        
+                                                                // If password is wrong, pop to root view.
+                                                                [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                }
+                                               cancelAction:^{
+                                                                [weakSelf showLoginActivity:NO];
+                                                                // If password is wrong, pop to root view.
+                                                                [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                }];
+                    [self presentViewController:popup animated:YES completion:nil];
+                }
+                
+                if (!_isSyferLock) {
+                    [self removePasswordsOfAccount:manager.account];
+                }
+                
+                ANError(@"Error message: %@", manager.errorInformation);
+            } else if (error == ERR_AUTHORIZE_FAILED) {
+                PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@""
+                                                                              message:NSLocalizedString(@"Authorize failed",nil)];
+                [self presentViewController:dialog animated:YES completion:nil];
+                
+                [self removePasswordsOfAccount:manager.account];
+            } else if (error == ERR_SUCCESS) {
+                //After register, we need to login again. Using the account we have saved.
+                if (!_account) {
+                    _account = [AAAManager sharedInstance].account;
+                }
+                [manager continueVPNThreadWithAccount:_account];
+                
+                break;
+            }
+            break;
+        }
+        case VPN_CB_SMX: {
+            _isSMX = YES;
+            
+            // Save password(s) for multi-step auth.
+            [self savePasswordsOfAccount:manager.account];
+            // Save current account, and use it to login after registering.
+            _account = [manager.account copy];
+            
+            // Clean passwords
+            _account.passWord = nil;
+            
+            ANDebug(@"message.code VPN_CB_SMX %zi", error);
+            
+            vpn_smx_info_t *smx_info = manager.smx_info;
+            if (smx_info != NULL) {
+                ANDebug(@"smx_info->action: %d", smx_info->action);
+                switch (smx_info->action) {
+                    case SMX_ACTION_INPUT_PASS:
+                    case SMX_ACTION_INPUT_OLD_PASS:
+                        if ([self.navigationController.topViewController.restorationIdentifier isEqualToString:VIEW_CONTROLLER_ID_SMX_LOGIN]) {
+                            //If the top controller is login controller, do nothing but send the status to it.
+                            [self refreshTopView];
+                            showAlert = YES;
+                        } else {
+                            [self performSegueWithIdentifier:kSegueToSMX sender:nil];
+                            showAlert = NO;
+                        }
+                        break;
+                    case SMX_ACTION_INPUT_NEW_PASS:
+                        if ([self.navigationController.topViewController.restorationIdentifier isEqualToString:VIEW_CONTROLLER_ID_SMX_NEWPASS]) {
+                            //If the top controller is new password controller, do nothing but send the status to it.
+                            [self refreshTopView];
+                            showAlert = YES;
+                            break;
+                        } else {
+                            [self performSegueWithIdentifier:kSegueToSMXChangePassword sender:nil];
+                            showAlert = NO;
+                        }
+                        break;
+                        
+                    case SMX_ACTION_PASS_CONFIRM:
+                        [self performSegueWithIdentifier:kSegueToSMXConfirmPassword sender:nil];
+                        showAlert = NO;
+                        break;
+                        
+                    default:
+                        break;
+                }
+                
+                if (showAlert && smx_info->errmsg[0] != '\0') {
+                    NSString *errorMessage = [NSString stringWithUTF8String:smx_info->errmsg];
+                    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@"" message:errorMessage];
+                    
+                    [self presentViewController:dialog animated:YES completion:nil];
+                }
+            }
+            break;
+        }
+        case VPN_CB_VDI_AUTH: {
+            [self handleVDIAuth];
+            break;
+        }
+        case VPN_CB_SMS: {
+            if ([self.navigationController.topViewController isKindOfClass:[SMSViewController class]]) {
+                [self refreshTopView];
+            } else {
+                [self performSegueWithIdentifier:kSegueToSMS sender:nil];
+            }
+            break;
+        }
+        case VPN_CB_CHANGPASSWORD: {
+            [self performSegueWithIdentifier:kSegueToChangePassword sender:nil];
+            break;
+        }
+        case VPN_CB_SYFERLOCK_LOGIN: {
+            _isSyferLock = YES;
+            if ([self.navigationController.topViewController isKindOfClass:[SyferLockLoginViewController class]]) {
+                [self refreshTopView];
+            } else {
+                [self performSegueWithIdentifier:kSegueToSyferLock sender:nil];
+            }
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+- (void)refreshTopView {
+    UIViewController *top = [self.navigationController topViewController];
+    SEL handler = NSSelectorFromString(@"refreshView");
+    if ([top respondsToSelector:handler]) {
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+        [top performSelector:handler];
+    }
+}
+
+// If last login method contains SMX.
+- (BOOL)isSMXAuth {
+    AAAManager *manager = [AAAManager sharedInstance];
+    
+    VPNAccount *account = _account;
+    if (!account) {
+        account = manager.account;
+    }
+    
+    NSString *currentMethod = account.loginMethod;
+    
+    NSArray *methods = [self allAAAMethods];
+    for (AAAMethod *method in methods) {
+        if ([method.name isEqualToString:currentMethod]) {
+            return method.isSmx;
+        }
+    }
+    
+    return NO;
+}
+
+- (NSString *)loginFailedMessage:(NSInteger)errorCode {
+    AAAManager *manager = [AAAManager sharedInstance];
+    
+    if ([self isSMXAuth]) {
+        // Get error message for SMX auth
+        NSString *errorMessage = manager.errorInformation;
+        if (errorMessage && errorMessage.length > 0) {
+            return errorMessage;
+        }
+        
+        vpn_smx_info_t *smx_info = manager.smx_info;
+        if (smx_info && strlen(smx_info->errmsg) != 0 && [self isValidSMXAction]) {
+            errorMessage = [NSString stringWithUTF8String:smx_info->errmsg];
+            if (errorMessage && ![errorMessage isEqualToString:@"OK"]) {
+                return errorMessage;
+            }
+        }
+    }
+    
+    if (errorCode == ERR_USER_LOCKED) {
+        NSString *errorMessage = manager.errorInformation;
+        if (errorMessage && errorMessage.length > 0) {
+            return errorMessage;
+        }
+    }
+    
+    NSString *errorMessage = manager.errorInformation;
+    if (errorMessage && errorMessage.length > 0) {
+        return errorMessage;
+    }
+    
+    // Return this string for all login error (incorrect username or password) except SMX auth.
+    return NSLocalizedString(@"Login failed, please check username and password", nil);
+}
+
+- (BOOL)isValidSMXAction {
+    vpn_smx_info_t *smx_info = [AAAManager sharedInstance].smx_info;
+    
+    return  (smx_info->action >= SMX_ACTION_UNKNOWN && smx_info->action <= SMX_ACTION_PASS_CONFIRM);
+}
+
+- (void)handleVDIAuth {
+    __weak typeof(self) weakSelf = self;
+    self.alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"VDI Credential", nil)
+                                                               message:NSLocalizedString(@"Please input username and password", nil)
+                                                        preferredStyle:UIAlertControllerStyleAlert];
+    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
+                                                           style:UIAlertActionStyleCancel
+                                                         handler:^(UIAlertAction * _Nonnull action) {
+                                                             VPNAccount *account = [[VPNAccount alloc] init];
+                                                             account.userName = nil;
+                                                             account.passWord = nil;
+                                                             
+                                                             [[AAAManager sharedInstance] continueVPNThreadWithVDIAccount:account];
+                                                         }];
+    UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
+                                                            style:UIAlertActionStyleDefault
+                                                          handler:^(UIAlertAction * _Nonnull action) {
+                                                              NSString *username = weakSelf.alertController.textFields[0].text;  // Username text field
+                                                              NSString *password = weakSelf.alertController.textFields[1].text;  // Password text field
+                                                              username = [username stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
+                                                              VPNAccount *account = [[VPNAccount alloc] init];
+                                                              account.userName = username;
+                                                              account.passWord = password;
+                                                              
+                                                              [[AAAManager sharedInstance] continueVPNThreadWithVDIAccount:account];
+                                                          }];
+    
+    [self.alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = NSLocalizedString(@"Username", nil);
+    }];
+    [self.alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = NSLocalizedString(@"Password", nil);
+    }];
+    [self.alertController addAction:confirmAction];
+    [self.alertController addAction:cancelAction];
+    
+    [self presentViewController:self.alertController animated:YES completion:nil];
+}
+
+- (void)finishLogin:(BOOL)success {
+    self.alertController = nil;
+    
+    __weak typeof(self) weakSelf = self;
+    [self dismissViewControllerAnimated:YES completion:^{
+        [weakSelf.delegate didFinishLogin:success];
+    }];
+}
+
+#pragma mark - Passwords
+- (void)savePasswordsOfAccount:(VPNAccount *)account {
+    Gateway *gateway = [self currentGateway];
+    if (![account.userName isEqualToString:gateway.username]){
+        
+        gateway.username = account.userName;
+        [[[GatewayManager alloc] init] updateGateway:gateway];
+    }
+    
+    if (account.userName){
+        
+        [self saveMethodName];
+        [self savePassWord:account];
+        return;
+    }
+    
+    if (gateway.username) {  // Only remember password when username is configured.
+        
+        [self savePassWord:account];
+    } else {
+        ANDebug(@"Password will be deleted, because the login user is different from the one in settings.");
+        
+        [self deleteMethodName];
+        [account deleteAllPasswords];
+    }
+}
+
+-(void) savePassWord: (VPNAccount *) account
+{
+    NSMutableArray *passwords = [[NSMutableArray alloc] init];
+    if (account.passWord) {
+        [passwords addObject:[account.passWord copy]];
+    }
+    
+    Gateway *gateway = [self currentGateway];
+
+    if (![self isRadiusSavePass:account.loginMethod]){
+        
+        gateway.isRadiusPWD = NO;
+        if (account.passWord2) {
+            [passwords addObject:[account.passWord2 copy]];
+        }
+        if (account.passWord3) {
+            [passwords addObject:[account.passWord3 copy]];
+        }
+    }else{
+        
+        gateway.isRadiusPWD = YES;
+    }
+    
+    [PasswordManager savePasswords:passwords forHost:account.vsHost username:account.userName port:account.vsPort];
+}
+
+-(BOOL) isRadiusSavePass: (NSString *) methodName
+{
+    if (self.allMethodDescs.count < 1 || ISNULLSTR(methodName)){
+        
+        return NO;
+    }
+    
+    NSInteger acount = [self.allMethodNames indexOfObject:methodName];
+    
+    if (acount < 0){
+        
+        return NO;
+    }
+    
+    NSString *methodDesc = [_allMethodDescs objectAtIndex:acount];
+    if ([methodDesc rangeOfString:RADIUS_SAVE_PWD].location != NSNotFound){
+        
+        ANInfo(@"LoginView-isRadiusSavePass- did not save pwd");
+        return YES;
+    }
+    
+    return NO;
+}
+
+-(void) saveMethodName
+{
+    NSString *methodName = self.currentMethod ?: (_methodMenu.titleLabel.text ?: @"");
+    NSString *userName = _usernameTextField.text ?: @"";
+    if ([methodName isEqualToString:@""]){
+        
+        methodName = @"ldb";
+    }
+    
+    NSString *methodType = [Singleton sharedSingleton].isSupportAuth ? @"0" : @"1";
+    NSDictionary *verifyDic = @{@"methodName" : methodName, @"userName" : userName, @"methodType" : methodType};
+    [Singleton setCurrentGatewayMethod:verifyDic andKey:self.gateWay];
+}
+
+-(void) getCurrentMethod
+{
+    auth_type_t type = self.currentMethodType;
+    if (type == AUTH_LOCALDB || type == AUTH_LDAP || type == AUTH_RADIUS || type == AUTH_RADIUS_ACCOUNT ||
+        type == AUTH_DEVID || type == AUTH_HTTP || type == AUTH_CERTIFICATE){
+        
+        [Singleton sharedSingleton].isSupportAuth = YES;
+    }else{
+        
+        [Singleton sharedSingleton].isSupportAuth = NO;
+    }
+    
+    if (type == AUTH_CERTIFICATE){
+        
+        _usernameTextField.text = @"";
+    }
+}
+
+-(void) deleteMethodName
+{
+    [Singleton setCurrentGatewayMethod:@{} andKey:self.gateWay];
+}
+
+- (void)removePasswordsOfAccount:(VPNAccount *)account {
+    [PasswordManager removePasswordsOfHost:account.vsHost username:account.userName port:account.vsPort];
+}
+
+#pragma mark - UITextFieldDelegate
+- (BOOL)textFieldShouldReturn:(UITextField *)textField {
+    if (textField == self.usernameTextField) {
+        [self.usernameTextField resignFirstResponder];
+        if (_currentTableCells.count > 1) {
+            [self.password1TextField becomeFirstResponder];
+        }
+    }
+    
+    return YES;
+}
+
+#pragma mark - ANViewControllerSwitchProtocol
+- (void)switchFromSender:(id)sender withOption:(NSDictionary *)option {
+    if (sender) {
+        self.delegate = sender;
+    }
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LoginViewController.m.MotionPro
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LoginViewController.m.MotionPro	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LoginViewController.m.MotionPro	(working copy)
@@ -0,0 +1,1346 @@
+//
+//  LoginViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/19.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "ANLogger.h"
+#import "AAAManager.h"
+#import "GatewayManager.h"
+#import "ArrayVPNWrapper.h"
+#import "PasswordManager.h"
+#import "InformationToSave.h"
+#import "DropMenuView.h"
+#import "ANPopupDialog.h"
+#import "FilterTypeModel.h"
+#import "UIDevice+Hardware.h"
+#import "SMSViewController.h"
+#import "SyferLockLoginViewController.h"
+#import "UIViewController+Activity.h"
+#import "UIViewController+HideKeyboard.h"
+#import "LoginViewController.h"
+#import "GatewayModel.h"
+#import "Singleton.h"
+
+static NSString * const methodCellID = @"LoginMethodCell";
+static NSString * const usernameCellID = @"LoginUsernameCell";
+static NSString * const passwordCellID = @"LoginPasswordCell";
+
+static NSString * const kSegueToChangePassword = @"LoginToChangePassword";
+static NSString * const kSegueToRegister = @"LoginToRegister";
+static NSString * const kSegueToChallenge = @"LoginToChallenge";
+static NSString * const kSegueToSMS = @"LoginToSMS";
+static NSString * const kSegueToSMX = @"LoginToSMX";
+static NSString * const kSegueToSMXChangePassword = @"LoginToSMXChangePassword";
+static NSString * const kSegueToSMXConfirmPassword = @"LoginToSMXConfirmPassword";
+static NSString * const kSegueToSyferLock = @"LoginToSyferLock";
+
+#if TARGET_OS_IPHONE
+NSString * const kAppGroupNameLogin = @"group.net.arraynetworks.MotionPro";
+#elif TARGET_OS_MAC
+NSString * const kAppGroupNameLogin = @"5VZLZ3YQ9P.net.arraynetworks.MacTunnel";
+#endif
+
+#define VIEW_CONTROLLER_ID_SMX_LOGIN            @"SMXLoginViewControllerID"
+#define VIEW_CONTROLLER_ID_SMX_NEWPASS          @"SMXNewPasswordViewControllerID"
+#define VIEW_CONTROLLER_ID_SMX_CONFIRM          @"SMXConfirmPasswordViewControllerID"
+
+#define TABLEVIEW_HEADER_HEIGHT         15
+#define TABLEVIEW_FOOTER_HEIGHT         CGFLOAT_MIN
+#define TABLEVIEW_CELL_HEIGHT           60
+#define TABLEVIEW_CELL_PADDING          10
+
+#define LABEL_TAG_ON_METHOD_CELL        1
+#define IMAGE_VIEW_TAG_ON_METHOD_CELL   2
+#define TEXTFIELD_TAG_ON_USERNAME_CELL  1
+#define TEXTFIELD_TAG_ON_PASSWORD_CELL  1
+
+#define DUMMY_PASSWD                    @"##&&**"
+#define OAUTH_SESSION_URL               @"/prx/000/http/localh/"
+#define RADIUS_SAVE_PWD                 @"radius_save_pwd"
+
+typedef enum {
+    kLoginCellMethodIndex = 0,
+    kLoginCellUsernameIndex,
+    kLoginCellPasswordIndex,
+    kLoginCellPassword2Index,
+    kLoginCellPassword3Index
+} LoginCellIndex;
+
+#define LOGIN_TABLE_SECTIONS    1
+
+@interface LoginViewController () <DropMenuDelegate, DropMenuDataSource, UITableViewDelegate, UITextFieldDelegate> {
+    DropMenuView    *_methodMenu;
+    
+    BOOL            _isMultiMethods;
+    BOOL            _isOAuthMethods;
+
+    NSArray         *_allMethodNames;
+    NSArray         *_allMethodDescs;
+    NSArray         *_currentTableCells;
+    
+    NSArray         *_realPasswords;
+    
+    VPNAccount      *_account;
+    BOOL            _isSMX;
+    BOOL            _isSyferLock;
+}
+
+@property (nonatomic, readonly) NSString    *currentMethod;
+@property (nonatomic)           NSUInteger  currentMethodIndex;
+@property (nonatomic, readonly) NSArray     *currentTableCells;
+@property (nonatomic, readonly) NSArray     *allMethodNames;
+@property (nonatomic, readonly) NSArray     *allMethodDescs;
+@property (nonatomic, strong)   NSArray     *methodActions;
+@property (nonatomic, strong)   NSArray     *methodRequests;
+@property (nonatomic, strong)   AAAManager  *model;
+@property (nonatomic, strong)   UITextField *usernameTextField;
+@property (nonatomic, strong)   UITextField *password1TextField;
+@property (nonatomic, strong)   UITextField *password2TextField;
+@property (nonatomic, strong)   UITextField *password3TextField;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *tableViewHeightConstraint;
+
+@property (weak, nonatomic) IBOutlet UITableView *tableView;
+@property (weak, nonatomic) IBOutlet UIButton *loginButton;
+
+@property (strong, nonatomic) UIAlertController *alertController;
+@property (weak, nonatomic) IBOutlet UILabel *methodNameLable;
+@property (nonatomic, strong) Gateway *gateWay;
+@property (assign, nonatomic) auth_type_t currentMethodType;
+
+@end
+
+@implementation LoginViewController
+
+- (void)dealloc {
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+    
+    self.model = nil;
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    
+    self.model = [AAAManager sharedInstance];
+    self.gateWay = [[[GatewayModel alloc] init] currentGatewayUpInside];
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleVPNNotification:) name:kVPNMessageNotification object:nil];
+    
+    [self enableHideKeyboard];
+    [self setLoginButtonAppearance];
+    
+    [self getSavedPassword];
+    [self initMethodView];
+    [self tryToAutoLogin];
+    
+    //iOS15新特性
+    if (@available(iOS 15.0, *)) {
+        
+        self.tableView.sectionHeaderTopPadding = 0;
+    }
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (IBAction)loginButtonClicked:(id)sender {
+    NSArray *allDescs = self.allMethodDescs;
+    if (allDescs && allDescs.count > 0) {
+        NSString *methodDesc = [allDescs objectAtIndex:_currentMethodIndex];
+        NSArray *parsedMethodDesc = [self parseMethodDesc:methodDesc];
+        if (parsedMethodDesc.count > 1) {
+            NSString *methodInfo;
+            for (int i = 0; i < parsedMethodDesc.count; i++) {
+                if ([[parsedMethodDesc objectAtIndex:i] containsString:KEY_METHOD_OAUTH]) {
+                    methodInfo = [parsedMethodDesc objectAtIndex:i];
+                    break;
+                }
+            }
+            
+            self.methodActions = [self parseMethodAction:methodInfo];
+            self.methodRequests = [self parseMethodRequest:methodInfo];
+            ANInfo(@"Oauth method action=%@, request =%@", self.methodActions, self.methodRequests);
+            NSString *oAuthurlInfo;
+            
+            for (int i = 0; i < self.methodActions.count; i++) {
+                int iAction = [[self.methodActions objectAtIndex:i] intValue] - 1;
+                if (iAction < self.methodRequests.count) {
+                    oAuthurlInfo = [self.methodRequests objectAtIndex:iAction];
+                    ANInfo(@"Oauth url info=%@", oAuthurlInfo);
+                }
+                
+                if ([oAuthurlInfo length] <= 0) {
+                    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                                  message:NSLocalizedString(@"Login failed, get oAuth info failed.",nil)];
+                    [self presentViewController:dialog animated:YES completion:nil];
+                    return;
+                }
+                if ([oAuthurlInfo containsString:@"http://"] || [oAuthurlInfo containsString:@"https://"]) {
+                    OpenURL([NSURL URLWithString:oAuthurlInfo]);  // Install app.
+                    return;
+                }
+                if ([self saveOAuthCodeLoginInfo:oAuthurlInfo]) {
+                    ANInfo(@"launch customer app and save oauth code info.");
+                    break;
+                }
+            }
+            
+            [self showLoginActivity:NO];
+            [self finishLogin:NO];
+            
+            [[AAAManager sharedInstance] cancelLoginTapped];
+            
+            [self dismissViewControllerAnimated:YES completion:nil];
+            return;
+        }
+    }
+    
+    NSInteger passwordCount = _isMultiMethods ? _currentTableCells.count - 2 : _currentTableCells.count - 1; // Substract method & username fields.
+    if (passwordCount > 0) {
+        if (![self checkPasswordFieldWithPasswordCount:passwordCount]) {
+            return;
+        }
+    }
+    
+    [self login];
+}
+
+- (IBAction)exitButtonClicked:(id)sender {
+    [self showLoginActivity:NO];
+    [self finishLogin:NO];
+    
+    [[AAAManager sharedInstance] cancelLoginTapped];
+    
+    [self dismissViewControllerAnimated:YES completion:nil];
+}
+
+- (void)setLoginButtonAppearance {
+    self.loginButton.layer.cornerRadius = 2.5;
+    self.loginButton.layer.shadowOffset = CGSizeMake(5.0, 5.0);
+    self.loginButton.layer.shadowColor = MAIN_COLOR.CGColor;
+    self.loginButton.layer.shadowOpacity = 0.25;
+}
+
+- (void)initMethodView {
+    if ([self allAAAMethods].count == 0) {
+        __weak typeof(self) weakSelf = self;
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                      message:NSLocalizedString(@"Incorrect server configuration!",nil)
+                                                                       action:^{
+                                                                           [weakSelf cancelLogin];
+                                                                       }];
+        [self presentViewController:dialog animated:YES completion:nil];
+    } else if ([self allAAAMethods].count > 1) {
+        _isMultiMethods = YES;
+    }else if ([self allAAAMethods].count > 0 && self.model.isOAuthType){ //认证方式
+        
+        _isMultiMethods = YES;
+    }
+    
+    _currentMethodIndex = 0;
+    _currentTableCells = [self cellsForMethodIndex:_currentMethodIndex];
+    if (_currentTableCells.count == 0) {
+        // Only deviceID auth, auto login.
+        __weak typeof(self) weakSelf = self;
+        dispatch_async(dispatch_get_main_queue(), ^{
+            [weakSelf login];
+        });
+    }
+}
+
+- (NSArray *)allAAAMethods {
+    return [self.model allAAAMehtods];
+}
+
+#pragma mark - Properties
+
+- (NSString *)currentMethod {
+    NSArray *allNames = self.allMethodNames;
+    if (!allNames || allNames.count == 0) {
+        return nil;
+    } else {
+        return [allNames objectAtIndex:_currentMethodIndex];
+    }
+}
+
+-(auth_type_t) currentMethodType{
+    
+    NSArray *typeArray = [self allAAAMethods];
+    
+    if (!typeArray || typeArray.count == 0) {
+        return -1;
+    } else {
+        
+        AAAMethod *method = [typeArray objectAtIndex:_currentMethodIndex];
+        if (method != nil){
+            
+            return method.authType;
+        }
+    }
+    return -1;
+}
+
+- (void)setCurrentMethodIndex:(NSUInteger)currentMethodIndex {
+    if (_currentMethodIndex == currentMethodIndex) {
+        return;
+    }
+    
+    _currentMethodIndex = currentMethodIndex;
+    _currentTableCells = [self cellsForMethodIndex:_currentMethodIndex];
+}
+
+- (NSArray*)allMethodNames {
+    if (_allMethodNames != nil) {
+        return _allMethodNames;
+    }
+    
+    NSMutableArray *names = [[NSMutableArray alloc] init];
+    
+    for (AAAMethod *method in [self allAAAMethods]) {
+        [names addObject:method.name];
+    }
+    
+    _allMethodNames = names;
+    
+    return _allMethodNames;
+}
+
+- (NSArray*)allMethodDescs {
+    if (_allMethodDescs != nil) {
+        return _allMethodDescs;
+    }
+    
+    NSMutableArray *descs = [[NSMutableArray alloc] init];
+    
+    for (AAAMethod *method in [self allAAAMethods]) {
+        [descs addObject:method.methodDescription];
+    }
+    
+    _allMethodDescs = descs;
+    
+    return _allMethodDescs;
+}
+
+#pragma mark - Parse Method
+
+- (NSArray *)parseMethodDesc:(NSString *)methodDesc {
+    NSMutableArray *methodParsed = [[NSMutableArray alloc] init];
+    
+    if ([methodDesc containsString:KEY_METHOD_OAUTH] && [methodDesc containsString:KEY_METHOD_MOBILE_ENABLE]) {
+        NSCharacterSet *delimiters = [NSCharacterSet characterSetWithCharactersInString:@"()"];
+        return [methodDesc componentsSeparatedByCharactersInSet:delimiters];
+    } else {
+        [methodParsed addObject:methodDesc];
+    }
+    
+    return methodParsed;
+}
+
+- (NSArray *)parseMethodAction:(NSString *)methodInfo {
+    NSString *methodAction;
+    NSMutableArray *actionArray = [[NSMutableArray alloc] init];
+    
+    if (methodInfo && [methodInfo containsString:KEY_METHOD_MOBILE_ENABLE]) {
+        NSArray *methodInfoArray = [methodInfo componentsSeparatedByString:@"@"];
+        for (int i = 0; i < methodInfoArray.count; i++) {
+            methodInfo = [methodInfoArray objectAtIndex:i];
+            if ([methodInfo containsString:KEY_METHOD_ACTION]) {
+                NSRange range = [methodInfo rangeOfString:KEY_METHOD_ACTION];
+                methodInfo = [methodInfo substringFromIndex:range.location + range.length];
+                NSArray *methodActionArray = [methodInfo componentsSeparatedByString:@"&"];
+                for(int j = 0; j < methodActionArray.count; j++) {
+                    methodInfo = [methodActionArray objectAtIndex:j];
+                    if ([methodInfo containsString:KEY_METHOD_MOBILE]) {
+                        range = [methodInfo rangeOfString:KEY_METHOD_MOBILE];
+                        methodAction = [methodInfo substringFromIndex:range.location + range.length];
+                        
+                        break;
+                    }
+                }
+            }
+        }
+        
+        if (methodAction.length > 0) {
+            for (int i = 0; i < methodAction.length; i ++) {
+                NSString *temp = [methodAction substringWithRange:NSMakeRange(i, 1)];
+                [actionArray addObject:temp];
+            }
+        }
+    }
+    
+    return actionArray;
+}
+
+- (NSArray *)parseMethodRequest:(NSString *)methodInfo {
+    NSMutableArray *methodRequestArray = [[NSMutableArray alloc] init];
+    NSString *methodBuf;
+    NSArray *methodReqArrayBuf;
+    
+    if (methodInfo && [methodInfo containsString:KEY_METHOD_MOBILE_ENABLE]) {
+        NSArray *methodInfoArray = [methodInfo componentsSeparatedByString:@"@"];
+        for (int i = 0; i < methodInfoArray.count; i++) {
+            methodBuf = [methodInfoArray objectAtIndex:i];
+            if ([methodBuf containsString:@"request"]) {
+                methodReqArrayBuf = [methodBuf componentsSeparatedByString:@"&"];
+                break;
+            }
+        }
+        
+        for (int i = 0; i < methodReqArrayBuf.count; i ++) {
+            NSString *req = [methodReqArrayBuf objectAtIndex:i];
+            req = [req substringFromIndex:9];
+            [methodRequestArray addObject:req];
+        }
+    }
+    
+    return methodRequestArray;
+}
+
+- (BOOL)saveOAuthCodeLoginInfo:(NSString *)oauthInfo {
+    if (![oauthInfo containsString:KEY_METHOD_RELIAO]) {
+        return NO;
+    }
+    
+    NSString *reliaoURL = @"reliao://f/vpn?action=login&callback=motionproplus%3a%2f%2fsetcode%3fcode%3d";
+    NSURL *url = [NSURL URLWithString:reliaoURL];
+    
+    if (!OpenURL(url)) {
+        return NO;
+    }
+    
+    oauthInfo = [oauthInfo substringToIndex:[oauthInfo rangeOfString:KEY_METHOD_RELIAO].location];
+    Gateway *gateway = [self currentGateway];
+    NSString *urlString = nil;
+    if ([gateway.port isEqualToString:@"443"]) {
+        urlString = [NSString stringWithFormat:@"https://%@%@%@", gateway.host, OAUTH_SESSION_URL, oauthInfo];
+    } else {
+        urlString = [NSString stringWithFormat:@"https://%@:%@%@%@", gateway.host, gateway.port, OAUTH_SESSION_URL, oauthInfo];
+    }
+    ANInfo(@"continue login url=%@", urlString);
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameLogin];
+    [userDefaults setValue:urlString forKey:KEY_OAUTH_URL];
+    
+    return YES;
+}
+
+#pragma mark - Login Related
+- (void)login {
+    ANInfo(@"------------>Start login...<------------");
+    
+    [self.view endEditing:YES];
+    
+    [self getCurrentMethod];
+    
+    VPNAccount *account = [self inputResult];
+    NSLog(@"vpn account on login: %@",account);
+    
+    if (account == nil) {
+        ANWarn(@"Cannot get account information");
+        return;
+    }
+    
+    InformationToSave *info = [InformationToSave sharedInstance];
+    
+    info.lastLoginAccount = account;
+    [info save];
+    
+    self.model.errorCode = 0; // Success
+    [self.model continueVPNThreadWithAccount:account];
+    
+    [self showLoginActivity:YES];
+}
+
+- (void)cancelLogin {
+    [self showLoginActivity:NO];
+    
+    [self.model cancelLoginTapped];
+}
+
+- (VPNAccount *)inputResult {
+    VPNAccount * account = self.model.account;
+    
+    account.loginMethod = self.currentMethod;
+    account.userName = self.usernameTextField.text;
+    
+    //Get account passwords
+    if ([self.password1TextField.text isEqualToString:DUMMY_PASSWD]) {
+        account.passWord = _realPasswords[0];
+    } else {
+        account.passWord = self.password1TextField.text;
+    }
+    
+    if ([self.password2TextField.text isEqualToString:DUMMY_PASSWD]) {
+        account.passWord2 = _realPasswords[1];
+    } else {
+        account.passWord2 = self.password2TextField.text;
+    }
+    
+    if ([self.password3TextField.text isEqualToString:DUMMY_PASSWD]) {
+        account.passWord3 = _realPasswords[2];
+    } else {
+        account.passWord3 = self.password3TextField.text;
+    }
+    
+    UIDevice *devInfo = [UIDevice currentDevice];
+    account.deviceName =[NSString stringWithFormat:@"%@|Apple;%@;iOS %@", devInfo.name, devInfo.platformString, devInfo.systemVersion];
+    
+    return account;
+}
+
+//Get all cells for the given method
+- (NSArray *)cellsForMethodIndex:(NSUInteger)index {
+    NSArray *methods = [self allAAAMethods];
+    if (methods == nil || methods.count == 0) {
+        ANError(@"No method found for login.");
+        return nil;
+    }
+    
+    AAAMethod *method = [methods objectAtIndex:index];
+    if (method == nil) {
+        return nil;
+    }
+    
+    NSMutableArray *cells = [[NSMutableArray alloc] init];
+    
+    for (InputField *field in method.inputFields) {
+        UITableViewCell *cell = [self cellForInputField:field];
+        if (cell == nil) {
+            ANError(@"Unknow inputField type %d", field.type);
+            continue;
+        }
+        
+        if (field.type == FieldTypeUsernameText) {
+            // Make sure Username is above password
+            [cells insertObject:cell atIndex:0];
+        } else {
+            [cells addObject:cell];
+        }
+    }
+    
+    NSString *infoDesc;
+    if (_isMultiMethods) {
+        //Display the method names
+        UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:methodCellID];
+        [self initMethodMenuWithCell:cell];
+        _methodMenu.titleLabel =  (UILabel *)[cell viewWithTag:1];
+        NSArray *pasedMethodDesc = [self parseMethodDesc:method.methodDescription];
+        if (pasedMethodDesc.count > 0) {
+            infoDesc = [pasedMethodDesc objectAtIndex:0];
+        } else {
+            infoDesc = method.methodDescription;
+        }
+        _methodMenu.titleLabel.text = infoDesc;
+        //Method cell shoud be at the top.
+        if (cell != nil) {
+            [cells insertObject:cell atIndex:0];
+        }
+    }
+    
+    return cells;
+}
+
+// Create a cell for the inputed field.
+- (UITableViewCell *)cellForInputField:(InputField *)field {
+    UITableViewCell *cell = nil;
+    
+    Gateway *gateway = [self currentGateway];
+    
+    NSString *username = self.model.account.userName;
+    if (!username || username.length == 0) {
+        username = gateway.username;
+    }
+    
+    NSString *passwd;
+    
+    switch (field.type) {
+        case FieldTypeUsernameText: {
+            //username field
+            cell = [self.tableView dequeueReusableCellWithIdentifier:usernameCellID];
+            self.usernameTextField = (UITextField *)[cell viewWithTag:TEXTFIELD_TAG_ON_USERNAME_CELL];
+            if (field.inputString) {
+                self.usernameTextField.text = field.inputString;
+            } else {
+                self.usernameTextField.text = username;
+            }
+            break;
+        }
+        case FieldTypePasswordText: {
+            switch (field.passwordIndex) {
+                case INDEX_PASSWORD1: {
+                    cell = [self.tableView dequeueReusableCellWithIdentifier:passwordCellID];
+                    self.password1TextField = (UITextField *) [cell viewWithTag:TEXTFIELD_TAG_ON_PASSWORD_CELL];
+                    self.password1TextField.placeholder = [NSString stringWithFormat:@"%@(%@)", NSLocalizedString(@"Password", nil), field.fieldDescription ?: @""];
+                    
+                    passwd = _realPasswords[0];
+                    if (passwd.length > 0) {
+                        self.password1TextField.text = DUMMY_PASSWD;
+                    }
+                    break;
+                }
+                case INDEX_PASSWORD2: {
+                    cell = [self.tableView dequeueReusableCellWithIdentifier:passwordCellID];
+                    self.password2TextField = (UITextField *) [cell viewWithTag:TEXTFIELD_TAG_ON_PASSWORD_CELL];
+                    self.password2TextField.placeholder = [NSString stringWithFormat:@"%@(%@)", NSLocalizedString(@"Password", nil), field.fieldDescription ?: @""];
+                    
+                    passwd = _realPasswords[1];
+                    if (passwd.length > 0) {
+                        self.password2TextField.text = DUMMY_PASSWD;
+                    }
+                    break;
+                }
+                case INDEX_PASSWORD3: {
+                    cell = [self.tableView dequeueReusableCellWithIdentifier:passwordCellID];
+                    self.password3TextField = (UITextField *) [cell viewWithTag:TEXTFIELD_TAG_ON_PASSWORD_CELL];
+                    self.password3TextField.placeholder = [NSString stringWithFormat:@"%@(%@)", NSLocalizedString(@"Password", nil), field.fieldDescription ?: @""];
+                    
+                    passwd = _realPasswords[0];
+                    if (passwd.length > 0) {
+                        self.password3TextField.text = DUMMY_PASSWD;
+                    }
+                    break;
+                }
+                default:
+                    break;
+            }
+            break;
+        }
+        default:
+            break;
+    }
+    
+    return cell;
+}
+
+- (Gateway *)currentGateway {
+    NSString *url = self.model.account.vsURL;
+    NSString *port = self.model.account.vsPort;
+    Gateway *gateway = [[GatewayManager sharedInstance] gatewayOfUrl:url andport:port];
+    
+    return gateway;
+}
+
+- (void)getSavedPassword {
+    Gateway *gateway = [self currentGateway];
+    NSString *username = gateway.username;
+    
+    _realPasswords = @[@"", @"", @""];
+    if (username != nil) {
+        if (!gateway.lastAccessedDate) {  // Prevent from getting saved password after reinstall.
+            [PasswordManager removePasswordsOfHost:gateway.host username:username port:gateway.port];
+        }
+        
+        if (gateway.isSavePasswordEnabled) {
+            _realPasswords = [PasswordManager passwordsOfHost:gateway.host username:username port:gateway.port];
+        } else {
+            ANDebug(@"delete user \"%@\" password", username?username:@"nil");
+            
+            if (!gateway.isFaceOrTouchIDEnabled && !gateway.isGestureEnabled){
+                
+                [self deleteMethodName];
+                [self.model.account deleteAllPasswords];
+            }
+        }
+    }
+}
+
+- (void)tryToAutoLogin {
+    Gateway *gateway = [self currentGateway];
+    BOOL showLoginDialog = gateway.isShowLoginDialogEnabled;
+    
+    if (gateway.isSavePasswordEnabled) {
+        if (!showLoginDialog && (_currentTableCells.count == 1 || ![_realPasswords isEqual:@[@"", @"", @""]])) {
+            dispatch_async(dispatch_get_main_queue(), ^{
+                [self login];
+            });
+        }
+    }
+}
+
+#pragma mark - Table view data source
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return LOGIN_TABLE_SECTIONS;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    NSInteger totalCells = _currentTableCells.count;
+    [self updateTableViewHeightWithCellsNumber:totalCells];
+    return _currentTableCells.count;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    return _currentTableCells[indexPath.row];
+}
+
+- (void)updateTableViewHeightWithCellsNumber:(NSInteger)cells {
+    self.tableViewHeightConstraint.constant = cells * TABLEVIEW_CELL_HEIGHT + TABLEVIEW_CELL_PADDING;
+}
+
+#pragma mark - SyferLock switch
+- (BOOL)isSyferLockEnabled {
+    Gateway *gateway = [self currentGateway];
+    if (!gateway) {
+        ANInfo(@"Current gateway is nil, no syferlock can be enabled.");
+        return NO;
+    } else {
+        return gateway.isSyferLockEnabled;
+    }
+}
+
+#pragma mark - UITableViewDelegate
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    
+    if (@available(iOS 15.0, *)){
+           
+        return 0.1;
+    }
+    
+    return TABLEVIEW_HEADER_HEIGHT;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return TABLEVIEW_FOOTER_HEIGHT;
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    [tableView deselectRowAtIndexPath:indexPath animated:YES];
+    
+    if (indexPath.section == 0 && indexPath.row == kLoginCellMethodIndex && _isMultiMethods) {  // Deal with method drop-down menu.
+        [_methodMenu showMenuOnView:self.view];
+    }
+}
+
+- (BOOL)checkPasswordFieldWithPasswordCount:(NSInteger)count {
+    enum PasswordCount {
+        kPasswordOne = 1,
+        kPasswordTwo = 2,
+        kPasswordThree = 3
+    };
+    
+    BOOL result = YES;
+    
+    switch (count) {
+        case kPasswordOne:
+            if ([self.password1TextField.text isEqualToString:@""]) {
+                result = NO;
+            }
+            break;
+        case kPasswordTwo:
+            if ([self.password1TextField.text isEqualToString:@""] ||
+                [self.password2TextField.text isEqualToString:@""]) {
+                result = NO;
+            }
+            break;
+        case kPasswordThree:
+            if ([self.password1TextField.text isEqualToString:@""] ||
+                [self.password2TextField.text isEqualToString:@""] ||
+                [self.password3TextField.text isEqualToString:@""]) {
+                result = NO;
+            }
+            break;
+        default:
+            break;
+    }
+    
+    if (!result) {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                      message:NSLocalizedString(@"Login failed, please check username and password",nil)];
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+    
+    return result;
+}
+
+- (void)initMethodMenuWithCell:(UITableViewCell *)cell {
+    if (!_methodMenu) {
+        _methodMenu = [[DropMenuView alloc] initWithOrigin:CGPointMake(0, cell.frame.size.height+TABLEVIEW_HEADER_HEIGHT)];
+        _methodMenu.delegate = self;
+        _methodMenu.dataSource = self;
+        _methodMenu.transformImageView = [cell viewWithTag:IMAGE_VIEW_TAG_ON_METHOD_CELL];
+        _methodMenu.titleLabel = nil;
+    }
+    
+    [_methodMenu reloadData];
+}
+
+#pragma mark menuDelegate
+
+- (NSMutableArray<FilterTypeModel *> *)menu_filterDataArray {
+    NSMutableArray *array = nil;
+    NSArray *descs = self.allMethodDescs;
+    NSString *methodDesc;
+    
+    NSInteger index = -1;
+    array = [NSMutableArray arrayWithCapacity:descs.count];
+    for (NSString *desc in descs) {
+        ++index;
+        methodDesc = desc;
+        NSArray *pasedMethodDesc = [self parseMethodDesc:desc];
+        if (pasedMethodDesc.count > 0) {
+            methodDesc = [pasedMethodDesc objectAtIndex:0];
+        }
+        
+        FilterTypeModel *model = [[FilterTypeModel alloc] initWithName:methodDesc andId:[NSString stringWithFormat:@"%zi", index]];
+        [array addObject:model];
+    }
+    
+    return array;
+}
+
+- (void)menu:(DropMenuView *)menu tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    self.currentMethodIndex = indexPath.row;
+    
+    [self.tableView reloadData];
+}
+
+//VPN notifications handler
+- (void)handleVPNNotification:(NSNotification *)notification {
+    VPNMessage *message = notification.object;
+    AAAManager *manager = [AAAManager sharedInstance];
+    NSInteger error = manager.errorCode;
+    NSString *aMessage;
+    BOOL showAlert = YES;
+    
+    switch (message.code) {
+        case VPN_CB_CONNECTED: {
+            if (!_isSMX) {
+                // Save passwords for non-SMX login.
+                [self savePasswordsOfAccount:manager.account];
+            }
+            [self finishLogin:YES];
+            break;
+        }
+        case VPN_CB_DISCONNECTING: {
+            [self finishLogin:NO];
+            break;
+        }
+        case VPN_CB_DEVID_REG: {
+            if (!_isSMX) {
+                // Save the current account
+                // In SMX, the account has been saved.
+                _account = [manager.account copy];
+            } else {
+                // SMX, clean the saved password, since it is useless after register.
+                manager.account.passWord = nil;
+            }
+            
+            [self performSegueWithIdentifier:kSegueToRegister sender:nil];
+            break;
+        }
+        case VPN_CB_CHALLENGE: {
+            [self performSegueWithIdentifier:kSegueToChallenge sender:nil];
+            break;
+        }
+        case VPN_CB_CONN_FAILED: {
+            switch (error) {
+                case ERR_DEVID_APPROVE_PENDING:
+                    aMessage = NSLocalizedString(@"Your device is registering, please request manager approval",nil);
+                    break;
+                case ERR_DEVID_APPROVE_DENY:
+                    aMessage = NSLocalizedString(@"Register device deny, not allow register device auto approve",nil);
+                    break;
+                case ERR_DEVID_USER_LIMIT:
+                    aMessage = NSLocalizedString(@"User for this device has reached his or her limit",nil);
+                    break;
+                case ERR_DEVID_DEV_LIMIT:
+                    aMessage = NSLocalizedString(@"Device has reached its limit",nil);
+                    break;
+                case ERR_WRONG_USER_PASS:
+                    if (!_isSyferLock) {  // DON'T remove saved password if SyferLock is enabled.
+                        [self deleteMethodName];
+                        [manager.account deleteAllPasswords];
+                    }
+                    aMessage = manager.errorInformation;
+                    //aMessage = NSLocalizedString(@"Login failed, please check username and password",nil);
+                    break;
+                case ERR_AUTHORIZE_FAILED:
+                    aMessage = NSLocalizedString(@"Login failed", nil);
+                    break;
+                case ERR_CALLBACK_FAILED:
+                    break;
+                case ERR_INTERRUPTED:
+                    break;
+                case ERR_CLIENT_SECURITY:
+                    aMessage = NSLocalizedString(@"Client security is not supported", nil);
+                    break;
+                case ERR_CERT_NO:
+                    aMessage = NSLocalizedString(@"Client certificate not supply", nil);
+                    break;
+                case ERR_CERT_INVALID_SIGNTURE:
+                    aMessage = NSLocalizedString(@"Client certificate invalid signture", nil);
+                    break;
+                case ERR_CERT_UNTRUSTED:
+                    aMessage = NSLocalizedString(@"Client certificate untrusted", nil);
+                    break;
+                case ERR_CERT_EXPIRED:
+                    aMessage = NSLocalizedString(@"Client certificate expired", nil);
+                    break;
+                case ERR_CERT_INVALID:
+                    aMessage = NSLocalizedString(@"Client certificate invalid", nil);
+                    break;
+                case ERR_CERT_REVOKED:
+                    aMessage = NSLocalizedString(@"Client certificate revoked", nil);
+                    break;
+                case ERR_SMS_GET_PHONE:
+                    aMessage = NSLocalizedString(@"The system failed to get your phone number to do OTP authentication", nil);
+                    break;
+                case ERR_SMS_SEND:
+                    aMessage = NSLocalizedString(@"The system failed to send message to your phone", nil);
+                    break;
+                case ERR_SMS_TOO_MANY_RETRY:
+                    aMessage = NSLocalizedString(@"Your attempt to sign in failed, because you have entered wrong SMS verification code for too many times", nil);
+                    break;
+                case ERR_HWID_DENY:
+                    aMessage = NSLocalizedString(@"The device is denied because of wrong hardware ID!", nil);
+                    break;
+                case ERR_HWID_PENDING:
+                    aMessage = NSLocalizedString(@"The hardware ID of this device is not approved yet!", nil);
+                    break;
+                default:
+                    ANError(@"Login failed with error message: %@", aMessage);
+                    break;
+            }
+            
+            // Try to show error message, only valid on viewcontroller still exists.
+            if (![self currentGateway].isShowLoginDialogEnabled) {
+                if (aMessage && aMessage.length > 0) {
+                    if (![aMessage containsString:@"<a href='"]) {
+                        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:aMessage];
+                        [self presentViewController:dialog animated:YES completion:nil];
+                    } else {
+                        ANInfo(@"Connect failed:Error message=%@", aMessage);
+                        NSRange subStrRange = [aMessage rangeOfString:@"<a href='"];
+                        NSMutableString *finalMessage = [NSMutableString stringWithString:aMessage];
+                        [finalMessage deleteCharactersInRange:NSMakeRange(subStrRange.location, (int)strlen("<a href='"))];
+                        NSString *displayMessage = [finalMessage substringToIndex:[finalMessage rangeOfString:@"'>"].location];
+                        ANInfo(@"Connect failed:Display message=%@", displayMessage);
+                        
+                        NSString *URLMessage = [aMessage substringFromIndex:(subStrRange.location + subStrRange.length)];
+                        URLMessage = [URLMessage substringToIndex:[URLMessage rangeOfString:@"'>"].location];
+                        ANInfo(@"URL message=%@", URLMessage);
+                        
+                        PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil) message:displayMessage confirmAction:^{
+                                                                    NSURL *url = [NSURL URLWithString:URLMessage];
+                                                                    OpenURL(url);
+                                                                    }
+                                                        cancelAction:nil];
+                        [self presentViewController:popup animated:YES completion:nil];
+                    }
+                }
+            }
+            
+            break;
+        }
+        case VPN_CB_LOGIN:
+        case VPN_CB_SYFERLOCK_AUTH: {
+            if (error == ERR_WRONG_USER_PASS || error == ERR_USER_LOCKED) {
+                __weak typeof(self) weakSelf = self;
+                if (![manager.errorInformation containsString:@"<a href='"]) {
+                    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                                  message:[self loginFailedMessage:error]
+                                                                                   action:^{
+                                                                                       [weakSelf showLoginActivity:NO];
+                                                                                       
+                                                                                       // If password is wrong, pop to root view.
+                                                                                       [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                                   }];
+                    [self presentViewController:dialog animated:YES completion:nil];
+                } else {
+                    ANInfo(@"Error message=%@", manager.errorInformation);
+                    NSRange subStrRange = [manager.errorInformation rangeOfString:@"<a href='"];
+                    NSMutableString *finalMessage = [NSMutableString stringWithString:manager.errorInformation];
+                    [finalMessage deleteCharactersInRange:NSMakeRange(subStrRange.location, (int)strlen("<a href='"))];
+                    NSString *displayMessage = [finalMessage substringToIndex:[finalMessage rangeOfString:@"'>"].location];
+                    ANInfo(@"Display message=%@", displayMessage);
+                    
+                    NSString *URLMessage = [manager.errorInformation substringFromIndex:(subStrRange.location + subStrRange.length)];
+                    URLMessage = [URLMessage substringToIndex:[URLMessage rangeOfString:@"'>"].location];
+                    ANInfo(@"URL message=%@", URLMessage);
+                    
+                    PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil) message:displayMessage confirmAction:^{
+                                                                NSURL *url = [NSURL URLWithString:URLMessage];
+                                                                OpenURL(url);
+                                                                [weakSelf showLoginActivity:NO];
+                        
+                                                                // If password is wrong, pop to root view.
+                                                                [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                }
+                                               cancelAction:^{
+                                                                [weakSelf showLoginActivity:NO];
+                                                                // If password is wrong, pop to root view.
+                                                                [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                }];
+                    [self presentViewController:popup animated:YES completion:nil];
+                }
+                
+                if (!_isSyferLock) {
+                    [self removePasswordsOfAccount:manager.account];
+                }
+                
+                ANError(@"Error message: %@", manager.errorInformation);
+            } else if (error == ERR_AUTHORIZE_FAILED) {
+                PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@""
+                                                                              message:NSLocalizedString(@"Authorize failed",nil)];
+                [self presentViewController:dialog animated:YES completion:nil];
+                
+                [self removePasswordsOfAccount:manager.account];
+            } else if (error == ERR_SUCCESS) {
+                //After register, we need to login again. Using the account we have saved.
+                if (!_account) {
+                    _account = [AAAManager sharedInstance].account;
+                }
+                [manager continueVPNThreadWithAccount:_account];
+                
+                break;
+            }
+            break;
+        }
+        case VPN_CB_SMX: {
+            _isSMX = YES;
+            
+            // Save password(s) for multi-step auth.
+            [self savePasswordsOfAccount:manager.account];
+            // Save current account, and use it to login after registering.
+            _account = [manager.account copy];
+            
+            // Clean passwords
+            _account.passWord = nil;
+            
+            ANDebug(@"message.code VPN_CB_SMX %zi", error);
+            
+            vpn_smx_info_t *smx_info = manager.smx_info;
+            if (smx_info != NULL) {
+                ANDebug(@"smx_info->action: %d", smx_info->action);
+                switch (smx_info->action) {
+                    case SMX_ACTION_INPUT_PASS:
+                    case SMX_ACTION_INPUT_OLD_PASS:
+                        if ([self.navigationController.topViewController.restorationIdentifier isEqualToString:VIEW_CONTROLLER_ID_SMX_LOGIN]) {
+                            //If the top controller is login controller, do nothing but send the status to it.
+                            [self refreshTopView];
+                            showAlert = YES;
+                        } else {
+                            [self performSegueWithIdentifier:kSegueToSMX sender:nil];
+                            showAlert = NO;
+                        }
+                        break;
+                    case SMX_ACTION_INPUT_NEW_PASS:
+                        if ([self.navigationController.topViewController.restorationIdentifier isEqualToString:VIEW_CONTROLLER_ID_SMX_NEWPASS]) {
+                            //If the top controller is new password controller, do nothing but send the status to it.
+                            [self refreshTopView];
+                            showAlert = YES;
+                            break;
+                        } else {
+                            [self performSegueWithIdentifier:kSegueToSMXChangePassword sender:nil];
+                            showAlert = NO;
+                        }
+                        break;
+                        
+                    case SMX_ACTION_PASS_CONFIRM:
+                        [self performSegueWithIdentifier:kSegueToSMXConfirmPassword sender:nil];
+                        showAlert = NO;
+                        break;
+                        
+                    default:
+                        break;
+                }
+                
+                if (showAlert && smx_info->errmsg[0] != '\0') {
+                    NSString *errorMessage = [NSString stringWithUTF8String:smx_info->errmsg];
+                    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@"" message:errorMessage];
+                    
+                    [self presentViewController:dialog animated:YES completion:nil];
+                }
+            }
+            break;
+        }
+        case VPN_CB_VDI_AUTH: {
+            [self handleVDIAuth];
+            break;
+        }
+        case VPN_CB_SMS: {
+            if ([self.navigationController.topViewController isKindOfClass:[SMSViewController class]]) {
+                [self refreshTopView];
+            } else {
+                [self performSegueWithIdentifier:kSegueToSMS sender:nil];
+            }
+            break;
+        }
+        case VPN_CB_CHANGPASSWORD: {
+            [self performSegueWithIdentifier:kSegueToChangePassword sender:nil];
+            break;
+        }
+        case VPN_CB_SYFERLOCK_LOGIN: {
+            _isSyferLock = YES;
+            if ([self.navigationController.topViewController isKindOfClass:[SyferLockLoginViewController class]]) {
+                [self refreshTopView];
+            } else {
+                [self performSegueWithIdentifier:kSegueToSyferLock sender:nil];
+            }
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+- (void)refreshTopView {
+    UIViewController *top = [self.navigationController topViewController];
+    SEL handler = NSSelectorFromString(@"refreshView");
+    if ([top respondsToSelector:handler]) {
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+        [top performSelector:handler];
+    }
+}
+
+// If last login method contains SMX.
+- (BOOL)isSMXAuth {
+    AAAManager *manager = [AAAManager sharedInstance];
+    
+    VPNAccount *account = _account;
+    if (!account) {
+        account = manager.account;
+    }
+    
+    NSString *currentMethod = account.loginMethod;
+    
+    NSArray *methods = [self allAAAMethods];
+    for (AAAMethod *method in methods) {
+        if ([method.name isEqualToString:currentMethod]) {
+            return method.isSmx;
+        }
+    }
+    
+    return NO;
+}
+
+- (NSString *)loginFailedMessage:(NSInteger)errorCode {
+    AAAManager *manager = [AAAManager sharedInstance];
+    
+    if ([self isSMXAuth]) {
+        // Get error message for SMX auth
+        NSString *errorMessage = manager.errorInformation;
+        if (errorMessage && errorMessage.length > 0) {
+            return errorMessage;
+        }
+        
+        vpn_smx_info_t *smx_info = manager.smx_info;
+        if (smx_info && strlen(smx_info->errmsg) != 0 && [self isValidSMXAction]) {
+            errorMessage = [NSString stringWithUTF8String:smx_info->errmsg];
+            if (errorMessage && ![errorMessage isEqualToString:@"OK"]) {
+                return errorMessage;
+            }
+        }
+    }
+    
+    if (errorCode == ERR_USER_LOCKED) {
+        NSString *errorMessage = manager.errorInformation;
+        if (errorMessage && errorMessage.length > 0) {
+            return errorMessage;
+        }
+    }
+    
+    NSString *errorMessage = manager.errorInformation;
+    if (errorMessage && errorMessage.length > 0) {
+        return errorMessage;
+    }
+    
+    // Return this string for all login error (incorrect username or password) except SMX auth.
+    return NSLocalizedString(@"Login failed, please check username and password", nil);
+}
+
+- (BOOL)isValidSMXAction {
+    vpn_smx_info_t *smx_info = [AAAManager sharedInstance].smx_info;
+    
+    return  (smx_info->action >= SMX_ACTION_UNKNOWN && smx_info->action <= SMX_ACTION_PASS_CONFIRM);
+}
+
+- (void)handleVDIAuth {
+    __weak typeof(self) weakSelf = self;
+    self.alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"VDI Credential", nil)
+                                                               message:NSLocalizedString(@"Please input username and password", nil)
+                                                        preferredStyle:UIAlertControllerStyleAlert];
+    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
+                                                           style:UIAlertActionStyleCancel
+                                                         handler:^(UIAlertAction * _Nonnull action) {
+                                                             VPNAccount *account = [[VPNAccount alloc] init];
+                                                             account.userName = nil;
+                                                             account.passWord = nil;
+                                                             
+                                                             [[AAAManager sharedInstance] continueVPNThreadWithVDIAccount:account];
+                                                         }];
+    UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
+                                                            style:UIAlertActionStyleDefault
+                                                          handler:^(UIAlertAction * _Nonnull action) {
+                                                              NSString *username = weakSelf.alertController.textFields[0].text;  // Username text field
+                                                              NSString *password = weakSelf.alertController.textFields[1].text;  // Password text field
+                                                              username = [username stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
+                                                              VPNAccount *account = [[VPNAccount alloc] init];
+                                                              account.userName = username;
+                                                              account.passWord = password;
+                                                              
+                                                              [[AAAManager sharedInstance] continueVPNThreadWithVDIAccount:account];
+                                                          }];
+    
+    [self.alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = NSLocalizedString(@"Username", nil);
+    }];
+    [self.alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = NSLocalizedString(@"Password", nil);
+    }];
+    [self.alertController addAction:confirmAction];
+    [self.alertController addAction:cancelAction];
+    
+    [self presentViewController:self.alertController animated:YES completion:nil];
+}
+
+- (void)finishLogin:(BOOL)success {
+    self.alertController = nil;
+    
+    __weak typeof(self) weakSelf = self;
+    [self dismissViewControllerAnimated:YES completion:^{
+        [weakSelf.delegate didFinishLogin:success];
+    }];
+}
+
+#pragma mark - Passwords
+- (void)savePasswordsOfAccount:(VPNAccount *)account {
+    Gateway *gateway = [self currentGateway];
+    if (![account.userName isEqualToString:gateway.username]){
+        
+        gateway.username = account.userName;
+        [[[GatewayManager alloc] init] updateGateway:gateway];
+    }
+    
+    if (account.userName){
+        
+        [self saveMethodName];
+        [self savePassWord:account];
+        return;
+    }
+    
+    if (gateway.username) {  // Only remember password when username is configured.
+        
+        [self savePassWord:account];
+    } else {
+        ANDebug(@"Password will be deleted, because the login user is different from the one in settings.");
+        
+        [self deleteMethodName];
+        [account deleteAllPasswords];
+    }
+}
+
+-(void) savePassWord: (VPNAccount *) account
+{
+    NSMutableArray *passwords = [[NSMutableArray alloc] init];
+    if (account.passWord) {
+        [passwords addObject:[account.passWord copy]];
+    }
+    
+    Gateway *gateway = [self currentGateway];
+
+    if (![self isRadiusSavePass:account.loginMethod]){
+        
+        gateway.isRadiusPWD = NO;
+        if (account.passWord2) {
+            [passwords addObject:[account.passWord2 copy]];
+        }
+        if (account.passWord3) {
+            [passwords addObject:[account.passWord3 copy]];
+        }
+    }else{
+        
+        gateway.isRadiusPWD = YES;
+    }
+    
+    [PasswordManager savePasswords:passwords forHost:account.vsHost username:account.userName port:account.vsPort];
+}
+
+-(BOOL) isRadiusSavePass: (NSString *) methodName
+{
+    if (self.allMethodDescs.count < 1 || ISNULLSTR(methodName)){
+        
+        return NO;
+    }
+    
+    NSInteger acount = [self.allMethodNames indexOfObject:methodName];
+    
+    if (acount < 0){
+        
+        return NO;
+    }
+    
+    NSString *methodDesc = [_allMethodDescs objectAtIndex:acount];
+    if ([methodDesc rangeOfString:RADIUS_SAVE_PWD].location != NSNotFound){
+        
+        ANInfo(@"LoginView-isRadiusSavePass- did not save pwd");
+        return YES;
+    }
+    
+    return NO;
+}
+
+-(void) saveMethodName
+{
+    NSString *methodName = self.currentMethod ?: (_methodMenu.titleLabel.text ?: @"");
+    NSString *userName = _usernameTextField.text ?: @"";
+    if ([methodName isEqualToString:@""]){
+        
+        methodName = @"ldb";
+    }
+    
+    NSString *methodType = [Singleton sharedSingleton].isSupportAuth ? @"0" : @"1";
+    NSDictionary *verifyDic = @{@"methodName" : methodName, @"userName" : userName, @"methodType" : methodType};
+    [Singleton setCurrentGatewayMethod:verifyDic andKey:self.gateWay];
+}
+
+-(void) getCurrentMethod
+{
+    auth_type_t type = self.currentMethodType;
+    if (type == AUTH_LOCALDB || type == AUTH_LDAP || type == AUTH_RADIUS || type == AUTH_RADIUS_ACCOUNT ||
+        type == AUTH_DEVID || type == AUTH_HTTP || type == AUTH_CERTIFICATE){
+        
+        [Singleton sharedSingleton].isSupportAuth = YES;
+    }else{
+        
+        [Singleton sharedSingleton].isSupportAuth = NO;
+    }
+    
+    if (type == AUTH_CERTIFICATE){
+        
+        _usernameTextField.text = @"";
+    }
+}
+
+-(void) deleteMethodName
+{
+    [Singleton setCurrentGatewayMethod:@{} andKey:self.gateWay];
+}
+
+- (void)removePasswordsOfAccount:(VPNAccount *)account {
+    [PasswordManager removePasswordsOfHost:account.vsHost username:account.userName port:account.vsPort];
+}
+
+#pragma mark - UITextFieldDelegate
+- (BOOL)textFieldShouldReturn:(UITextField *)textField {
+    if (textField == self.usernameTextField) {
+        [self.usernameTextField resignFirstResponder];
+        if (_currentTableCells.count > 1) {
+            [self.password1TextField becomeFirstResponder];
+        }
+    }
+    
+    return YES;
+}
+
+#pragma mark - ANViewControllerSwitchProtocol
+- (void)switchFromSender:(id)sender withOption:(NSDictionary *)option {
+    if (sender) {
+        self.delegate = sender;
+    }
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LoginViewController.m.MotionProEnterprise
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LoginViewController.m.MotionProEnterprise	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/LoginViewController.m.MotionProEnterprise	(working copy)
@@ -0,0 +1,1346 @@
+//
+//  LoginViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/19.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "ANLogger.h"
+#import "AAAManager.h"
+#import "GatewayManager.h"
+#import "ArrayVPNWrapper.h"
+#import "PasswordManager.h"
+#import "InformationToSave.h"
+#import "DropMenuView.h"
+#import "ANPopupDialog.h"
+#import "FilterTypeModel.h"
+#import "UIDevice+Hardware.h"
+#import "SMSViewController.h"
+#import "SyferLockLoginViewController.h"
+#import "UIViewController+Activity.h"
+#import "UIViewController+HideKeyboard.h"
+#import "LoginViewController.h"
+#import "GatewayModel.h"
+#import "Singleton.h"
+
+static NSString * const methodCellID = @"LoginMethodCell";
+static NSString * const usernameCellID = @"LoginUsernameCell";
+static NSString * const passwordCellID = @"LoginPasswordCell";
+
+static NSString * const kSegueToChangePassword = @"LoginToChangePassword";
+static NSString * const kSegueToRegister = @"LoginToRegister";
+static NSString * const kSegueToChallenge = @"LoginToChallenge";
+static NSString * const kSegueToSMS = @"LoginToSMS";
+static NSString * const kSegueToSMX = @"LoginToSMX";
+static NSString * const kSegueToSMXChangePassword = @"LoginToSMXChangePassword";
+static NSString * const kSegueToSMXConfirmPassword = @"LoginToSMXConfirmPassword";
+static NSString * const kSegueToSyferLock = @"LoginToSyferLock";
+
+#if TARGET_OS_IPHONE
+NSString * const kAppGroupNameLogin = @"group.net.arraynetworks.groupenterprise";
+#elif TARGET_OS_MAC
+NSString * const kAppGroupNameLogin = @"5VZLZ3YQ9P.net.arraynetworks.MacTunnel";
+#endif
+
+#define VIEW_CONTROLLER_ID_SMX_LOGIN            @"SMXLoginViewControllerID"
+#define VIEW_CONTROLLER_ID_SMX_NEWPASS          @"SMXNewPasswordViewControllerID"
+#define VIEW_CONTROLLER_ID_SMX_CONFIRM          @"SMXConfirmPasswordViewControllerID"
+
+#define TABLEVIEW_HEADER_HEIGHT         15
+#define TABLEVIEW_FOOTER_HEIGHT         CGFLOAT_MIN
+#define TABLEVIEW_CELL_HEIGHT           60
+#define TABLEVIEW_CELL_PADDING          10
+
+#define LABEL_TAG_ON_METHOD_CELL        1
+#define IMAGE_VIEW_TAG_ON_METHOD_CELL   2
+#define TEXTFIELD_TAG_ON_USERNAME_CELL  1
+#define TEXTFIELD_TAG_ON_PASSWORD_CELL  1
+
+#define DUMMY_PASSWD                    @"##&&**"
+#define OAUTH_SESSION_URL               @"/prx/000/http/localh/"
+#define RADIUS_SAVE_PWD                 @"radius_save_pwd"
+
+typedef enum {
+    kLoginCellMethodIndex = 0,
+    kLoginCellUsernameIndex,
+    kLoginCellPasswordIndex,
+    kLoginCellPassword2Index,
+    kLoginCellPassword3Index
+} LoginCellIndex;
+
+#define LOGIN_TABLE_SECTIONS    1
+
+@interface LoginViewController () <DropMenuDelegate, DropMenuDataSource, UITableViewDelegate, UITextFieldDelegate> {
+    DropMenuView    *_methodMenu;
+    
+    BOOL            _isMultiMethods;
+    BOOL            _isOAuthMethods;
+
+    NSArray         *_allMethodNames;
+    NSArray         *_allMethodDescs;
+    NSArray         *_currentTableCells;
+    
+    NSArray         *_realPasswords;
+    
+    VPNAccount      *_account;
+    BOOL            _isSMX;
+    BOOL            _isSyferLock;
+}
+
+@property (nonatomic, readonly) NSString    *currentMethod;
+@property (nonatomic)           NSUInteger  currentMethodIndex;
+@property (nonatomic, readonly) NSArray     *currentTableCells;
+@property (nonatomic, readonly) NSArray     *allMethodNames;
+@property (nonatomic, readonly) NSArray     *allMethodDescs;
+@property (nonatomic, strong)   NSArray     *methodActions;
+@property (nonatomic, strong)   NSArray     *methodRequests;
+@property (nonatomic, strong)   AAAManager  *model;
+@property (nonatomic, strong)   UITextField *usernameTextField;
+@property (nonatomic, strong)   UITextField *password1TextField;
+@property (nonatomic, strong)   UITextField *password2TextField;
+@property (nonatomic, strong)   UITextField *password3TextField;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *tableViewHeightConstraint;
+
+@property (weak, nonatomic) IBOutlet UITableView *tableView;
+@property (weak, nonatomic) IBOutlet UIButton *loginButton;
+
+@property (strong, nonatomic) UIAlertController *alertController;
+@property (weak, nonatomic) IBOutlet UILabel *methodNameLable;
+@property (nonatomic, strong) Gateway *gateWay;
+@property (assign, nonatomic) auth_type_t currentMethodType;
+
+@end
+
+@implementation LoginViewController
+
+- (void)dealloc {
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+    
+    self.model = nil;
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    
+    self.model = [AAAManager sharedInstance];
+    self.gateWay = [[[GatewayModel alloc] init] currentGatewayUpInside];
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleVPNNotification:) name:kVPNMessageNotification object:nil];
+    
+    [self enableHideKeyboard];
+    [self setLoginButtonAppearance];
+    
+    [self getSavedPassword];
+    [self initMethodView];
+    [self tryToAutoLogin];
+    
+    //iOS15新特性
+    if (@available(iOS 15.0, *)) {
+        
+        self.tableView.sectionHeaderTopPadding = 0;
+    }
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (IBAction)loginButtonClicked:(id)sender {
+    NSArray *allDescs = self.allMethodDescs;
+    if (allDescs && allDescs.count > 0) {
+        NSString *methodDesc = [allDescs objectAtIndex:_currentMethodIndex];
+        NSArray *parsedMethodDesc = [self parseMethodDesc:methodDesc];
+        if (parsedMethodDesc.count > 1) {
+            NSString *methodInfo;
+            for (int i = 0; i < parsedMethodDesc.count; i++) {
+                if ([[parsedMethodDesc objectAtIndex:i] containsString:KEY_METHOD_OAUTH]) {
+                    methodInfo = [parsedMethodDesc objectAtIndex:i];
+                    break;
+                }
+            }
+            
+            self.methodActions = [self parseMethodAction:methodInfo];
+            self.methodRequests = [self parseMethodRequest:methodInfo];
+            ANInfo(@"Oauth method action=%@, request =%@", self.methodActions, self.methodRequests);
+            NSString *oAuthurlInfo;
+            
+            for (int i = 0; i < self.methodActions.count; i++) {
+                int iAction = [[self.methodActions objectAtIndex:i] intValue] - 1;
+                if (iAction < self.methodRequests.count) {
+                    oAuthurlInfo = [self.methodRequests objectAtIndex:iAction];
+                    ANInfo(@"Oauth url info=%@", oAuthurlInfo);
+                }
+                
+                if ([oAuthurlInfo length] <= 0) {
+                    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                                  message:NSLocalizedString(@"Login failed, get oAuth info failed.",nil)];
+                    [self presentViewController:dialog animated:YES completion:nil];
+                    return;
+                }
+                if ([oAuthurlInfo containsString:@"http://"] || [oAuthurlInfo containsString:@"https://"]) {
+                    OpenURL([NSURL URLWithString:oAuthurlInfo]);  // Install app.
+                    return;
+                }
+                if ([self saveOAuthCodeLoginInfo:oAuthurlInfo]) {
+                    ANInfo(@"launch customer app and save oauth code info.");
+                    break;
+                }
+            }
+            
+            [self showLoginActivity:NO];
+            [self finishLogin:NO];
+            
+            [[AAAManager sharedInstance] cancelLoginTapped];
+            
+            [self dismissViewControllerAnimated:YES completion:nil];
+            return;
+        }
+    }
+    
+    NSInteger passwordCount = _isMultiMethods ? _currentTableCells.count - 2 : _currentTableCells.count - 1; // Substract method & username fields.
+    if (passwordCount > 0) {
+        if (![self checkPasswordFieldWithPasswordCount:passwordCount]) {
+            return;
+        }
+    }
+    
+    [self login];
+}
+
+- (IBAction)exitButtonClicked:(id)sender {
+    [self showLoginActivity:NO];
+    [self finishLogin:NO];
+    
+    [[AAAManager sharedInstance] cancelLoginTapped];
+    
+    [self dismissViewControllerAnimated:YES completion:nil];
+}
+
+- (void)setLoginButtonAppearance {
+    self.loginButton.layer.cornerRadius = 2.5;
+    self.loginButton.layer.shadowOffset = CGSizeMake(5.0, 5.0);
+    self.loginButton.layer.shadowColor = MAIN_COLOR.CGColor;
+    self.loginButton.layer.shadowOpacity = 0.25;
+}
+
+- (void)initMethodView {
+    if ([self allAAAMethods].count == 0) {
+        __weak typeof(self) weakSelf = self;
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                      message:NSLocalizedString(@"Incorrect server configuration!",nil)
+                                                                       action:^{
+                                                                           [weakSelf cancelLogin];
+                                                                       }];
+        [self presentViewController:dialog animated:YES completion:nil];
+    } else if ([self allAAAMethods].count > 1) {
+        _isMultiMethods = YES;
+    }else if ([self allAAAMethods].count > 0 && self.model.isOAuthType){ //认证方式
+        
+        _isMultiMethods = YES;
+    }
+    
+    _currentMethodIndex = 0;
+    _currentTableCells = [self cellsForMethodIndex:_currentMethodIndex];
+    if (_currentTableCells.count == 0) {
+        // Only deviceID auth, auto login.
+        __weak typeof(self) weakSelf = self;
+        dispatch_async(dispatch_get_main_queue(), ^{
+            [weakSelf login];
+        });
+    }
+}
+
+- (NSArray *)allAAAMethods {
+    return [self.model allAAAMehtods];
+}
+
+#pragma mark - Properties
+
+- (NSString *)currentMethod {
+    NSArray *allNames = self.allMethodNames;
+    if (!allNames || allNames.count == 0) {
+        return nil;
+    } else {
+        return [allNames objectAtIndex:_currentMethodIndex];
+    }
+}
+
+-(auth_type_t) currentMethodType{
+    
+    NSArray *typeArray = [self allAAAMethods];
+    
+    if (!typeArray || typeArray.count == 0) {
+        return -1;
+    } else {
+        
+        AAAMethod *method = [typeArray objectAtIndex:_currentMethodIndex];
+        if (method != nil){
+            
+            return method.authType;
+        }
+    }
+    return -1;
+}
+
+- (void)setCurrentMethodIndex:(NSUInteger)currentMethodIndex {
+    if (_currentMethodIndex == currentMethodIndex) {
+        return;
+    }
+    
+    _currentMethodIndex = currentMethodIndex;
+    _currentTableCells = [self cellsForMethodIndex:_currentMethodIndex];
+}
+
+- (NSArray*)allMethodNames {
+    if (_allMethodNames != nil) {
+        return _allMethodNames;
+    }
+    
+    NSMutableArray *names = [[NSMutableArray alloc] init];
+    
+    for (AAAMethod *method in [self allAAAMethods]) {
+        [names addObject:method.name];
+    }
+    
+    _allMethodNames = names;
+    
+    return _allMethodNames;
+}
+
+- (NSArray*)allMethodDescs {
+    if (_allMethodDescs != nil) {
+        return _allMethodDescs;
+    }
+    
+    NSMutableArray *descs = [[NSMutableArray alloc] init];
+    
+    for (AAAMethod *method in [self allAAAMethods]) {
+        [descs addObject:method.methodDescription];
+    }
+    
+    _allMethodDescs = descs;
+    
+    return _allMethodDescs;
+}
+
+#pragma mark - Parse Method
+
+- (NSArray *)parseMethodDesc:(NSString *)methodDesc {
+    NSMutableArray *methodParsed = [[NSMutableArray alloc] init];
+    
+    if ([methodDesc containsString:KEY_METHOD_OAUTH] && [methodDesc containsString:KEY_METHOD_MOBILE_ENABLE]) {
+        NSCharacterSet *delimiters = [NSCharacterSet characterSetWithCharactersInString:@"()"];
+        return [methodDesc componentsSeparatedByCharactersInSet:delimiters];
+    } else {
+        [methodParsed addObject:methodDesc];
+    }
+    
+    return methodParsed;
+}
+
+- (NSArray *)parseMethodAction:(NSString *)methodInfo {
+    NSString *methodAction;
+    NSMutableArray *actionArray = [[NSMutableArray alloc] init];
+    
+    if (methodInfo && [methodInfo containsString:KEY_METHOD_MOBILE_ENABLE]) {
+        NSArray *methodInfoArray = [methodInfo componentsSeparatedByString:@"@"];
+        for (int i = 0; i < methodInfoArray.count; i++) {
+            methodInfo = [methodInfoArray objectAtIndex:i];
+            if ([methodInfo containsString:KEY_METHOD_ACTION]) {
+                NSRange range = [methodInfo rangeOfString:KEY_METHOD_ACTION];
+                methodInfo = [methodInfo substringFromIndex:range.location + range.length];
+                NSArray *methodActionArray = [methodInfo componentsSeparatedByString:@"&"];
+                for(int j = 0; j < methodActionArray.count; j++) {
+                    methodInfo = [methodActionArray objectAtIndex:j];
+                    if ([methodInfo containsString:KEY_METHOD_MOBILE]) {
+                        range = [methodInfo rangeOfString:KEY_METHOD_MOBILE];
+                        methodAction = [methodInfo substringFromIndex:range.location + range.length];
+                        
+                        break;
+                    }
+                }
+            }
+        }
+        
+        if (methodAction.length > 0) {
+            for (int i = 0; i < methodAction.length; i ++) {
+                NSString *temp = [methodAction substringWithRange:NSMakeRange(i, 1)];
+                [actionArray addObject:temp];
+            }
+        }
+    }
+    
+    return actionArray;
+}
+
+- (NSArray *)parseMethodRequest:(NSString *)methodInfo {
+    NSMutableArray *methodRequestArray = [[NSMutableArray alloc] init];
+    NSString *methodBuf;
+    NSArray *methodReqArrayBuf;
+    
+    if (methodInfo && [methodInfo containsString:KEY_METHOD_MOBILE_ENABLE]) {
+        NSArray *methodInfoArray = [methodInfo componentsSeparatedByString:@"@"];
+        for (int i = 0; i < methodInfoArray.count; i++) {
+            methodBuf = [methodInfoArray objectAtIndex:i];
+            if ([methodBuf containsString:@"request"]) {
+                methodReqArrayBuf = [methodBuf componentsSeparatedByString:@"&"];
+                break;
+            }
+        }
+        
+        for (int i = 0; i < methodReqArrayBuf.count; i ++) {
+            NSString *req = [methodReqArrayBuf objectAtIndex:i];
+            req = [req substringFromIndex:9];
+            [methodRequestArray addObject:req];
+        }
+    }
+    
+    return methodRequestArray;
+}
+
+- (BOOL)saveOAuthCodeLoginInfo:(NSString *)oauthInfo {
+    if (![oauthInfo containsString:KEY_METHOD_RELIAO]) {
+        return NO;
+    }
+    
+    NSString *reliaoURL = @"reliao://f/vpn?action=login&callback=motionproplus%3a%2f%2fsetcode%3fcode%3d";
+    NSURL *url = [NSURL URLWithString:reliaoURL];
+    
+    if (!OpenURL(url)) {
+        return NO;
+    }
+    
+    oauthInfo = [oauthInfo substringToIndex:[oauthInfo rangeOfString:KEY_METHOD_RELIAO].location];
+    Gateway *gateway = [self currentGateway];
+    NSString *urlString = nil;
+    if ([gateway.port isEqualToString:@"443"]) {
+        urlString = [NSString stringWithFormat:@"https://%@%@%@", gateway.host, OAUTH_SESSION_URL, oauthInfo];
+    } else {
+        urlString = [NSString stringWithFormat:@"https://%@:%@%@%@", gateway.host, gateway.port, OAUTH_SESSION_URL, oauthInfo];
+    }
+    ANInfo(@"continue login url=%@", urlString);
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameLogin];
+    [userDefaults setValue:urlString forKey:KEY_OAUTH_URL];
+    
+    return YES;
+}
+
+#pragma mark - Login Related
+- (void)login {
+    ANInfo(@"------------>Start login...<------------");
+    
+    [self.view endEditing:YES];
+    
+    [self getCurrentMethod];
+    
+    VPNAccount *account = [self inputResult];
+    NSLog(@"vpn account on login: %@",account);
+    
+    if (account == nil) {
+        ANWarn(@"Cannot get account information");
+        return;
+    }
+    
+    InformationToSave *info = [InformationToSave sharedInstance];
+    
+    info.lastLoginAccount = account;
+    [info save];
+    
+    self.model.errorCode = 0; // Success
+    [self.model continueVPNThreadWithAccount:account];
+    
+    [self showLoginActivity:YES];
+}
+
+- (void)cancelLogin {
+    [self showLoginActivity:NO];
+    
+    [self.model cancelLoginTapped];
+}
+
+- (VPNAccount *)inputResult {
+    VPNAccount * account = self.model.account;
+    
+    account.loginMethod = self.currentMethod;
+    account.userName = self.usernameTextField.text;
+    
+    //Get account passwords
+    if ([self.password1TextField.text isEqualToString:DUMMY_PASSWD]) {
+        account.passWord = _realPasswords[0];
+    } else {
+        account.passWord = self.password1TextField.text;
+    }
+    
+    if ([self.password2TextField.text isEqualToString:DUMMY_PASSWD]) {
+        account.passWord2 = _realPasswords[1];
+    } else {
+        account.passWord2 = self.password2TextField.text;
+    }
+    
+    if ([self.password3TextField.text isEqualToString:DUMMY_PASSWD]) {
+        account.passWord3 = _realPasswords[2];
+    } else {
+        account.passWord3 = self.password3TextField.text;
+    }
+    
+    UIDevice *devInfo = [UIDevice currentDevice];
+    account.deviceName =[NSString stringWithFormat:@"%@|Apple;%@;iOS %@", devInfo.name, devInfo.platformString, devInfo.systemVersion];
+    
+    return account;
+}
+
+//Get all cells for the given method
+- (NSArray *)cellsForMethodIndex:(NSUInteger)index {
+    NSArray *methods = [self allAAAMethods];
+    if (methods == nil || methods.count == 0) {
+        ANError(@"No method found for login.");
+        return nil;
+    }
+    
+    AAAMethod *method = [methods objectAtIndex:index];
+    if (method == nil) {
+        return nil;
+    }
+    
+    NSMutableArray *cells = [[NSMutableArray alloc] init];
+    
+    for (InputField *field in method.inputFields) {
+        UITableViewCell *cell = [self cellForInputField:field];
+        if (cell == nil) {
+            ANError(@"Unknow inputField type %d", field.type);
+            continue;
+        }
+        
+        if (field.type == FieldTypeUsernameText) {
+            // Make sure Username is above password
+            [cells insertObject:cell atIndex:0];
+        } else {
+            [cells addObject:cell];
+        }
+    }
+    
+    NSString *infoDesc;
+    if (_isMultiMethods) {
+        //Display the method names
+        UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:methodCellID];
+        [self initMethodMenuWithCell:cell];
+        _methodMenu.titleLabel =  (UILabel *)[cell viewWithTag:1];
+        NSArray *pasedMethodDesc = [self parseMethodDesc:method.methodDescription];
+        if (pasedMethodDesc.count > 0) {
+            infoDesc = [pasedMethodDesc objectAtIndex:0];
+        } else {
+            infoDesc = method.methodDescription;
+        }
+        _methodMenu.titleLabel.text = infoDesc;
+        //Method cell shoud be at the top.
+        if (cell != nil) {
+            [cells insertObject:cell atIndex:0];
+        }
+    }
+    
+    return cells;
+}
+
+// Create a cell for the inputed field.
+- (UITableViewCell *)cellForInputField:(InputField *)field {
+    UITableViewCell *cell = nil;
+    
+    Gateway *gateway = [self currentGateway];
+    
+    NSString *username = self.model.account.userName;
+    if (!username || username.length == 0) {
+        username = gateway.username;
+    }
+    
+    NSString *passwd;
+    
+    switch (field.type) {
+        case FieldTypeUsernameText: {
+            //username field
+            cell = [self.tableView dequeueReusableCellWithIdentifier:usernameCellID];
+            self.usernameTextField = (UITextField *)[cell viewWithTag:TEXTFIELD_TAG_ON_USERNAME_CELL];
+            if (field.inputString) {
+                self.usernameTextField.text = field.inputString;
+            } else {
+                self.usernameTextField.text = username;
+            }
+            break;
+        }
+        case FieldTypePasswordText: {
+            switch (field.passwordIndex) {
+                case INDEX_PASSWORD1: {
+                    cell = [self.tableView dequeueReusableCellWithIdentifier:passwordCellID];
+                    self.password1TextField = (UITextField *) [cell viewWithTag:TEXTFIELD_TAG_ON_PASSWORD_CELL];
+                    self.password1TextField.placeholder = [NSString stringWithFormat:@"%@(%@)", NSLocalizedString(@"Password", nil), field.fieldDescription ?: @""];
+                    
+                    passwd = _realPasswords[0];
+                    if (passwd.length > 0) {
+                        self.password1TextField.text = DUMMY_PASSWD;
+                    }
+                    break;
+                }
+                case INDEX_PASSWORD2: {
+                    cell = [self.tableView dequeueReusableCellWithIdentifier:passwordCellID];
+                    self.password2TextField = (UITextField *) [cell viewWithTag:TEXTFIELD_TAG_ON_PASSWORD_CELL];
+                    self.password2TextField.placeholder = [NSString stringWithFormat:@"%@(%@)", NSLocalizedString(@"Password", nil), field.fieldDescription ?: @""];
+                    
+                    passwd = _realPasswords[1];
+                    if (passwd.length > 0) {
+                        self.password2TextField.text = DUMMY_PASSWD;
+                    }
+                    break;
+                }
+                case INDEX_PASSWORD3: {
+                    cell = [self.tableView dequeueReusableCellWithIdentifier:passwordCellID];
+                    self.password3TextField = (UITextField *) [cell viewWithTag:TEXTFIELD_TAG_ON_PASSWORD_CELL];
+                    self.password3TextField.placeholder = [NSString stringWithFormat:@"%@(%@)", NSLocalizedString(@"Password", nil), field.fieldDescription ?: @""];
+                    
+                    passwd = _realPasswords[0];
+                    if (passwd.length > 0) {
+                        self.password3TextField.text = DUMMY_PASSWD;
+                    }
+                    break;
+                }
+                default:
+                    break;
+            }
+            break;
+        }
+        default:
+            break;
+    }
+    
+    return cell;
+}
+
+- (Gateway *)currentGateway {
+    NSString *url = self.model.account.vsURL;
+    NSString *port = self.model.account.vsPort;
+    Gateway *gateway = [[GatewayManager sharedInstance] gatewayOfUrl:url andport:port];
+    
+    return gateway;
+}
+
+- (void)getSavedPassword {
+    Gateway *gateway = [self currentGateway];
+    NSString *username = gateway.username;
+    
+    _realPasswords = @[@"", @"", @""];
+    if (username != nil) {
+        if (!gateway.lastAccessedDate) {  // Prevent from getting saved password after reinstall.
+            [PasswordManager removePasswordsOfHost:gateway.host username:username port:gateway.port];
+        }
+        
+        if (gateway.isSavePasswordEnabled) {
+            _realPasswords = [PasswordManager passwordsOfHost:gateway.host username:username port:gateway.port];
+        } else {
+            ANDebug(@"delete user \"%@\" password", username?username:@"nil");
+            
+            if (!gateway.isFaceOrTouchIDEnabled && !gateway.isGestureEnabled){
+                
+                [self deleteMethodName];
+                [self.model.account deleteAllPasswords];
+            }
+        }
+    }
+}
+
+- (void)tryToAutoLogin {
+    Gateway *gateway = [self currentGateway];
+    BOOL showLoginDialog = gateway.isShowLoginDialogEnabled;
+    
+    if (gateway.isSavePasswordEnabled) {
+        if (!showLoginDialog && (_currentTableCells.count == 1 || ![_realPasswords isEqual:@[@"", @"", @""]])) {
+            dispatch_async(dispatch_get_main_queue(), ^{
+                [self login];
+            });
+        }
+    }
+}
+
+#pragma mark - Table view data source
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return LOGIN_TABLE_SECTIONS;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    NSInteger totalCells = _currentTableCells.count;
+    [self updateTableViewHeightWithCellsNumber:totalCells];
+    return _currentTableCells.count;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    return _currentTableCells[indexPath.row];
+}
+
+- (void)updateTableViewHeightWithCellsNumber:(NSInteger)cells {
+    self.tableViewHeightConstraint.constant = cells * TABLEVIEW_CELL_HEIGHT + TABLEVIEW_CELL_PADDING;
+}
+
+#pragma mark - SyferLock switch
+- (BOOL)isSyferLockEnabled {
+    Gateway *gateway = [self currentGateway];
+    if (!gateway) {
+        ANInfo(@"Current gateway is nil, no syferlock can be enabled.");
+        return NO;
+    } else {
+        return gateway.isSyferLockEnabled;
+    }
+}
+
+#pragma mark - UITableViewDelegate
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    
+    if (@available(iOS 15.0, *)){
+           
+        return 0.1;
+    }
+    
+    return TABLEVIEW_HEADER_HEIGHT;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return TABLEVIEW_FOOTER_HEIGHT;
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    [tableView deselectRowAtIndexPath:indexPath animated:YES];
+    
+    if (indexPath.section == 0 && indexPath.row == kLoginCellMethodIndex && _isMultiMethods) {  // Deal with method drop-down menu.
+        [_methodMenu showMenuOnView:self.view];
+    }
+}
+
+- (BOOL)checkPasswordFieldWithPasswordCount:(NSInteger)count {
+    enum PasswordCount {
+        kPasswordOne = 1,
+        kPasswordTwo = 2,
+        kPasswordThree = 3
+    };
+    
+    BOOL result = YES;
+    
+    switch (count) {
+        case kPasswordOne:
+            if ([self.password1TextField.text isEqualToString:@""]) {
+                result = NO;
+            }
+            break;
+        case kPasswordTwo:
+            if ([self.password1TextField.text isEqualToString:@""] ||
+                [self.password2TextField.text isEqualToString:@""]) {
+                result = NO;
+            }
+            break;
+        case kPasswordThree:
+            if ([self.password1TextField.text isEqualToString:@""] ||
+                [self.password2TextField.text isEqualToString:@""] ||
+                [self.password3TextField.text isEqualToString:@""]) {
+                result = NO;
+            }
+            break;
+        default:
+            break;
+    }
+    
+    if (!result) {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                      message:NSLocalizedString(@"Login failed, please check username and password",nil)];
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+    
+    return result;
+}
+
+- (void)initMethodMenuWithCell:(UITableViewCell *)cell {
+    if (!_methodMenu) {
+        _methodMenu = [[DropMenuView alloc] initWithOrigin:CGPointMake(0, cell.frame.size.height+TABLEVIEW_HEADER_HEIGHT)];
+        _methodMenu.delegate = self;
+        _methodMenu.dataSource = self;
+        _methodMenu.transformImageView = [cell viewWithTag:IMAGE_VIEW_TAG_ON_METHOD_CELL];
+        _methodMenu.titleLabel = nil;
+    }
+    
+    [_methodMenu reloadData];
+}
+
+#pragma mark menuDelegate
+
+- (NSMutableArray<FilterTypeModel *> *)menu_filterDataArray {
+    NSMutableArray *array = nil;
+    NSArray *descs = self.allMethodDescs;
+    NSString *methodDesc;
+    
+    NSInteger index = -1;
+    array = [NSMutableArray arrayWithCapacity:descs.count];
+    for (NSString *desc in descs) {
+        ++index;
+        methodDesc = desc;
+        NSArray *pasedMethodDesc = [self parseMethodDesc:desc];
+        if (pasedMethodDesc.count > 0) {
+            methodDesc = [pasedMethodDesc objectAtIndex:0];
+        }
+        
+        FilterTypeModel *model = [[FilterTypeModel alloc] initWithName:methodDesc andId:[NSString stringWithFormat:@"%zi", index]];
+        [array addObject:model];
+    }
+    
+    return array;
+}
+
+- (void)menu:(DropMenuView *)menu tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    self.currentMethodIndex = indexPath.row;
+    
+    [self.tableView reloadData];
+}
+
+//VPN notifications handler
+- (void)handleVPNNotification:(NSNotification *)notification {
+    VPNMessage *message = notification.object;
+    AAAManager *manager = [AAAManager sharedInstance];
+    NSInteger error = manager.errorCode;
+    NSString *aMessage;
+    BOOL showAlert = YES;
+    
+    switch (message.code) {
+        case VPN_CB_CONNECTED: {
+            if (!_isSMX) {
+                // Save passwords for non-SMX login.
+                [self savePasswordsOfAccount:manager.account];
+            }
+            [self finishLogin:YES];
+            break;
+        }
+        case VPN_CB_DISCONNECTING: {
+            [self finishLogin:NO];
+            break;
+        }
+        case VPN_CB_DEVID_REG: {
+            if (!_isSMX) {
+                // Save the current account
+                // In SMX, the account has been saved.
+                _account = [manager.account copy];
+            } else {
+                // SMX, clean the saved password, since it is useless after register.
+                manager.account.passWord = nil;
+            }
+            
+            [self performSegueWithIdentifier:kSegueToRegister sender:nil];
+            break;
+        }
+        case VPN_CB_CHALLENGE: {
+            [self performSegueWithIdentifier:kSegueToChallenge sender:nil];
+            break;
+        }
+        case VPN_CB_CONN_FAILED: {
+            switch (error) {
+                case ERR_DEVID_APPROVE_PENDING:
+                    aMessage = NSLocalizedString(@"Your device is registering, please request manager approval",nil);
+                    break;
+                case ERR_DEVID_APPROVE_DENY:
+                    aMessage = NSLocalizedString(@"Register device deny, not allow register device auto approve",nil);
+                    break;
+                case ERR_DEVID_USER_LIMIT:
+                    aMessage = NSLocalizedString(@"User for this device has reached his or her limit",nil);
+                    break;
+                case ERR_DEVID_DEV_LIMIT:
+                    aMessage = NSLocalizedString(@"Device has reached its limit",nil);
+                    break;
+                case ERR_WRONG_USER_PASS:
+                    if (!_isSyferLock) {  // DON'T remove saved password if SyferLock is enabled.
+                        [self deleteMethodName];
+                        [manager.account deleteAllPasswords];
+                    }
+                    aMessage = manager.errorInformation;
+                    //aMessage = NSLocalizedString(@"Login failed, please check username and password",nil);
+                    break;
+                case ERR_AUTHORIZE_FAILED:
+                    aMessage = NSLocalizedString(@"Login failed", nil);
+                    break;
+                case ERR_CALLBACK_FAILED:
+                    break;
+                case ERR_INTERRUPTED:
+                    break;
+                case ERR_CLIENT_SECURITY:
+                    aMessage = NSLocalizedString(@"Client security is not supported", nil);
+                    break;
+                case ERR_CERT_NO:
+                    aMessage = NSLocalizedString(@"Client certificate not supply", nil);
+                    break;
+                case ERR_CERT_INVALID_SIGNTURE:
+                    aMessage = NSLocalizedString(@"Client certificate invalid signture", nil);
+                    break;
+                case ERR_CERT_UNTRUSTED:
+                    aMessage = NSLocalizedString(@"Client certificate untrusted", nil);
+                    break;
+                case ERR_CERT_EXPIRED:
+                    aMessage = NSLocalizedString(@"Client certificate expired", nil);
+                    break;
+                case ERR_CERT_INVALID:
+                    aMessage = NSLocalizedString(@"Client certificate invalid", nil);
+                    break;
+                case ERR_CERT_REVOKED:
+                    aMessage = NSLocalizedString(@"Client certificate revoked", nil);
+                    break;
+                case ERR_SMS_GET_PHONE:
+                    aMessage = NSLocalizedString(@"The system failed to get your phone number to do OTP authentication", nil);
+                    break;
+                case ERR_SMS_SEND:
+                    aMessage = NSLocalizedString(@"The system failed to send message to your phone", nil);
+                    break;
+                case ERR_SMS_TOO_MANY_RETRY:
+                    aMessage = NSLocalizedString(@"Your attempt to sign in failed, because you have entered wrong SMS verification code for too many times", nil);
+                    break;
+                case ERR_HWID_DENY:
+                    aMessage = NSLocalizedString(@"The device is denied because of wrong hardware ID!", nil);
+                    break;
+                case ERR_HWID_PENDING:
+                    aMessage = NSLocalizedString(@"The hardware ID of this device is not approved yet!", nil);
+                    break;
+                default:
+                    ANError(@"Login failed with error message: %@", aMessage);
+                    break;
+            }
+            
+            // Try to show error message, only valid on viewcontroller still exists.
+            if (![self currentGateway].isShowLoginDialogEnabled) {
+                if (aMessage && aMessage.length > 0) {
+                    if (![aMessage containsString:@"<a href='"]) {
+                        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:aMessage];
+                        [self presentViewController:dialog animated:YES completion:nil];
+                    } else {
+                        ANInfo(@"Connect failed:Error message=%@", aMessage);
+                        NSRange subStrRange = [aMessage rangeOfString:@"<a href='"];
+                        NSMutableString *finalMessage = [NSMutableString stringWithString:aMessage];
+                        [finalMessage deleteCharactersInRange:NSMakeRange(subStrRange.location, (int)strlen("<a href='"))];
+                        NSString *displayMessage = [finalMessage substringToIndex:[finalMessage rangeOfString:@"'>"].location];
+                        ANInfo(@"Connect failed:Display message=%@", displayMessage);
+                        
+                        NSString *URLMessage = [aMessage substringFromIndex:(subStrRange.location + subStrRange.length)];
+                        URLMessage = [URLMessage substringToIndex:[URLMessage rangeOfString:@"'>"].location];
+                        ANInfo(@"URL message=%@", URLMessage);
+                        
+                        PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil) message:displayMessage confirmAction:^{
+                                                                    NSURL *url = [NSURL URLWithString:URLMessage];
+                                                                    OpenURL(url);
+                                                                    }
+                                                        cancelAction:nil];
+                        [self presentViewController:popup animated:YES completion:nil];
+                    }
+                }
+            }
+            
+            break;
+        }
+        case VPN_CB_LOGIN:
+        case VPN_CB_SYFERLOCK_AUTH: {
+            if (error == ERR_WRONG_USER_PASS || error == ERR_USER_LOCKED) {
+                __weak typeof(self) weakSelf = self;
+                if (![manager.errorInformation containsString:@"<a href='"]) {
+                    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                                  message:[self loginFailedMessage:error]
+                                                                                   action:^{
+                                                                                       [weakSelf showLoginActivity:NO];
+                                                                                       
+                                                                                       // If password is wrong, pop to root view.
+                                                                                       [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                                   }];
+                    [self presentViewController:dialog animated:YES completion:nil];
+                } else {
+                    ANInfo(@"Error message=%@", manager.errorInformation);
+                    NSRange subStrRange = [manager.errorInformation rangeOfString:@"<a href='"];
+                    NSMutableString *finalMessage = [NSMutableString stringWithString:manager.errorInformation];
+                    [finalMessage deleteCharactersInRange:NSMakeRange(subStrRange.location, (int)strlen("<a href='"))];
+                    NSString *displayMessage = [finalMessage substringToIndex:[finalMessage rangeOfString:@"'>"].location];
+                    ANInfo(@"Display message=%@", displayMessage);
+                    
+                    NSString *URLMessage = [manager.errorInformation substringFromIndex:(subStrRange.location + subStrRange.length)];
+                    URLMessage = [URLMessage substringToIndex:[URLMessage rangeOfString:@"'>"].location];
+                    ANInfo(@"URL message=%@", URLMessage);
+                    
+                    PopupDialog *popup = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil) message:displayMessage confirmAction:^{
+                                                                NSURL *url = [NSURL URLWithString:URLMessage];
+                                                                OpenURL(url);
+                                                                [weakSelf showLoginActivity:NO];
+                        
+                                                                // If password is wrong, pop to root view.
+                                                                [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                }
+                                               cancelAction:^{
+                                                                [weakSelf showLoginActivity:NO];
+                                                                // If password is wrong, pop to root view.
+                                                                [weakSelf.navigationController popToRootViewControllerAnimated:YES];
+                                                                }];
+                    [self presentViewController:popup animated:YES completion:nil];
+                }
+                
+                if (!_isSyferLock) {
+                    [self removePasswordsOfAccount:manager.account];
+                }
+                
+                ANError(@"Error message: %@", manager.errorInformation);
+            } else if (error == ERR_AUTHORIZE_FAILED) {
+                PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@""
+                                                                              message:NSLocalizedString(@"Authorize failed",nil)];
+                [self presentViewController:dialog animated:YES completion:nil];
+                
+                [self removePasswordsOfAccount:manager.account];
+            } else if (error == ERR_SUCCESS) {
+                //After register, we need to login again. Using the account we have saved.
+                if (!_account) {
+                    _account = [AAAManager sharedInstance].account;
+                }
+                [manager continueVPNThreadWithAccount:_account];
+                
+                break;
+            }
+            break;
+        }
+        case VPN_CB_SMX: {
+            _isSMX = YES;
+            
+            // Save password(s) for multi-step auth.
+            [self savePasswordsOfAccount:manager.account];
+            // Save current account, and use it to login after registering.
+            _account = [manager.account copy];
+            
+            // Clean passwords
+            _account.passWord = nil;
+            
+            ANDebug(@"message.code VPN_CB_SMX %zi", error);
+            
+            vpn_smx_info_t *smx_info = manager.smx_info;
+            if (smx_info != NULL) {
+                ANDebug(@"smx_info->action: %d", smx_info->action);
+                switch (smx_info->action) {
+                    case SMX_ACTION_INPUT_PASS:
+                    case SMX_ACTION_INPUT_OLD_PASS:
+                        if ([self.navigationController.topViewController.restorationIdentifier isEqualToString:VIEW_CONTROLLER_ID_SMX_LOGIN]) {
+                            //If the top controller is login controller, do nothing but send the status to it.
+                            [self refreshTopView];
+                            showAlert = YES;
+                        } else {
+                            [self performSegueWithIdentifier:kSegueToSMX sender:nil];
+                            showAlert = NO;
+                        }
+                        break;
+                    case SMX_ACTION_INPUT_NEW_PASS:
+                        if ([self.navigationController.topViewController.restorationIdentifier isEqualToString:VIEW_CONTROLLER_ID_SMX_NEWPASS]) {
+                            //If the top controller is new password controller, do nothing but send the status to it.
+                            [self refreshTopView];
+                            showAlert = YES;
+                            break;
+                        } else {
+                            [self performSegueWithIdentifier:kSegueToSMXChangePassword sender:nil];
+                            showAlert = NO;
+                        }
+                        break;
+                        
+                    case SMX_ACTION_PASS_CONFIRM:
+                        [self performSegueWithIdentifier:kSegueToSMXConfirmPassword sender:nil];
+                        showAlert = NO;
+                        break;
+                        
+                    default:
+                        break;
+                }
+                
+                if (showAlert && smx_info->errmsg[0] != '\0') {
+                    NSString *errorMessage = [NSString stringWithUTF8String:smx_info->errmsg];
+                    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@"" message:errorMessage];
+                    
+                    [self presentViewController:dialog animated:YES completion:nil];
+                }
+            }
+            break;
+        }
+        case VPN_CB_VDI_AUTH: {
+            [self handleVDIAuth];
+            break;
+        }
+        case VPN_CB_SMS: {
+            if ([self.navigationController.topViewController isKindOfClass:[SMSViewController class]]) {
+                [self refreshTopView];
+            } else {
+                [self performSegueWithIdentifier:kSegueToSMS sender:nil];
+            }
+            break;
+        }
+        case VPN_CB_CHANGPASSWORD: {
+            [self performSegueWithIdentifier:kSegueToChangePassword sender:nil];
+            break;
+        }
+        case VPN_CB_SYFERLOCK_LOGIN: {
+            _isSyferLock = YES;
+            if ([self.navigationController.topViewController isKindOfClass:[SyferLockLoginViewController class]]) {
+                [self refreshTopView];
+            } else {
+                [self performSegueWithIdentifier:kSegueToSyferLock sender:nil];
+            }
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+- (void)refreshTopView {
+    UIViewController *top = [self.navigationController topViewController];
+    SEL handler = NSSelectorFromString(@"refreshView");
+    if ([top respondsToSelector:handler]) {
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+        [top performSelector:handler];
+    }
+}
+
+// If last login method contains SMX.
+- (BOOL)isSMXAuth {
+    AAAManager *manager = [AAAManager sharedInstance];
+    
+    VPNAccount *account = _account;
+    if (!account) {
+        account = manager.account;
+    }
+    
+    NSString *currentMethod = account.loginMethod;
+    
+    NSArray *methods = [self allAAAMethods];
+    for (AAAMethod *method in methods) {
+        if ([method.name isEqualToString:currentMethod]) {
+            return method.isSmx;
+        }
+    }
+    
+    return NO;
+}
+
+- (NSString *)loginFailedMessage:(NSInteger)errorCode {
+    AAAManager *manager = [AAAManager sharedInstance];
+    
+    if ([self isSMXAuth]) {
+        // Get error message for SMX auth
+        NSString *errorMessage = manager.errorInformation;
+        if (errorMessage && errorMessage.length > 0) {
+            return errorMessage;
+        }
+        
+        vpn_smx_info_t *smx_info = manager.smx_info;
+        if (smx_info && strlen(smx_info->errmsg) != 0 && [self isValidSMXAction]) {
+            errorMessage = [NSString stringWithUTF8String:smx_info->errmsg];
+            if (errorMessage && ![errorMessage isEqualToString:@"OK"]) {
+                return errorMessage;
+            }
+        }
+    }
+    
+    if (errorCode == ERR_USER_LOCKED) {
+        NSString *errorMessage = manager.errorInformation;
+        if (errorMessage && errorMessage.length > 0) {
+            return errorMessage;
+        }
+    }
+    
+    NSString *errorMessage = manager.errorInformation;
+    if (errorMessage && errorMessage.length > 0) {
+        return errorMessage;
+    }
+    
+    // Return this string for all login error (incorrect username or password) except SMX auth.
+    return NSLocalizedString(@"Login failed, please check username and password", nil);
+}
+
+- (BOOL)isValidSMXAction {
+    vpn_smx_info_t *smx_info = [AAAManager sharedInstance].smx_info;
+    
+    return  (smx_info->action >= SMX_ACTION_UNKNOWN && smx_info->action <= SMX_ACTION_PASS_CONFIRM);
+}
+
+- (void)handleVDIAuth {
+    __weak typeof(self) weakSelf = self;
+    self.alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"VDI Credential", nil)
+                                                               message:NSLocalizedString(@"Please input username and password", nil)
+                                                        preferredStyle:UIAlertControllerStyleAlert];
+    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
+                                                           style:UIAlertActionStyleCancel
+                                                         handler:^(UIAlertAction * _Nonnull action) {
+                                                             VPNAccount *account = [[VPNAccount alloc] init];
+                                                             account.userName = nil;
+                                                             account.passWord = nil;
+                                                             
+                                                             [[AAAManager sharedInstance] continueVPNThreadWithVDIAccount:account];
+                                                         }];
+    UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
+                                                            style:UIAlertActionStyleDefault
+                                                          handler:^(UIAlertAction * _Nonnull action) {
+                                                              NSString *username = weakSelf.alertController.textFields[0].text;  // Username text field
+                                                              NSString *password = weakSelf.alertController.textFields[1].text;  // Password text field
+                                                              username = [username stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
+                                                              VPNAccount *account = [[VPNAccount alloc] init];
+                                                              account.userName = username;
+                                                              account.passWord = password;
+                                                              
+                                                              [[AAAManager sharedInstance] continueVPNThreadWithVDIAccount:account];
+                                                          }];
+    
+    [self.alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = NSLocalizedString(@"Username", nil);
+    }];
+    [self.alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = NSLocalizedString(@"Password", nil);
+    }];
+    [self.alertController addAction:confirmAction];
+    [self.alertController addAction:cancelAction];
+    
+    [self presentViewController:self.alertController animated:YES completion:nil];
+}
+
+- (void)finishLogin:(BOOL)success {
+    self.alertController = nil;
+    
+    __weak typeof(self) weakSelf = self;
+    [self dismissViewControllerAnimated:YES completion:^{
+        [weakSelf.delegate didFinishLogin:success];
+    }];
+}
+
+#pragma mark - Passwords
+- (void)savePasswordsOfAccount:(VPNAccount *)account {
+    Gateway *gateway = [self currentGateway];
+    if (![account.userName isEqualToString:gateway.username]){
+        
+        gateway.username = account.userName;
+        [[[GatewayManager alloc] init] updateGateway:gateway];
+    }
+    
+    if (account.userName){
+        
+        [self saveMethodName];
+        [self savePassWord:account];
+        return;
+    }
+    
+    if (gateway.username) {  // Only remember password when username is configured.
+        
+        [self savePassWord:account];
+    } else {
+        ANDebug(@"Password will be deleted, because the login user is different from the one in settings.");
+        
+        [self deleteMethodName];
+        [account deleteAllPasswords];
+    }
+}
+
+-(void) savePassWord: (VPNAccount *) account
+{
+    NSMutableArray *passwords = [[NSMutableArray alloc] init];
+    if (account.passWord) {
+        [passwords addObject:[account.passWord copy]];
+    }
+    
+    Gateway *gateway = [self currentGateway];
+
+    if (![self isRadiusSavePass:account.loginMethod]){
+        
+        gateway.isRadiusPWD = NO;
+        if (account.passWord2) {
+            [passwords addObject:[account.passWord2 copy]];
+        }
+        if (account.passWord3) {
+            [passwords addObject:[account.passWord3 copy]];
+        }
+    }else{
+        
+        gateway.isRadiusPWD = YES;
+    }
+    
+    [PasswordManager savePasswords:passwords forHost:account.vsHost username:account.userName port:account.vsPort];
+}
+
+-(BOOL) isRadiusSavePass: (NSString *) methodName
+{
+    if (self.allMethodDescs.count < 1 || ISNULLSTR(methodName)){
+        
+        return NO;
+    }
+    
+    NSInteger acount = [self.allMethodNames indexOfObject:methodName];
+    
+    if (acount < 0){
+        
+        return NO;
+    }
+    
+    NSString *methodDesc = [_allMethodDescs objectAtIndex:acount];
+    if ([methodDesc rangeOfString:RADIUS_SAVE_PWD].location != NSNotFound){
+        
+        ANInfo(@"LoginView-isRadiusSavePass- did not save pwd");
+        return YES;
+    }
+    
+    return NO;
+}
+
+-(void) saveMethodName
+{
+    NSString *methodName = self.currentMethod ?: (_methodMenu.titleLabel.text ?: @"");
+    NSString *userName = _usernameTextField.text ?: @"";
+    if ([methodName isEqualToString:@""]){
+        
+        methodName = @"ldb";
+    }
+    
+    NSString *methodType = [Singleton sharedSingleton].isSupportAuth ? @"0" : @"1";
+    NSDictionary *verifyDic = @{@"methodName" : methodName, @"userName" : userName, @"methodType" : methodType};
+    [Singleton setCurrentGatewayMethod:verifyDic andKey:self.gateWay];
+}
+
+-(void) getCurrentMethod
+{
+    auth_type_t type = self.currentMethodType;
+    if (type == AUTH_LOCALDB || type == AUTH_LDAP || type == AUTH_RADIUS || type == AUTH_RADIUS_ACCOUNT ||
+        type == AUTH_DEVID || type == AUTH_HTTP || type == AUTH_CERTIFICATE){
+        
+        [Singleton sharedSingleton].isSupportAuth = YES;
+    }else{
+        
+        [Singleton sharedSingleton].isSupportAuth = NO;
+    }
+    
+    if (type == AUTH_CERTIFICATE){
+        
+        _usernameTextField.text = @"";
+    }
+}
+
+-(void) deleteMethodName
+{
+    [Singleton setCurrentGatewayMethod:@{} andKey:self.gateWay];
+}
+
+- (void)removePasswordsOfAccount:(VPNAccount *)account {
+    [PasswordManager removePasswordsOfHost:account.vsHost username:account.userName port:account.vsPort];
+}
+
+#pragma mark - UITextFieldDelegate
+- (BOOL)textFieldShouldReturn:(UITextField *)textField {
+    if (textField == self.usernameTextField) {
+        [self.usernameTextField resignFirstResponder];
+        if (_currentTableCells.count > 1) {
+            [self.password1TextField becomeFirstResponder];
+        }
+    }
+    
+    return YES;
+}
+
+#pragma mark - ANViewControllerSwitchProtocol
+- (void)switchFromSender:(id)sender withOption:(NSDictionary *)option {
+    if (sender) {
+        self.delegate = sender;
+    }
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/RegisterViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/RegisterViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/RegisterViewController.h	(working copy)
@@ -0,0 +1,13 @@
+//
+//  RegisterViewController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/18.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface RegisterViewController : UIViewController
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/RegisterViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/RegisterViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/RegisterViewController.m	(working copy)
@@ -0,0 +1,214 @@
+//
+//  RegisterViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/18.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "ANLogger.h"
+#import "AAAManager.h"
+#import "ANPopupDialog.h"
+#import "GatewayManager.h"
+#import "InformationToSave.h"
+#import "PasswordManager.h"
+#import "UIDevice+Hardware.h"
+#import "UIViewController+Activity.h"
+#import "UIViewController+HideKeyboard.h"
+#import "RegisterViewController.h"
+
+#define DUMMY_PASSWORD      @"##&&**"
+
+#define TOTAL_SECTIONS      1
+#define TOTAL_ROWS          3
+
+static NSInteger kTextFieldTag = 1;
+
+static NSString * const kUsernameCellID = @"RegisterUsernameCell";
+static NSString * const kPasswordCellID = @"RegisterPasswordCell";
+static NSString * const kDeviceNameCellID = @"RegisterDeviceNameCell";
+
+typedef NS_ENUM(NSInteger, RegisterTableIndex) {
+    kRegisterTableUsername = 0,
+    kRegisterTablePassword,
+    kRegisterTableDeviceName,
+};
+
+@interface RegisterViewController () <UITableViewDataSource, UITableViewDelegate> {
+    UITextField *_usernameTextField;
+    UITextField *_passwordTextField;
+    UITextField *_deviceNameTextField;
+    NSString *_realPassword;
+}
+
+@property (weak, nonatomic) IBOutlet UITableView *tableView;
+@property (weak, nonatomic) IBOutlet UIButton *registerButton;
+
+@end
+
+@implementation RegisterViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    [self enableHideKeyboard];
+    [self initButtonAppearance];
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (void)initButtonAppearance {
+    self.registerButton.layer.cornerRadius = 2.5;
+    self.registerButton.layer.shadowOffset = CGSizeMake(5.0, 5.0);
+    self.registerButton.layer.shadowColor = MAIN_COLOR.CGColor;
+    self.registerButton.layer.shadowOpacity = 0.25;
+}
+
+- (IBAction)registerButtonClicked:(id)sender {
+    [self login];
+}
+
+- (IBAction)cancelButtonClicked:(id)sender {
+    [self showLoginActivity:NO];
+    [[AAAManager sharedInstance] cancelLoginTapped];
+}
+
+- (UITextField *)textFieldWithCell:(UITableViewCell *)cell {
+    return (UITextField *)[cell viewWithTag:kTextFieldTag];
+}
+
+- (void)login {
+    ANDebug(@"Start to register...");
+
+    [self.view endEditing:YES];
+    
+    VPNAccount *account = [self inputAccount];
+    if (account == nil) {
+        ANWarn(@"Cannot get account information on register.");
+        return;
+    }
+    
+    ANInfo(@"VPN account on register: %@", account);
+
+    InformationToSave *infor =  [InformationToSave sharedInstance];
+    infor.lastLoginAccount = account;
+    [infor save];
+    
+    AAAManager *manager = [AAAManager sharedInstance];
+    manager.errorCode = ERR_SUCCESS;
+    [manager continueVPNThreadWithAccount:account];
+    
+    [self showLoginActivity:YES];
+}
+
+- (VPNAccount *)inputAccount {
+    VPNAccount *account = [AAAManager sharedInstance].account;
+    
+    NSString *username = [_usernameTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+    NSString *password = [_passwordTextField.text isEqualToString:DUMMY_PASSWORD] ? _realPassword : _passwordTextField.text;
+
+    NSString *devName = [_deviceNameTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+    if (devName == nil || devName.length == 0) {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@""
+                                                                      message:NSLocalizedString(@"Device name couldn`t be empty", nil)];
+        
+        [self presentViewController:dialog animated:YES completion:nil];
+        
+        return nil;
+    }
+    
+    UIDevice *devInfo = [UIDevice currentDevice];
+    NSString *longDevName = [NSString stringWithFormat:@"%@|Apple;%@;iOS %@", _deviceNameTextField.text,devInfo.platformString,devInfo.systemVersion];
+    
+    account.deviceName = longDevName;
+    if (account.deviceName.length > 64) {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                      message:NSLocalizedString(@"The valid length of device's name is 1-64!", nil)];
+        
+        [self presentViewController:dialog animated:YES completion:nil];
+        
+        return nil;
+    }
+    
+    account.userName = username;
+    account.passWord = password;
+    
+    return account;
+}
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return TOTAL_SECTIONS;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return TOTAL_ROWS;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    NSString *cellID = nil;
+    UITableViewCell *cell = nil;
+    NSInteger row = indexPath.row;
+    VPNAccount *account = [AAAManager sharedInstance].account;
+    
+    switch (row) {
+        case kRegisterTableUsername:{
+            cellID = kUsernameCellID;
+            cell = [self.tableView dequeueReusableCellWithIdentifier:cellID];
+            _usernameTextField = [self textFieldWithCell:cell];
+            _usernameTextField.text = account.userName;
+            break;
+        }
+        case kRegisterTablePassword: {
+            cellID = kPasswordCellID;
+            cell = [self.tableView dequeueReusableCellWithIdentifier:cellID];
+            
+            _passwordTextField = [self textFieldWithCell:cell];
+            
+            // Auto fill the first password field.
+            _realPassword = [AAAManager sharedInstance].account.passWord;
+            
+            if (!_realPassword || _realPassword.length == 0) {
+                Gateway *gateway = [[GatewayManager sharedInstance] gatewayOfUrl:account.vsURL andport:account.vsPort];
+                NSString *username = gateway.username;
+                if (username) {
+                    _realPassword = [PasswordManager passwordsOfHost:account.vsHost username:username port:account.vsPort][0];
+                } else {
+                    _realPassword = @"";
+                }
+            }
+
+            if (_realPassword && _realPassword.length > 0) {
+                _passwordTextField.text = DUMMY_PASSWORD;
+            }
+            break;
+        }
+        case kRegisterTableDeviceName: {
+            cellID = kDeviceNameCellID;
+            cell = [self.tableView dequeueReusableCellWithIdentifier:cellID];
+            _deviceNameTextField = [self textFieldWithCell:cell];
+            _deviceNameTextField.text = [UIDevice currentDevice].name;  // Set system device name as default.
+            break;
+        }
+        default:
+            ANError(@"Invalid cell row of (%zi) received.", row);
+            return [[UITableViewCell alloc] init];  // Prevent from crash.
+    }
+    
+    return cell;
+}
+
+#pragma mark - UITableViewDelegate
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    return 15.0;
+}
+
+-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/RemoteDesktopSettingsViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/RemoteDesktopSettingsViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/RemoteDesktopSettingsViewController.h	(working copy)
@@ -0,0 +1,13 @@
+//
+//  RemoteDesktopSettingsViewController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/9/6.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface RemoteDesktopSettingsViewController : UITableViewController
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/RemoteDesktopSettingsViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/RemoteDesktopSettingsViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/RemoteDesktopSettingsViewController.m	(working copy)
@@ -0,0 +1,182 @@
+//
+//  RemoteDesktopSettingsViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/9/6.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "ActionSheetPicker.h"
+#import "RemoteDesktopSettingsViewController.h"
+
+#define TOTAL_SECTIONS      2
+#define TOTAL_ROWS          1
+
+#define AUDIO_MODE_MIN      0
+#define AUDIO_MODE_MAX      3
+#define VENDOR_MIN          0
+#define VENDOR_MAX          2
+
+typedef NS_ENUM(NSInteger, RDSettingSectionIndex) {
+    kRDSettingSectionIndexAudioMode,
+    kRDSettingSectionIndexVendor
+};
+
+static NSInteger const kRDSettingsRowIndex = 0;
+
+static NSString * const DESKTOP_AUDIO_KEY = @"desktop_audio_mode";
+static NSString * const DESKTOP_CLIENT_VENDOR = @"desktop_client_vendor";
+
+@interface RemoteDesktopSettingsViewController ()
+
+@property (weak, nonatomic) IBOutlet UILabel *audioModeLabel;
+@property (weak, nonatomic) IBOutlet UILabel *vendorLabel;
+@property (weak, nonatomic) IBOutlet UITableViewCell *audioModelCell;
+@property (weak, nonatomic) IBOutlet UITableViewCell *vendorCell;
+
+@property (nonatomic) NSInteger audioMode;
+@property (nonatomic) NSInteger vendorIndex;
+
+@end
+
+@implementation RemoteDesktopSettingsViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+
+    [self configAudioModeLabel];
+    [self configVenderLabel];
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+}
+
+- (NSInteger)audioMode {
+    NSInteger mode = [[NSUserDefaults standardUserDefaults] integerForKey:DESKTOP_AUDIO_KEY];
+    if (mode >= AUDIO_MODE_MAX || mode < AUDIO_MODE_MIN) {
+        mode = AUDIO_MODE_MIN;
+        [[NSUserDefaults standardUserDefaults] setInteger:mode forKey:DESKTOP_AUDIO_KEY];
+    }
+    
+    return mode;
+}
+
+- (void)setAudioMode:(NSInteger)audioMode {
+    if (audioMode >= AUDIO_MODE_MAX || audioMode < AUDIO_MODE_MIN) {
+        return;
+    }
+    
+    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
+    [userDefaults setInteger:audioMode forKey:DESKTOP_AUDIO_KEY];
+    [userDefaults synchronize];
+}
+
+- (NSInteger)vendorIndex {
+    NSInteger mode = [[NSUserDefaults standardUserDefaults] integerForKey:DESKTOP_CLIENT_VENDOR];
+    if (mode >= VENDOR_MAX || mode < VENDOR_MIN) {
+        mode = VENDOR_MIN;
+        [[NSUserDefaults standardUserDefaults] setInteger:mode forKey:DESKTOP_CLIENT_VENDOR];
+    }
+    
+    return mode;
+}
+
+- (void)setVendorIndex:(NSInteger)vendorIndex {
+    if (vendorIndex >= VENDOR_MAX || vendorIndex < VENDOR_MIN) {
+        return;
+    }
+    
+    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
+    [userDefaults setInteger:vendorIndex forKey:DESKTOP_CLIENT_VENDOR];
+    [userDefaults synchronize];
+}
+
+- (NSString *)audioModeString {
+    return @[NSLocalizedString(@"Local", nil), NSLocalizedString(@"Remote", nil), NSLocalizedString(@"Mute", nil)][self.audioMode];
+}
+
+- (NSString *)venderString {
+    return @[@"MS RDP", @"JP-RDP"][self.vendorIndex];
+}
+
+- (void)configAudioModeLabel {
+    self.audioModeLabel.text = [self audioModeString];
+}
+
+- (void)configVenderLabel {
+    self.vendorLabel.text = [self venderString];
+}
+
+- (void)showAllAudioModes {
+    NSString *local = NSLocalizedString(@"Play sounds on the local device", nil);
+    NSString *remote = NSLocalizedString(@"Play sounds on the remote computer", nil);
+    NSString *mute = NSLocalizedString(@"Do not play sounds", nil);
+    
+    __weak typeof(self) weakSelf = self;
+    [ActionSheetStringPicker showPickerWithTitle:nil
+                                            rows:@[local, remote, mute]
+                                initialSelection:0
+                                       doneBlock:^(ActionSheetStringPicker *picker, NSInteger selectedIndex, id selectedValue) {
+                                           weakSelf.audioMode = selectedIndex;
+                                           [weakSelf configAudioModeLabel];
+                                       }
+                                     cancelBlock:^(ActionSheetStringPicker *picker) {
+                                         
+                                     }
+                                          origin:self.audioModelCell];
+}
+
+- (void)showAllVenders {
+    NSString *vendorMSRDP = NSLocalizedString(@"MS RDP", nil);
+    NSString *vendorNEC = NSLocalizedString(@"JP-RDP", nil);
+    
+    __weak typeof(self) weakSelf = self;
+    [ActionSheetStringPicker showPickerWithTitle:nil
+                                            rows:@[vendorMSRDP, vendorNEC]
+                                initialSelection:0
+                                       doneBlock:^(ActionSheetStringPicker *picker, NSInteger selectedIndex, id selectedValue) {
+                                           weakSelf.vendorIndex = selectedIndex;
+                                           [weakSelf configVenderLabel];
+                                       }
+                                     cancelBlock:^(ActionSheetStringPicker *picker) {
+                                         
+                                     }
+                                          origin:self.vendorCell];
+}
+
+#pragma mark - Table view data source
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return TOTAL_SECTIONS;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return TOTAL_ROWS;
+}
+
+#pragma mark - UITableViewDelegate
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    return 15;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
+    
+    NSInteger section = indexPath.section;
+    NSInteger row = indexPath.row;
+    
+    if (row == kRDSettingsRowIndex) {
+        if (section == kRDSettingSectionIndexAudioMode) {
+            [self showAllAudioModes];
+        } else if (section == kRDSettingSectionIndexVendor) {
+            [self showAllVenders];
+        }
+    }
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ResourcesViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ResourcesViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ResourcesViewController.h	(working copy)
@@ -0,0 +1,13 @@
+//
+//  ResourcesViewController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/27.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface ResourcesViewController : UIViewController
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ResourcesViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ResourcesViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ResourcesViewController.m	(working copy)
@@ -0,0 +1,1306 @@
+//
+//  ResourcesViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/27.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "ANLogger.h"
+#import "AAAManager.h"
+#import "AppManager.h"
+#import "GCustomItem.h"
+#import "PubAppItem.h"
+#import "FBKVOController.h"
+#import "ArrayVPNWrapper.h"
+#import "ANPopupDialog.h"
+#import "GatewayManager.h"
+#import "CertificateManager.h"
+#import "ConfigurationManager.h"
+#import "RulesManager.h"
+#import "ResourceCell.h"
+#import "MJRefresh.h"
+#import "NativeAppCell.h"
+#import "AutoLoginHandler.h"
+#import "SubResourceViewController.h"
+#import "UIView+Toast.h"
+#import "ResourcesViewController.h"
+#import "AccessModeCell.h"
+#import "AccessModeSelectViewController.h"
+#import "ZTWKWebViewController.h"
+
+static NSString * const kSegueToSubResource = @"ResourceToSubResource";
+static NSString * const kSegueToCustomDesktop = @"ResourceToCustomDesktop";
+static NSString * const kSegueToAccessModeSelect = @"ResourceToAccessModeSelect";
+
+NSString * const kAppGroupNameResource = @"group.net.arraynetworks.MotionProPlus";
+NSString * const kArrayVPNTunelErrorMsgResource = @"net.arraynetworks.sslvpn.errormsg";
+
+typedef NS_ENUM(NSInteger, ResourceSectionNumber) {
+    kResourceSectionZero = 0,
+    kResourceSectionOne,
+    kResourceSectionTwo,
+    kResourceSectionThree
+};
+
+typedef NS_ENUM(NSInteger, ResourceSectionIndex) {
+    kResourceSectionIndex0 = 0,
+    kResourceSectionIndex1,
+    kResourceSectionIndex2
+};
+
+@interface ResourcesViewController () <TimerRuleDelegate, AcsModeSelectControllerDelegate> {
+    NSInteger _longPressedIndex;
+}
+
+@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator;
+@property (weak, nonatomic) IBOutlet UILabel *statusLabel;
+@property (weak, nonatomic) IBOutlet UISwitch *vpnEnableSwitch;
+@property (weak, nonatomic) IBOutlet UIImageView *statusImageView;
+
+@property (weak, nonatomic) IBOutlet UIView *messageView;
+@property (weak, nonatomic) IBOutlet UILabel *messageLabel;
+
+@property (weak, nonatomic) IBOutlet UIView *emptyResourceView;
+@property (weak, nonatomic) IBOutlet UIImageView *emptyResourceImageView;
+@property (weak, nonatomic) IBOutlet UILabel *emptyResourceLabel;
+
+@property (weak, nonatomic) IBOutlet UITableView *resourceTableView;
+
+@property (weak, nonatomic) IBOutlet UITableView *acsModeTableView;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *resourceViewTopConstraint;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *emptyViewTopConstraint;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *messageViewTopConstraint;
+
+@property (strong, nonatomic) AppManager *model;
+@property (strong, nonatomic) NSArray *desktops;  // As a cache
+
+@property (strong, nonatomic) NSArray *acsDescList;
+@property (strong, nonatomic) NSArray *acsNameList;
+@property (strong, nonatomic) NSString *acsSelectedInfo;
+
+
+@property (strong, nonatomic) id browser;
+
+// For DesktopDirect
+@property (nonatomic, strong) NSIndexPath *currentIndex;
+@property (nonatomic, strong) ResourceItem *currentItem;
+@property (nonatomic, strong) FBKVOController *kvoController;
+@property (nonatomic, strong) UIControl *darkView;
+@property (nonatomic) BOOL silence;
+@property (nonatomic) BOOL needReconnect;
+
+@end
+
+@implementation ResourcesViewController
+
+@synthesize desktops = _desktops;
+
+- (void)dealloc {
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:kArrayVPNTunelErrorMsgResource object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    self.model = [AppManager sharedInstance];
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(handleVPNStatus:)
+                                                 name:kArrayVPNStatusNotification
+                                               object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(handleAutoLogout:)
+                                                 name:kAutoLogoutNotification
+                                               object:nil];
+    
+    [self setVPNStatusAsDisconnected];
+    [self autoStartVPN];
+    [self doPostLoginCV];
+    
+    [self initKVOController];
+    
+    [self initTopView];
+    [self initAccessModeView];
+    [self initPullToRefresh];
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [super viewWillDisappear:animated];
+    
+    self.silence = YES;
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    
+    self.silence = NO;
+}
+
+- (void)viewDidAppear:(BOOL)animated {
+    [super viewDidAppear:animated];
+    
+    RulesManager *manager = [RulesManager sharedInstance];
+    if (manager.didEndSession) {
+        manager.didEndSession = NO;
+        
+        [self logoutSilently];
+    }
+}
+
+- (void)initAccessModeView {
+    BOOL bShowAcsModeView = NO;
+    
+    self.acsSelectedInfo = nil;
+    self.acsDescList = [AAAManager sharedInstance].acsModeDesc;
+    self.acsNameList = [AAAManager sharedInstance].acsModeName;
+    if (self.acsDescList != nil) {
+        bShowAcsModeView = YES;
+    }
+    
+    if (bShowAcsModeView) {
+        self.acsModeTableView.hidden = NO;
+        self.resourceViewTopConstraint.constant = 95;
+        self.emptyViewTopConstraint.constant = 100;
+        self.messageViewTopConstraint.constant = 100;
+        self.acsModeTableView.tableHeaderView = [[UIView alloc]initWithFrame:CGRectMake(0,0,0,0.01)];
+    } else {
+        self.acsModeTableView.hidden = YES;
+        self.resourceViewTopConstraint.constant = 45;
+        self.emptyViewTopConstraint.constant = 50;
+        self.messageViewTopConstraint.constant = 50;
+    }
+    
+    self.needReconnect = NO;
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (IBAction)exitButtonClicked:(id)sender {
+    __weak typeof(self) weakSelf = self;
+    PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+                                                                   message:NSLocalizedString(@"Would you like to sign out?", nil)
+                                                             confirmAction:^{
+                                                                 [weakSelf stopVPNAndLogout:NO];
+                                                             }
+                                                              cancelAction:nil];
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (IBAction)vpnEnableSwitched:(id)sender {
+    if (self.vpnEnableSwitch.on) {
+        BOOL ret = [self startVPN:NO];
+        if (!ret) {
+            [self setVPNStatusAsError:NSLocalizedString(@"Can't start VPN.", nil)];
+        }
+    } else {
+        [self stopVPN];
+    }
+}
+
+- (void)initTopView {
+    [self.acsModeTableView registerNib:[UINib nibWithNibName:@"AccessModeCell" bundle:nil] forCellReuseIdentifier:kAccessModeCellID];
+    if (self.model.isEmpty) {
+        [self showEmptyResouceView];
+    } else {
+        [self showResourceTableView];
+        [self.resourceTableView registerNib:[UINib nibWithNibName:@"ResourceCell" bundle:nil] forCellReuseIdentifier:kResourceCellID];
+        [self.resourceTableView registerNib:[UINib nibWithNibName:@"NativeAppCell" bundle:nil] forCellReuseIdentifier:kNativeAppCellID];
+    }
+}
+
+- (void)initPullToRefresh {
+    __weak typeof(self) weakSelf = self;
+    self.resourceTableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
+        __strong typeof(weakSelf) strongSelf = weakSelf;
+        [strongSelf endRefresh];
+        
+        Gateway *currentGateway = [self getCurrentGateway];
+        if (currentGateway) {
+            [[AppManager sharedInstance] fetchAppsFromServer:currentGateway.host
+                                                        port:currentGateway.port
+                                                  completion:^(BOOL isNeedUpdate) {
+                                                      [strongSelf.resourceTableView reloadData];
+                                                  }];
+        }
+    }];
+}
+
+- (void)endRefresh{
+    [self.resourceTableView.mj_header endRefreshing];
+}
+
+- (void)doPostLoginCV {
+    [[RulesManager sharedInstance] setDelegate:self];
+    
+    /**
+     * It may not be a reliable way to do post login Client Verification.
+     * Maybe we should listen to the VPN_CB_CV_USER message.
+     */
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{
+        RulesManager *manager = [RulesManager sharedInstance];
+        [manager cleanTimerRuleInteraction];
+        [manager kickoffTimerRules];
+    });
+    
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{
+        [[RulesManager sharedInstance].interactionHandler takeAction];
+    });
+}
+
+- (void)initKVOController {
+    self.kvoController = [FBKVOController controllerWithObserver:self];
+}
+
+#pragma mark - Access Mode
+
+- (NSArray *)cellsForTableView:(UITableView *)tableView
+{
+    NSInteger sections = tableView.numberOfSections;
+    NSMutableArray *cells = [[NSMutableArray alloc]  init];
+    for (int section = 0; section < sections; section++) {
+        NSInteger rows =  [tableView numberOfRowsInSection:section];
+        for (int row = 0; row < rows; row++) {
+            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
+            [cells addObject:[tableView cellForRowAtIndexPath:indexPath]];
+        }
+    }
+    return cells;
+}
+
+- (int)switchAccessMode:(NSString *)acsDesc {
+    int ret = ERROR_ACM_SUCCESS;
+    BOOL isMatchDesc = NO;
+    
+    if ([self.acsDescList count] == [self.acsNameList count]) {
+        for (NSUInteger i =0; i < [self.acsDescList count]; i++) {
+            if ([[self.acsDescList objectAtIndex:i] isEqualToString:acsDesc]) {
+                isMatchDesc = YES;
+                ret = array_vpn_access_mode_set([[self.acsNameList objectAtIndex:i] UTF8String], NULL, NULL, 0);
+                break;
+            }
+        }
+    }
+    
+    if (!isMatchDesc) {
+        ANError(@"switchAccessMode: get match access mode message failed, switch failed return error.");
+        ret = ERROR_ACM_UNDEFINE;
+    }
+    
+    return ret;
+}
+
+- (void)accessModeRestartVPN{
+    BOOL ret = [self startVPN:NO];
+    if (!ret) {
+        [self setVPNStatusAsError:NSLocalizedString(@"Can't start VPN.", nil)];
+    }
+    
+    NSArray *cells = [self cellsForTableView:self.acsModeTableView];
+    if ([cells count] == 1) {
+        AccessModeCell *cell = (AccessModeCell *)[cells objectAtIndex:0];
+        [cell showActiveView:NO];
+        [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+    }
+}
+
+- (void)didFinishSelect:(NSString *)selectAcsDesc {
+    NSArray *cells = [self cellsForTableView:self.acsModeTableView];
+    if ([cells count] == 1) {
+        AccessModeCell *cell = (AccessModeCell *)[cells objectAtIndex:0];
+        NSString *currentAcsDesc = [cell getCellText];
+        if ([selectAcsDesc length] > 0) {
+            if ([currentAcsDesc isEqualToString:selectAcsDesc]) {
+                ANInfo(@"didFinishSelect: user select same access mode ,do nothing.");
+            } else {
+                ANInfo(@"didFinishSelect: user select access mode[%@]", selectAcsDesc);
+                [cell setCellText:selectAcsDesc];
+                [cell showActiveView:YES];
+                [cell setCellImage:ACCESS_MODE_IMAGE_INACTIVE_NAME];
+                dispatch_async(dispatch_get_main_queue(), ^{
+                    int ret = [self switchAccessMode:selectAcsDesc];
+                    NSString *errorMessage = nil;
+                    switch (ret) {
+                        case ERROR_ACM_SUCCESS:
+                            ANInfo(@"didFinishSelect:switch access mode successfully.");
+                            [cell showActiveView:NO];
+                            [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+                            break;
+                        case ERROR_ACM_SUCCESS_RECONN:
+                            ANInfo(@"didFinishSelect:switch access mode successfully.");
+                            ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+                            if (tunnelStatus == ArrayVPNConnected) {
+                                ANInfo(@"didFinishSelect:vpn status is connected, need reconnect.");
+                                self.needReconnect = YES;
+                                [self stopVPN];
+                            } else {
+                                [cell showActiveView:NO];
+                                [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+                            }
+                            break;
+                        case ERROR_ACM_WITHOUT_SESSION:
+                            errorMessage = NSLocalizedString(@"Switching failure: invalid user session. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_NAME_INVALID:
+                            errorMessage = NSLocalizedString(@"Switching failure: illegal mode information. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_NAME_NONE:
+                            errorMessage = NSLocalizedString(@"Switching failure: mode information does not exist. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_INVALID_PARAMETER:
+                            errorMessage = NSLocalizedString(@"Switching failure: incorrect parameter. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_ACL_CHANGE_FAILED:
+                            errorMessage = NSLocalizedString(@"Switching failure: the server fails to switch. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_NETWORK:
+                            errorMessage = NSLocalizedString(@"Switching failure: network error. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_UNDEFINE:
+                            errorMessage = NSLocalizedString(@"Switching failure: unknown error. Please switch again or contact the administrator.", nil);
+                            break;
+                        default:
+                            errorMessage = NSLocalizedString(@"Switching failure: unknown error. Please switch again or contact the administrator.", nil);
+                            break;
+                    }
+                    if (errorMessage && errorMessage.length > 0) {
+                        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error",nil) message:errorMessage];
+                        [self presentViewController:dialog animated:YES completion:nil];
+                        [cell showActiveView:NO];
+                        [cell setCellText:currentAcsDesc];
+                        [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+                    } else {
+                        for (NSString *info in self.acsDescList) {
+                            if ([selectAcsDesc isEqualToString:info]) {
+                                self.acsSelectedInfo = info;
+                            }
+                        }
+                    }
+                    ANInfo(@"didFinishSelect:switch access mode finished, select access mode=%@.", self.acsSelectedInfo);
+                });
+            }
+        }
+    }
+}
+
+#pragma mark - Auto Logout
+- (void)handleAutoLogout:(NSNotification *)notification {
+    [self logoutSilently];
+}
+
+- (void)clearCookies {  // ANsession should be cleared on logout. (for WebAuth)
+#define MP_SESSION_PREFIX   @"ANsession"
+#define MP_USERNAME_COOKIE  @"username"
+#define MP_ACCESS_NAME      @"acs_mode"
+#define MP_ACCESS_DESC      @"acs_desc"
+    
+    NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
+    NSArray *cookies = cookieJar.cookies;
+    for (NSHTTPCookie *cookie in cookies) {
+        if (cookie.name) {
+            if ([cookie.name isEqualToString:MP_USERNAME_COOKIE] ||[cookie.name containsString:MP_SESSION_PREFIX] || [cookie.name containsString:MP_ACCESS_NAME] || [cookie.name containsString:MP_ACCESS_DESC]) {
+                [cookieJar deleteCookie:cookie];
+            }
+        }
+    }
+}
+
+#pragma mark - VPN Status
+#define STATUS_LABEL_COLOR_NORMAL   UIColorFromRGBA(0x666666, 1.0)
+#define STATUS_LABEL_COLOR_WARNING  UIColorFromRGBA(0xff0000, 1.0)
+#define STATUS_LABEL_COLOR_GREEN    UIColorFromRGBA(0x42a009, 1.0)
+
+- (void)setVPNStatusAsConnecting {
+    self.activityIndicator.hidden = NO;
+    [self.activityIndicator startAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_NORMAL;
+    self.statusLabel.text = NSLocalizedString(@"Connecting...", nil);
+    self.statusImageView.hidden = YES;
+    self.vpnEnableSwitch.on = YES;
+    [self showMessageViewWithInfo:nil];
+}
+
+- (void)setVPNSStatusAsConnected {
+    [self.activityIndicator stopAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_GREEN;
+    self.statusLabel.text = NSLocalizedString(@"Connected", nil);
+    self.statusImageView.image = [UIImage imageNamed:@"ResourceConnectSuccess"];
+    self.statusImageView.hidden = NO;
+    self.vpnEnableSwitch.on = YES;
+    [self showMessageViewWithInfo:nil];
+}
+
+- (void)setVPNStatusAsDisconnected {
+    [self.activityIndicator stopAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_NORMAL;
+    self.statusLabel.text = NSLocalizedString(@"Disconnected", nil);
+    self.statusImageView.image = [UIImage imageNamed:@"ResourceConnectError"];
+    self.statusImageView.hidden = NO;
+    self.vpnEnableSwitch.on = NO;
+    [self showMessageViewWithInfo:nil];
+    if (self.needReconnect) {
+        ANInfo(@"access mode disconnect vpn finished, now need restart vpn.");
+        self.needReconnect = NO;
+        [self accessModeRestartVPN];
+    }
+}
+
+- (void)setVPNStatusAsDisconnecting {
+    [self.activityIndicator startAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_NORMAL;
+    self.statusLabel.text = NSLocalizedString(@"Disconnecting...", nil);
+    self.statusImageView.hidden = YES;
+    self.vpnEnableSwitch.on = NO;
+    [self showMessageViewWithInfo:nil];
+}
+
+- (void)setVPNStatusAsError:(NSString *)errorMessage {
+    [self.activityIndicator stopAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_WARNING;
+    self.statusLabel.text = NSLocalizedString(@"Connect failed", nil);
+    self.statusImageView.image = [UIImage imageNamed:@"ResourceConnectError"];
+    self.statusImageView.hidden = NO;
+    self.vpnEnableSwitch.on = NO;
+    [self showMessageViewWithInfo:errorMessage];
+}
+
+- (void)showMessageViewWithInfo:(NSString *)info {
+    if (info) {
+        self.messageLabel.text = info;
+        self.messageView.hidden = NO;
+    } else {
+        self.messageLabel.text = @"";
+        self.messageView.hidden = YES;
+    }
+}
+
+- (void)showEmptyResouceView {
+    self.emptyResourceView.hidden = NO;
+    self.resourceTableView.hidden = YES;
+    [self.view bringSubviewToFront:self.emptyResourceView];
+}
+
+- (void)showResourceTableView {
+    self.emptyResourceView.hidden = YES;
+    self.resourceTableView.hidden = NO;
+    [self.view bringSubviewToFront:self.resourceTableView];
+}
+
+#pragma mark - VPN Related
+- (BOOL)autoStartVPN {
+    BOOL isAutoStart = NO;
+    Gateway *gateway = [self getCurrentGateway];
+    
+    if (!gateway) {
+        isAutoStart = YES;
+        ANInfo(@"No gateway is selected, it is auto start vpn.");
+    } else {
+        if (!gateway.isSecureTunnelEnabled) {
+            ANInfo(@"Auto start VPN is not enabled.");
+            return NO;
+        }
+    }
+
+    return [self startVPN:isAutoStart];
+}
+
+- (BOOL)startVPN:(BOOL)isAutoStart {
+    //Gateway *gateway = [self getCurrentGateway];
+    //NSString *session = [AAAManager sharedInstance].sessionID;
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    
+    //Reset connect fail reason.
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameResource];
+    [userDefaults removeObjectForKey:@"tunnel_result"];
+    [userDefaults removeObjectForKey:@"dns_list"];
+    
+    [vpnWrapper startSSLVPN];
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleVPNTunnelError:)
+                                                 name:kArrayVPNTunelErrorMsgResource object:nil];
+    
+    return YES;
+    
+//    if (isAutoStart) {
+//        [vpnWrapper startSSLVPN];
+//    }
+//
+//    return [vpnWrapper validateSessionWithHost:gateway.host
+//                                          port:gateway.port
+//                                       session:session
+//                                    completion:^(BOOL isSuccess, NSError *error) {
+//                                        if (isSuccess) {
+//                                            [vpnWrapper startSSLVPN];
+//                                        } else {
+//                                            NSString *message = NSLocalizedString(@"Session is invalid, please login again!", nil);
+//                                            PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+//                                                                                                          message:message
+//                                                                                                           action:^{
+//                                                                                                               [[NSNotificationCenter defaultCenter]
+//                                                                                                                postNotificationName:kAutoLogoutNotification
+//                                                                                                                object:nil];
+//                                                                                                           }];
+//                                            [self presentViewController:dialog animated:YES completion:nil];
+//                                        }
+//                                    }];
+}
+
+- (void)stopVPN {
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    [vpnWrapper stopSSLVPN];
+}
+
+- (void)stopVPNAndLogout:(BOOL)isSilent {
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{  // Stop timer rules fisrt.
+        [[RulesManager sharedInstance] stopAllRules];
+    });
+    
+    AAAManager *manager = [AAAManager sharedInstance];
+    [manager continueVPNThreadWithAccount:nil];
+    [self stopVPN];
+    
+    [self clearCookies];
+    
+    if (!isSilent) {
+        __weak typeof(self) weakSelf = self;
+        [self.view makeToastActivity:CSToastPositionCenter];
+//        dispatch_async(dispatch_get_global_queue(0, 0), ^{
+        dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), queue, ^{
+            NSInteger ret = [[AAAManager sharedInstance] stopL3VPNDirectly];
+            if (ret != ERR_SUCCESS) {
+                ANError(@"Logout failed with error code: %zi.", ret);
+            }
+            
+            __strong typeof(weakSelf) strongSelf = weakSelf;
+            dispatch_async(dispatch_get_main_queue(), ^{
+                [strongSelf.view hideToastActivity];
+                [strongSelf dismissViewControllerAnimated:YES completion:nil];
+            });
+        });
+    }
+}
+
+- (void)logoutSilently {
+    [self stopVPNAndLogout:YES];
+    
+    [self.navigationController dismissViewControllerAnimated:NO completion:nil];  // Dismiss modal view if exists.
+    [self dismissViewControllerAnimated:YES completion:nil];
+}
+
+- (Gateway *)getCurrentGateway {
+    VPNAccount *account = [AAAManager sharedInstance].account;
+    GatewayManager *gm = [GatewayManager sharedInstance];
+    NSString *url = account.vsURL;
+    NSString *port = account.vsPort;
+    NSInteger index = [gm indexOfUrl:url andport:port];
+    
+    return [gm gatewayAtIndex:index];
+}
+
+#pragma mark - VPN Status Handler
+- (void)handleVPNStatus:(NSNotification *)notification {
+    ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+    
+    ANDebug(@"Array VPN tunnel status = %zi", tunnelStatus);
+    
+    [self updateUIWithVPNStatus:tunnelStatus];
+}
+
+- (void)updateUIWithVPNStatus:(ArrayVPNStatus)status {
+    switch (status) {
+        case ArrayVPNInavlid:
+        case ArrayVPNDisconnected:
+            [self setVPNStatusAsDisconnected];
+            break;
+        case ArrayVPNDisconnecting:
+            [self setVPNStatusAsDisconnecting];
+            break;
+        case ArrayVPNConnecting:
+        case ArrayVPNReasserting:
+            [self setVPNStatusAsConnecting];
+            break;
+        case ArrayVPNConnected:
+            [self setVPNSStatusAsConnected];
+            break;
+            
+        default:
+            break;
+    }
+}
+
+- (void)handleVPNTunnelError:(NSNotification *)notification {
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    NSString *errMessage = [vpnWrapper getErrorMsgWithCode];
+    if (errMessage && errMessage.length > 0) {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:errMessage];
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+#pragma mark - Number of Sections & Rows
+- (BOOL)isWebAppToShow {
+    PortalTabsConfiguration *portalConfiguration = [ConfigurationManager sharedInstance].portalTabs;
+    
+    return portalConfiguration.isWebAppConfigured && self.model.webApps.children.count > 0;
+}
+
+- (BOOL)isNativeAppToShow {
+    PortalTabsConfiguration *portalConfiguration = [ConfigurationManager sharedInstance].portalTabs;
+    
+    return portalConfiguration.isNativeAppConfigured && self.model.nativeApps.children.count > 0;
+}
+
+- (BOOL)isDesktopToShow {
+    PortalTabsConfiguration *portalConfiguration = [ConfigurationManager sharedInstance].portalTabs;
+    
+    return portalConfiguration.isDesktopConfigured && self.model.desktopApps.resourceItems.count > 0;
+}
+
+- (NSInteger)totalSections {
+    NSInteger totalSections = 0;
+    NSInteger webSection = [self isWebAppToShow] ? 1 : 0;
+    NSInteger nativeSection = [self isNativeAppToShow] ? 1 : 0;
+    NSInteger desktopSection = [self isDesktopToShow] ? 1 : 0;
+    
+    totalSections = webSection + nativeSection + desktopSection;
+    
+    return totalSections;
+}
+
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([segue.identifier isEqualToString:kSegueToSubResource]) {
+        SubResourceViewController *viewController = segue.destinationViewController;
+        [viewController setupModel:(NSArray *)sender];
+    }
+    if ([segue.identifier isEqualToString:kSegueToAccessModeSelect]) {
+        NSArray *cells = [self cellsForTableView:self.acsModeTableView];
+        if ([cells count] == 1) {
+            UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
+            AccessModeSelectViewController *controller = (AccessModeSelectViewController *)navController.topViewController;
+            controller.selectedAcsModeString = self.acsSelectedInfo;
+            controller.delegate = self;
+        }
+    }
+}
+
+#pragma mark - Get Child at Index
+- (NSArray *)didSelectWebAppAtIndexPath:(NSIndexPath *)indexPath {
+    NSInteger row = indexPath.row;
+    
+    if (row >= self.model.webApps.children.count) {
+        ANError(@"Index (%zi) is out range of web apps count.", row);
+        return nil;
+    }
+    
+    WebApp *app = [self.model.webApps.children objectAtIndex:row];
+    if (app.type == APP_TYPE_WEBAPP) {
+        ZTWKWebViewController *control = [[ZTWKWebViewController alloc] init];
+        control.webUrl = [app.url absoluteString];
+        [self.navigationController pushViewController:control animated:YES];
+
+        
+        return nil;
+    }
+    
+    return app.children;
+}
+
+- (NSArray *)didSelectNativeAppAtIndexPath:(NSIndexPath *)indexPath {
+    NSInteger row = indexPath.row;
+    
+    if (row >= self.model.nativeApps.children.count) {
+        ANError(@"Index (%zi) is out range of native apps count.", row);
+        return nil;
+    }
+    
+    NativeApp *app = [self.model.nativeApps.children objectAtIndex:row];
+    NSURL *url = [NSURL URLWithString:app.scheme];
+    if (url.scheme == nil) {
+        url = [NSURL URLWithString:[NSString stringWithFormat:@"%@://", app.scheme]];
+    }
+    
+    ANInfo(@"open app url=%@", url);
+    if (![[UIApplication sharedApplication] canOpenURL:url]) {
+        BOOL isAppStoreApp = (app.installUrl != nil);
+        if (!isAppStoreApp) {
+            NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Application %@ has not been installed, Would you like to search it on App Store?", nil), app.name];
+            PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:@""
+                                                                           message:message
+                                                                     confirmAction:^{
+                                                                         NSString *string = [NSString stringWithFormat:APPSTORE_SEARCH_STRING,
+                                                                                             [app.name stringByAddingPercentEncodingWithAllowedCharacters:
+                                                                                              NSCharacterSet.URLQueryAllowedCharacterSet]];
+                                                                         OpenURL([NSURL URLWithString:string]);
+                                                                     }
+                                                                      cancelAction:nil];
+            
+            [self presentViewController:dialog animated:YES completion:nil];
+        } else {
+            ANError(@"appstore client don't support this case any more.");
+        }
+    }
+    
+    return nil;
+}
+
+- (NSArray *)didSelectDesktopAtIndexPath:(NSIndexPath *)indexPath {
+    NSInteger row = indexPath.row;
+    
+    if (row >= self.model.desktopApps.resourceItems.count) {
+        ANError(@"Index (%zi) is out range of desktop apps count.", row);
+        return nil;
+    }
+    
+    FolderItem *item = [self.desktops objectAtIndex:row];
+    if ([item isKindOfClass:[GCustomItem class]] && [item.name isEqualToString:NSLocalizedString(@"Other", nil)]) {
+        [self performSegueWithIdentifier:kSegueToCustomDesktop sender:self];
+        return nil;
+    } else if ([item isKindOfClass:[HostItem class]]) {
+        [self didSelectHostItem:(HostItem *)item atIndexPath:indexPath];
+        return nil;
+    }
+    
+    return [self getSortedArray:[item.resourceItems allValues]];
+}
+
+#pragma mark - DesktopDirect
+- (void)didSelectHostItem:(HostItem *)hostItem atIndexPath:(NSIndexPath *)indexPath {
+    if (self.currentIndex
+        && self.currentIndex.row == indexPath.row
+        && hostItem.status < ResourceStatusReady) {
+        return;
+    }
+    
+    self.currentIndex = indexPath;
+    self.currentItem = hostItem;
+    
+    ResourceCell *cell = (ResourceCell *)[self.resourceTableView cellForRowAtIndexPath:indexPath];
+    
+    __weak typeof(self) weakSelf = self;
+    [self.kvoController observe:hostItem
+                        keyPath:@"status"
+                        options:NSKeyValueObservingOptionNew
+                          block:^(ResourcesViewController *observer, HostItem *host, NSDictionary *change) {
+                              NSInteger hostStatus = host.status;
+        
+                        
+        
+                              dispatch_async(dispatch_get_main_queue(), ^{
+                                  [cell updateUI:host];
+                                  if (observer.currentIndex.row != indexPath.row) {
+                                      return;
+                                  }
+                                  
+                                  if (observer.silence) {
+                                      return;
+                                  }
+                                  if (host.status == ResourceStatusReady) {
+                                      [observer.kvoController unobserve:host];
+                                      NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
+                                      AppManager *appManager = [AppManager sharedInstance];
+                                      BOOL cliEnabledNEC = NO;
+                                      NSString *enabledNEC = appManager.desktopSettings.settings[@"jp-rdp"];
+                                      if (enabledNEC && [enabledNEC isEqualToString:@"1"])
+                                          cliEnabledNEC = YES;
+                                      if (cliEnabledNEC || [userDefaults integerForKey:@"desktop_client_vendor"] == 1) {
+                                          [observer openRDClientNEC:host];
+                                      } else {
+                                          [observer openRDClient:host];
+                                      }
+                                      // Reset power state
+                                      host.powerState = HostPowerStateDown;
+                                      return;
+                                  } else if (hostStatus >= ResourceStatusFailed && hostStatus < ResourceStatusResolveHostNameFailed) {
+                                      ANError(@"Cannot connect to remote host, error code: %zi", hostStatus);
+                                      
+                                      if (hostStatus == ResourceStatusPowerDown) {
+                                          NSString *message = NSLocalizedString(@"It seems the remote host is turned off. Would you like to try and wake it up?", nil);
+                                          
+                                          PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Cannot connect to remote host", nil)
+                                                                                                         message:message
+                                                                                                   confirmAction:^{
+                                                                                                       NSInteger row = weakSelf.currentIndex.row;
+                                                                                                       HostItem *host = weakSelf.desktops[row];
+                                                                                                       [host wakeUp];
+                                                                                                   }
+                                                                                                    cancelAction:nil];
+                                          
+                                          [weakSelf presentViewController:dialog animated:YES completion:nil];
+                                          
+                                          return;
+                                      } else {
+                                          [observer.kvoController unobserve:host];
+                                      }
+                                  }
+                              });
+                          }];
+    
+    
+    NSThread *thread = [[NSThread alloc] initWithTarget:hostItem selector:@selector(prepare) object:nil];
+    [thread start];
+    [hostItem prepare];
+}
+
+- (void)openRDClient:(HostItem *)hostItem {
+    NSURL *url = hostItem.url;
+    if (!url) {
+        return;
+    }
+    
+    if (![[UIApplication sharedApplication] canOpenURL:url]) {
+        NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Application %@ has not been installed, Would you like to search it on App Store?", nil), @"RD client"];
+        PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Cannot connect to remote host", nil)
+                                                                       message:message
+                                                                 confirmAction:^{
+                                                                     NSString *string = [NSString stringWithFormat:APPSTORE_SEARCH_STRING,
+                                                                                         [@"RD client" stringByAddingPercentEncodingWithAllowedCharacters:
+                                                                                          NSCharacterSet.URLQueryAllowedCharacterSet]];
+                                                                     
+                                                                     OpenURL([NSURL URLWithString:string]);
+                                                                 }
+                                                                  cancelAction:nil];
+        
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+- (void)openRDClientNEC:(HostItem *)hostItem {
+    NSURL *url = hostItem.urlVendorNEC;
+    if (!url) {
+        return;
+    }
+    
+    if (![[UIApplication sharedApplication] canOpenURL:url]) {
+        NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Application %@ has not been installed, Would you like to search it on App Store?", nil),@"RD"];
+        PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Cannot connect to remote host", nil)
+                                                                       message:message
+                                                                 confirmAction:^{
+                                                                     NSString *string = @"https://itunes.apple.com/jp/app/rd-v1.3/id771611106?mt=8";
+                                                                     OpenURL([NSURL URLWithString:string]);
+                                                                 }
+                                                                  cancelAction:nil];
+        
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+- (NSArray *)desktops {
+    if (!_desktops) {
+        _desktops = [self getSortedArray:[self.model.desktopApps.resourceItems allValues]];
+    }
+    
+    return _desktops;
+}
+
+- (NSArray *)getSortedArray:(NSArray *)array {
+    if (!array || array.count == 0) {
+        ANWarn(@"Empty array, should not be sorted.");
+        return nil;
+    }
+    
+    NSSortDescriptor *byClass = [NSSortDescriptor sortDescriptorWithKey:@"class" ascending:YES comparator:^NSComparisonResult(id obj1, id obj2) {
+        // Sort by class name
+        return [NSStringFromClass(obj1) compare:NSStringFromClass(obj2)];
+        
+    }];
+    
+    NSSortDescriptor *byName = [NSSortDescriptor sortDescriptorWithKey:@"name"
+                                                             ascending:YES
+                                                              selector:@selector(localizedStandardCompare:)];
+    
+    NSArray *sortDescriptors = [NSArray arrayWithObjects:byClass, byName, nil];
+    
+    return [array sortedArrayUsingDescriptors:sortDescriptors];
+}
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    if ([tableView isEqual:self.resourceTableView]) {
+        return [self totalSections];
+    } else if ([tableView isEqual:self.acsModeTableView]) {
+        return 1;
+    }
+    
+    return 0;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    if ([tableView isEqual:self.resourceTableView]) {
+        NSInteger totalSections = [self totalSections];
+        if (section > totalSections) {
+            ANError(@"Section (%zi) is larger than total sections (%zi).", section, totalSections);
+            
+            return 0;
+        }
+        
+        __weak typeof(self) weakSelf = self;
+        NSNumber *result = [self getCellInfoInSection:section
+                                         totalSection:totalSections
+                                               object:nil
+                                              action1:^id(id param) {
+                                                  __strong typeof(weakSelf) strongSelf = weakSelf;
+                                                  NSInteger rows = strongSelf.model.webApps.children.count;
+                                                  return [NSNumber numberWithInteger:rows];
+                                              }
+                                              action2:^id(id param) {
+                                                  __strong typeof(weakSelf) strongSelf = weakSelf;
+                                                  NSInteger rows = strongSelf.model.nativeApps.children.count;
+                                                  return [NSNumber numberWithInteger:rows];
+                                              }
+                                              action3:^id(id param) {
+                                                  __strong typeof(weakSelf) strongSelf = weakSelf;
+                                                  NSInteger rows = strongSelf.model.desktopApps.resourceItems.count;
+                                                  return [NSNumber numberWithInteger:rows];
+                                              }];
+        
+        return [result integerValue];
+    } else if ([tableView isEqual:self.acsModeTableView]) {
+        return 1;
+    }
+    
+    return 0;
+}
+
+- (UITableViewCell *)configureWebAppWithRow:(NSInteger)row {
+    ResourceCell *cell = [self.resourceTableView dequeueReusableCellWithIdentifier:kResourceCellID];
+    if (!cell) {
+        cell = [[ResourceCell alloc] init];
+    }
+    
+    WebApp *app = [self.model.webApps.children objectAtIndex:row];
+    UIImage *image = nil;
+    BOOL isFolder = app.type == APP_TYPE_FOLDER;
+    if (isFolder) {
+        image = [UIImage imageNamed:FOLDER_APP_IMAGE_NAME];
+    } else {
+        image = [UIImage imageNamed:WEB_APP_IMAGE_NAME];
+        UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self
+                                                                                                       action:@selector(cellLongPressed:)];
+        [cell addGestureRecognizer:longPressGesture];
+    }
+    [cell configureCellWithImage:image name:app.name isFolder:isFolder];
+    
+    return cell;
+}
+
+- (UITableViewCell *)configureNativeAppWithRow:(NSInteger)row {
+    NativeAppCell *cell = [self.resourceTableView dequeueReusableCellWithIdentifier:kNativeAppCellID];
+    if (!cell) {
+        cell = [[NativeAppCell alloc] init];
+    }
+    
+    NativeApp *app = [self.model.nativeApps.children objectAtIndex:row];
+    UIImage *image = nil;
+    if (app.customIcon) {
+        image = app.customIcon;
+    } else if (app.appIcon) {
+        image = app.appIcon;
+    } else {
+        image = [UIImage imageNamed:NATIVE_APP_IMAGE_NAME];
+    }
+    [cell configureCellWithImage:image name:app.name isFolder:NO];  // Native app doesn't support folder.
+    [cell setDescriptionContent:app.desc];
+    
+    return cell;
+}
+
+- (UITableViewCell *)configureDesktopAppWithRow:(NSInteger)row {
+    ResourceCell *cell = [self.resourceTableView dequeueReusableCellWithIdentifier:kResourceCellID];
+    if (!cell) {
+        cell = [[ResourceCell alloc] init];
+    }
+    
+    ResourceItem *item = [self.desktops objectAtIndex:row];
+    BOOL isFolder = [item isKindOfClass:[FolderItem class]];  // Only pub-app & self-defined desktop has folder.
+    BOOL isCustomDesktop = [item isKindOfClass:[GCustomItem class]];
+    if (isCustomDesktop) {
+        isFolder = YES;
+    }
+    UIImage *image = nil;
+    if (item.icon != nil) {
+        if ([item.description containsString:@"http.ico"]) {
+            image = [UIImage imageNamed:ZRT_HTTP_IMAGE_NAME];
+        } else if ([item.description containsString:@"HSValuate1.ico"]) {
+            image = [UIImage imageNamed:ZRT_HSVALUATE1_IMAGE_NAME];
+        } else if ([item.description containsString:@"HSValuate2.ico"]) {
+            image = [UIImage imageNamed:ZRT_HSVALUATE2_IMAGE_NAME];
+        } else if ([item.description containsString:@"fundclient1.ico"]) {
+            image = [UIImage imageNamed:ZRT_FUNDCLIENT1_IMAGE_NAME];
+        } else if ([item.description containsString:@"fundclient2.ico"]) {
+            image = [UIImage imageNamed:ZRT_FUNDCLIENT2_IMAGE_NAME];
+        } else {
+            image = item.icon;
+        }
+    } else {
+        image = (isFolder && !isCustomDesktop) ? [UIImage imageNamed:FOLDER_APP_IMAGE_NAME] : [UIImage imageNamed:DESKTOP_IMAGE_NAME];
+    }
+    [cell configureCellWithImage:image name:item.name isFolder:isFolder];
+    
+    return cell;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell *cell = nil;
+    if ([tableView isEqual:self.resourceTableView]) {
+        NSInteger row = indexPath.row;
+        NSInteger section = indexPath.section;
+        NSInteger totalSections = [self totalSections];
+        
+        __weak typeof(self) weakSelf = self;
+        cell = [self getCellInfoInSection:section
+                             totalSection:totalSections
+                                   object:[NSNumber numberWithInteger:row]
+                                  action1:^id(id param) {
+                                      __strong typeof(weakSelf) strongSelf = weakSelf;
+                                      NSInteger row = [(NSNumber *)param integerValue];
+                                      return [strongSelf configureWebAppWithRow:row];
+                                  }
+                                  action2:^id(id param) {
+                                      __strong typeof(weakSelf) strongSelf = weakSelf;
+                                      NSInteger row = [(NSNumber *)param integerValue];
+                                      return [strongSelf configureNativeAppWithRow:row];
+                                  }
+                                  action3:^id(id param) {
+                                      __strong typeof(weakSelf) strongSelf = weakSelf;
+                                      NSInteger row = [(NSNumber *)param integerValue];
+                                      return [strongSelf configureDesktopAppWithRow:row];
+                                  }];
+    } else if([tableView isEqual:self.acsModeTableView]) {
+        if ([self.acsDescList count] > 0) {
+            AccessModeCell *accessModeCell = [self.acsModeTableView dequeueReusableCellWithIdentifier:kAccessModeCellID];
+            if (!accessModeCell) {
+                accessModeCell = [[AccessModeCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kAccessModeCellID];
+            }
+            NSString *showAcsDesc = [self.acsDescList objectAtIndex:0];
+            if ([self.acsDescList count] > 1) {
+                showAcsDesc = [NSString stringWithFormat:@"%@...", showAcsDesc];
+            }
+            
+            [accessModeCell configureCellWithMessage:showAcsDesc isDescList:NO];
+            [accessModeCell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+            
+            return accessModeCell;
+        } else {
+            cell = [[UITableViewCell alloc] init];
+        }
+        
+    }
+    
+    return cell;
+}
+
+- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
+    NSString *title = @"";
+    if ([tableView isEqual:self.resourceTableView]) {
+        NSInteger totalSections = [self totalSections];
+
+        title = [self getCellInfoInSection:section
+                              totalSection:totalSections
+                                    object:nil
+                                   action1:^id(id param) {
+                                       return NSLocalizedString(@"Web App", nil);
+                                   }
+                                   action2:^id(id param) {
+                                       return NSLocalizedString(@"Native App", nil);
+                                   }
+                                   action3:^id(id param) {
+                                       return NSLocalizedString(@"Remote Desktop", nil);
+                                   }];
+    }
+
+    return title;
+}
+
+#pragma mark - Long press handler for WebApp
+- (void)cellLongPressed:(UIGestureRecognizer *)recognizer {
+    if (recognizer.state == UIGestureRecognizerStateBegan) {
+        CGPoint location = [recognizer locationInView:self.resourceTableView];
+        NSIndexPath *indexPath = [self.resourceTableView indexPathForRowAtPoint:location];
+        _longPressedIndex = indexPath.row;
+        ResourceCell *cell = [self.resourceTableView cellForRowAtIndexPath:indexPath];
+        
+        [self showMenuWithCell:cell];
+    }
+}
+
+- (void)showMenuWithCell:(ResourceCell *)cell {
+    [cell becomeFirstResponder];
+    
+    UIMenuController *controller = [UIMenuController sharedMenuController];
+    UIMenuItem *openItem = [[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Open in Safari", nil) action:@selector(openWebPage:)];
+    [controller setMenuItems:[NSArray arrayWithObjects:openItem, nil]];
+    [controller setTargetRect:cell.contentView.frame inView:cell.contentView];
+    [controller setMenuVisible:YES animated:YES];
+}
+
+- (void)openWebPage:(id)sender {
+    if (_longPressedIndex >= self.model.webApps.children.count) {
+        ANError(@"Index (%zi) is out range of web apps count.", _longPressedIndex);
+        return;
+    }
+    
+    WebApp *app = [self.model.webApps.children objectAtIndex:_longPressedIndex];
+    if (app.type == APP_TYPE_WEBAPP) {
+        [[UIApplication sharedApplication] openURL:app.url];
+    }
+}
+
+#pragma mark - TimerRuleDelegate
+- (void)shouldSignOut {
+    [self logoutSilently];
+}
+
+#pragma mark - UITableViewDelegate
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    if ([tableView isEqual:self.resourceTableView]) {
+        [self.resourceTableView deselectRowAtIndexPath:indexPath animated:YES];
+        
+        NSInteger totalSections = [self totalSections];
+        NSInteger section = indexPath.section;
+        NSArray *children = nil;
+        
+        __weak typeof(self) weakSelf = self;
+        children = [self getCellInfoInSection:section
+                                 totalSection:totalSections
+                                       object:indexPath
+                                      action1:^id(id param) {
+                                          __strong typeof(weakSelf) strongSelf = weakSelf;
+                                          return [strongSelf didSelectWebAppAtIndexPath:indexPath];
+                                      }
+                                      action2:^id(id param) {
+                                          __strong typeof(weakSelf) strongSelf = weakSelf;
+                                          return [strongSelf didSelectNativeAppAtIndexPath:indexPath];
+                                      }
+                                      action3:^id(id param) {
+                                          __strong typeof(weakSelf) strongSelf = weakSelf;
+                                          return [strongSelf didSelectDesktopAtIndexPath:indexPath];
+                                      }];
+        
+        if (children != nil) {
+            [self performSegueWithIdentifier:kSegueToSubResource sender:children];
+        }
+    } else if ([tableView isEqual:self.acsModeTableView]) {
+        [self.acsModeTableView deselectRowAtIndexPath:indexPath animated:YES];
+        if ([self.acsDescList count] > 0) {
+            [self performSegueWithIdentifier:kSegueToAccessModeSelect sender:self];
+        }
+    }
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    if ([tableView isEqual:self.resourceTableView]) {
+        return 39;
+    } 
+    
+    return 0;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
+    if ([tableView isEqual:self.resourceTableView]) {
+        static CGFloat kDefaultCellHeight = 44.0;
+        static CGFloat kNativeCellHeight = 66.0;
+        NSInteger section = indexPath.section;
+        NSInteger totalSections = [self totalSections];
+        
+        NSNumber *result = [self getCellInfoInSection:section
+                                         totalSection:totalSections
+                                               object:nil
+                                              action1:^id(id param) {
+                                                  return [NSNumber numberWithFloat:kDefaultCellHeight];
+                                              }
+                                              action2:^id(id param) {
+                                                  return [NSNumber numberWithFloat:kNativeCellHeight];
+                                              }
+                                              action3:^id(id param) {
+                                                  return [NSNumber numberWithFloat:kDefaultCellHeight];
+                                              }];
+        
+        return [result integerValue];
+    } else if ([tableView isEqual:self.acsModeTableView]) {
+        return 44;
+    }
+    
+    return 0;
+}
+
+#pragma mark - Helper
+typedef id (^Action)(id param);
+
+- (id)getCellInfoInSection:(NSInteger)section
+              totalSection:(NSInteger)totalSection
+                    object:(id)object
+                   action1:(Action)action1
+                   action2:(Action)action2
+                   action3:(Action)action3 {
+    id result = nil;
+    
+    switch (totalSection) {
+        case kResourceSectionOne: {
+            if ([self isWebAppToShow]) {
+                result = action1(object);
+            } else if ([self isNativeAppToShow]) {
+                result = action2(object);
+            } else if ([self isDesktopToShow]) {
+                result = action3(object);
+            }
+            break;
+        }
+        case kResourceSectionTwo:
+            if ([self isWebAppToShow]) {
+                if ([self isNativeAppToShow]) {
+                    if (section == kResourceSectionIndex0) {
+                        result = action1(object);
+                    } else if (section == kResourceSectionIndex1) {
+                        result = action2(object);
+                    }
+                } else if ([self isDesktopToShow]) {
+                    if ([self isDesktopToShow]) {
+                        if (section == kResourceSectionIndex0) {
+                            result = action1(object);
+                        } else if (section == kResourceSectionIndex1) {
+                            result = action3(object);
+                        }
+                    }
+                }
+            } else if ([self isNativeAppToShow]) {
+                if ([self isDesktopToShow]) {
+                    if (section == kResourceSectionIndex0) {
+                        result = action2(object);
+                    } else if (section == kResourceSectionIndex1) {
+                        result = action3(object);
+                    }
+                }
+            }
+            break;
+        case kResourceSectionThree:
+            if (section == kResourceSectionIndex0) {
+                result = action1(object);
+            } else if (section == kResourceSectionIndex1) {
+                result = action2(object);
+            } else if (section == kResourceSectionIndex2) {
+                result = action3(object);
+            }
+            break;
+            
+        default:
+            ANError(@"Invalid sections number of (%zi) received.", section);
+            break;
+    }
+    
+    return result;
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ResourcesViewController.m.InfosecEnterprise
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ResourcesViewController.m.InfosecEnterprise	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ResourcesViewController.m.InfosecEnterprise	(working copy)
@@ -0,0 +1,1319 @@
+//
+//  ResourcesViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/27.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "ANLogger.h"
+#import "AAAManager.h"
+#import "AppManager.h"
+#import "GCustomItem.h"
+#import "PubAppItem.h"
+#import "FBKVOController.h"
+#import "ArrayVPNWrapper.h"
+#import "ANPopupDialog.h"
+#import "GatewayManager.h"
+#import "CertificateManager.h"
+#import "ConfigurationManager.h"
+#import "RulesManager.h"
+#import "ResourceCell.h"
+#import "MJRefresh.h"
+#import "NativeAppCell.h"
+#import "AutoLoginHandler.h"
+#import "SubResourceViewController.h"
+#import "UIView+Toast.h"
+#import "ResourcesViewController.h"
+#import "AccessModeCell.h"
+#import "AccessModeSelectViewController.h"
+#import "ZTWKWebViewController.h"
+
+static NSString * const kSegueToSubResource = @"ResourceToSubResource";
+static NSString * const kSegueToCustomDesktop = @"ResourceToCustomDesktop";
+static NSString * const kSegueToAccessModeSelect = @"ResourceToAccessModeSelect";
+
+#if TARGET_OS_IPHONE
+NSString * const kAppGroupNameResource = @"group.net.infosec.groupenterprise";
+NSString * const kArrayVPNTunelErrorMsgResource = @"net.arraynetworks.sslvpn.errormsg";
+#elif TARGET_OS_MAC
+NSString * const kAppGroupNameResource = @"5VZLZ3YQ9P.net.arraynetworks.MacTunnel";
+#endif
+
+typedef NS_ENUM(NSInteger, ResourceSectionNumber) {
+    kResourceSectionZero = 0,
+    kResourceSectionOne,
+    kResourceSectionTwo,
+    kResourceSectionThree
+};
+
+typedef NS_ENUM(NSInteger, ResourceSectionIndex) {
+    kResourceSectionIndex0 = 0,
+    kResourceSectionIndex1,
+    kResourceSectionIndex2
+};
+
+@interface ResourcesViewController () <TimerRuleDelegate, AcsModeSelectControllerDelegate> {
+    NSInteger _longPressedIndex;
+}
+
+@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator;
+@property (weak, nonatomic) IBOutlet UILabel *statusLabel;
+@property (weak, nonatomic) IBOutlet UISwitch *vpnEnableSwitch;
+@property (weak, nonatomic) IBOutlet UIImageView *statusImageView;
+
+@property (weak, nonatomic) IBOutlet UIView *messageView;
+@property (weak, nonatomic) IBOutlet UILabel *messageLabel;
+
+@property (weak, nonatomic) IBOutlet UIView *emptyResourceView;
+@property (weak, nonatomic) IBOutlet UIImageView *emptyResourceImageView;
+@property (weak, nonatomic) IBOutlet UILabel *emptyResourceLabel;
+
+@property (weak, nonatomic) IBOutlet UITableView *resourceTableView;
+
+@property (weak, nonatomic) IBOutlet UITableView *acsModeTableView;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *resourceViewTopConstraint;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *emptyViewTopConstraint;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *messageViewTopConstraint;
+
+@property (strong, nonatomic) AppManager *model;
+@property (strong, nonatomic) NSArray *desktops;  // As a cache
+
+@property (strong, nonatomic) NSArray *acsDescList;
+@property (strong, nonatomic) NSArray *acsNameList;
+@property (strong, nonatomic) NSString *acsSelectedInfo;
+
+
+@property (strong, nonatomic) id browser;
+
+// For DesktopDirect
+@property (nonatomic, strong) NSIndexPath *currentIndex;
+@property (nonatomic, strong) ResourceItem *currentItem;
+@property (nonatomic, strong) FBKVOController *kvoController;
+@property (nonatomic, strong) UIControl *darkView;
+@property (nonatomic) BOOL silence;
+@property (nonatomic) BOOL needReconnect;
+
+@end
+
+@implementation ResourcesViewController
+
+@synthesize desktops = _desktops;
+
+- (void)dealloc {
+#if TARGET_OS_IPHONE
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:kArrayVPNTunelErrorMsgResource object:nil];
+#endif
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    self.model = [AppManager sharedInstance];
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(handleVPNStatus:)
+                                                 name:kArrayVPNStatusNotification
+                                               object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(handleAutoLogout:)
+                                                 name:kAutoLogoutNotification
+                                               object:nil];
+    
+    [self setVPNStatusAsDisconnected];
+    [self autoStartVPN];
+    [self doPostLoginCV];
+    
+    [self initKVOController];
+    
+    [self initTopView];
+    [self initAccessModeView];
+    [self initPullToRefresh];
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [super viewWillDisappear:animated];
+    
+    self.silence = YES;
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    
+    self.silence = NO;
+}
+
+- (void)viewDidAppear:(BOOL)animated {
+    [super viewDidAppear:animated];
+    
+    RulesManager *manager = [RulesManager sharedInstance];
+    if (manager.didEndSession) {
+        manager.didEndSession = NO;
+        
+        [self logoutSilently];
+    }
+}
+
+- (void)initAccessModeView {
+    BOOL bShowAcsModeView = NO;
+    
+    self.acsSelectedInfo = nil;
+    self.acsDescList = [AAAManager sharedInstance].acsModeDesc;
+    self.acsNameList = [AAAManager sharedInstance].acsModeName;
+    if (self.acsDescList != nil) {
+        bShowAcsModeView = YES;
+    }
+    
+    if (bShowAcsModeView) {
+        self.acsModeTableView.hidden = NO;
+        self.resourceViewTopConstraint.constant = 95;
+        self.emptyViewTopConstraint.constant = 100;
+        self.messageViewTopConstraint.constant = 100;
+        self.acsModeTableView.tableHeaderView = [[UIView alloc]initWithFrame:CGRectMake(0,0,0,0.01)];
+    } else {
+        self.acsModeTableView.hidden = YES;
+        self.resourceViewTopConstraint.constant = 45;
+        self.emptyViewTopConstraint.constant = 50;
+        self.messageViewTopConstraint.constant = 50;
+    }
+    
+    self.needReconnect = NO;
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (IBAction)exitButtonClicked:(id)sender {
+    __weak typeof(self) weakSelf = self;
+    PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+                                                                   message:NSLocalizedString(@"Would you like to sign out?", nil)
+                                                             confirmAction:^{
+                                                                 [weakSelf stopVPNAndLogout:NO];
+                                                             }
+                                                              cancelAction:nil];
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (IBAction)vpnEnableSwitched:(id)sender {
+    if (self.vpnEnableSwitch.on) {
+        BOOL ret = [self startVPN:NO];
+        if (!ret) {
+            [self setVPNStatusAsError:NSLocalizedString(@"Can't start VPN.", nil)];
+        }
+    } else {
+        [self stopVPN];
+    }
+}
+
+- (void)initTopView {
+    [self.acsModeTableView registerNib:[UINib nibWithNibName:@"AccessModeCell" bundle:nil] forCellReuseIdentifier:kAccessModeCellID];
+    if (self.model.isEmpty) {
+        [self showEmptyResouceView];
+    } else {
+        [self showResourceTableView];
+        [self.resourceTableView registerNib:[UINib nibWithNibName:@"ResourceCell" bundle:nil] forCellReuseIdentifier:kResourceCellID];
+        [self.resourceTableView registerNib:[UINib nibWithNibName:@"NativeAppCell" bundle:nil] forCellReuseIdentifier:kNativeAppCellID];
+    }
+}
+
+- (void)initPullToRefresh {
+    __weak typeof(self) weakSelf = self;
+    self.resourceTableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
+        __strong typeof(weakSelf) strongSelf = weakSelf;
+        [strongSelf endRefresh];
+        
+        Gateway *currentGateway = [self getCurrentGateway];
+        if (currentGateway) {
+            [[AppManager sharedInstance] fetchAppsFromServer:currentGateway.host
+                                                        port:currentGateway.port
+                                                  completion:^(BOOL isNeedUpdate) {
+                                                      [strongSelf.resourceTableView reloadData];
+                                                  }];
+        }
+    }];
+}
+
+- (void)endRefresh{
+    [self.resourceTableView.mj_header endRefreshing];
+}
+
+- (void)doPostLoginCV {
+    [[RulesManager sharedInstance] setDelegate:self];
+    
+    /**
+     * It may not be a reliable way to do post login Client Verification.
+     * Maybe we should listen to the VPN_CB_CV_USER message.
+     */
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{
+        RulesManager *manager = [RulesManager sharedInstance];
+        [manager cleanTimerRuleInteraction];
+        [manager kickoffTimerRules];
+    });
+    
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{
+        [[RulesManager sharedInstance].interactionHandler takeAction];
+    });
+}
+
+- (void)initKVOController {
+    self.kvoController = [FBKVOController controllerWithObserver:self];
+}
+
+#pragma mark - Access Mode
+
+- (NSArray *)cellsForTableView:(UITableView *)tableView
+{
+    NSInteger sections = tableView.numberOfSections;
+    NSMutableArray *cells = [[NSMutableArray alloc]  init];
+    for (int section = 0; section < sections; section++) {
+        NSInteger rows =  [tableView numberOfRowsInSection:section];
+        for (int row = 0; row < rows; row++) {
+            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
+            [cells addObject:[tableView cellForRowAtIndexPath:indexPath]];
+        }
+    }
+    return cells;
+}
+
+- (int)switchAccessMode:(NSString *)acsDesc {
+    int ret = ERROR_ACM_SUCCESS;
+    BOOL isMatchDesc = NO;
+    
+    if ([self.acsDescList count] == [self.acsNameList count]) {
+        for (NSUInteger i =0; i < [self.acsDescList count]; i++) {
+            if ([[self.acsDescList objectAtIndex:i] isEqualToString:acsDesc]) {
+                isMatchDesc = YES;
+                ret = array_vpn_access_mode_set([[self.acsNameList objectAtIndex:i] UTF8String], NULL, NULL, 0);
+                break;
+            }
+        }
+    }
+    
+    if (!isMatchDesc) {
+        ANError(@"switchAccessMode: get match access mode message failed, switch failed return error.");
+        ret = ERROR_ACM_UNDEFINE;
+    }
+    
+    return ret;
+}
+
+- (void)accessModeRestartVPN{
+    BOOL ret = [self startVPN:NO];
+    if (!ret) {
+        [self setVPNStatusAsError:NSLocalizedString(@"Can't start VPN.", nil)];
+    }
+    
+    NSArray *cells = [self cellsForTableView:self.acsModeTableView];
+    if ([cells count] == 1) {
+        AccessModeCell *cell = (AccessModeCell *)[cells objectAtIndex:0];
+        [cell showActiveView:NO];
+        [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+    }
+}
+
+- (void)didFinishSelect:(NSString *)selectAcsDesc {
+    NSArray *cells = [self cellsForTableView:self.acsModeTableView];
+    if ([cells count] == 1) {
+        AccessModeCell *cell = (AccessModeCell *)[cells objectAtIndex:0];
+        NSString *currentAcsDesc = [cell getCellText];
+        if ([selectAcsDesc length] > 0) {
+            if ([currentAcsDesc isEqualToString:selectAcsDesc]) {
+                ANInfo(@"didFinishSelect: user select same access mode ,do nothing.");
+            } else {
+                ANInfo(@"didFinishSelect: user select access mode[%@]", selectAcsDesc);
+                [cell setCellText:selectAcsDesc];
+                [cell showActiveView:YES];
+                [cell setCellImage:ACCESS_MODE_IMAGE_INACTIVE_NAME];
+                dispatch_async(dispatch_get_main_queue(), ^{
+                    int ret = [self switchAccessMode:selectAcsDesc];
+                    NSString *errorMessage = nil;
+                    switch (ret) {
+                        case ERROR_ACM_SUCCESS:
+                            ANInfo(@"didFinishSelect:switch access mode successfully.");
+                            [cell showActiveView:NO];
+                            [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+                            break;
+                        case ERROR_ACM_SUCCESS_RECONN:
+                            ANInfo(@"didFinishSelect:switch access mode successfully.");
+                            ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+                            if (tunnelStatus == ArrayVPNConnected) {
+                                ANInfo(@"didFinishSelect:vpn status is connected, need reconnect.");
+                                self.needReconnect = YES;
+                                [self stopVPN];
+                            } else {
+                                [cell showActiveView:NO];
+                                [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+                            }
+                            break;
+                        case ERROR_ACM_WITHOUT_SESSION:
+                            errorMessage = NSLocalizedString(@"Switching failure: invalid user session. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_NAME_INVALID:
+                            errorMessage = NSLocalizedString(@"Switching failure: illegal mode information. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_NAME_NONE:
+                            errorMessage = NSLocalizedString(@"Switching failure: mode information does not exist. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_INVALID_PARAMETER:
+                            errorMessage = NSLocalizedString(@"Switching failure: incorrect parameter. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_ACL_CHANGE_FAILED:
+                            errorMessage = NSLocalizedString(@"Switching failure: the server fails to switch. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_NETWORK:
+                            errorMessage = NSLocalizedString(@"Switching failure: network error. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_UNDEFINE:
+                            errorMessage = NSLocalizedString(@"Switching failure: unknown error. Please switch again or contact the administrator.", nil);
+                            break;
+                        default:
+                            errorMessage = NSLocalizedString(@"Switching failure: unknown error. Please switch again or contact the administrator.", nil);
+                            break;
+                    }
+                    if (errorMessage && errorMessage.length > 0) {
+                        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error",nil) message:errorMessage];
+                        [self presentViewController:dialog animated:YES completion:nil];
+                        [cell showActiveView:NO];
+                        [cell setCellText:currentAcsDesc];
+                        [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+                    } else {
+                        for (NSString *info in self.acsDescList) {
+                            if ([selectAcsDesc isEqualToString:info]) {
+                                self.acsSelectedInfo = info;
+                            }
+                        }
+                    }
+                    ANInfo(@"didFinishSelect:switch access mode finished, select access mode=%@.", self.acsSelectedInfo);
+                });
+            }
+        }
+    }
+}
+
+#pragma mark - Auto Logout
+- (void)handleAutoLogout:(NSNotification *)notification {
+    [self logoutSilently];
+}
+
+- (void)clearCookies {  // ANsession should be cleared on logout. (for WebAuth)
+#define MP_SESSION_PREFIX   @"ANsession"
+#define MP_USERNAME_COOKIE  @"username"
+#define MP_ACCESS_NAME      @"acs_mode"
+#define MP_ACCESS_DESC      @"acs_desc"
+    
+    NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
+    NSArray *cookies = cookieJar.cookies;
+    for (NSHTTPCookie *cookie in cookies) {
+        if (cookie.name) {
+            if ([cookie.name isEqualToString:MP_USERNAME_COOKIE] ||[cookie.name containsString:MP_SESSION_PREFIX] || [cookie.name containsString:MP_ACCESS_NAME] || [cookie.name containsString:MP_ACCESS_DESC]) {
+                [cookieJar deleteCookie:cookie];
+            }
+        }
+    }
+}
+
+#pragma mark - VPN Status
+#define STATUS_LABEL_COLOR_NORMAL   UIColorFromRGBA(0x666666, 1.0)
+#define STATUS_LABEL_COLOR_WARNING  UIColorFromRGBA(0xff0000, 1.0)
+#define STATUS_LABEL_COLOR_GREEN    UIColorFromRGBA(0x42a009, 1.0)
+
+- (void)setVPNStatusAsConnecting {
+    self.activityIndicator.hidden = NO;
+    [self.activityIndicator startAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_NORMAL;
+    self.statusLabel.text = NSLocalizedString(@"Connecting...", nil);
+    self.statusImageView.hidden = YES;
+    self.vpnEnableSwitch.on = YES;
+    [self showMessageViewWithInfo:nil];
+}
+
+- (void)setVPNSStatusAsConnected {
+    [self.activityIndicator stopAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_GREEN;
+    self.statusLabel.text = NSLocalizedString(@"Connected", nil);
+    self.statusImageView.image = [UIImage imageNamed:@"ResourceConnectSuccess"];
+    self.statusImageView.hidden = NO;
+    self.vpnEnableSwitch.on = YES;
+    [self showMessageViewWithInfo:nil];
+}
+
+- (void)setVPNStatusAsDisconnected {
+    [self.activityIndicator stopAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_NORMAL;
+    self.statusLabel.text = NSLocalizedString(@"Disconnected", nil);
+    self.statusImageView.image = [UIImage imageNamed:@"ResourceConnectError"];
+    self.statusImageView.hidden = NO;
+    self.vpnEnableSwitch.on = NO;
+    [self showMessageViewWithInfo:nil];
+    if (self.needReconnect) {
+        ANInfo(@"access mode disconnect vpn finished, now need restart vpn.");
+        self.needReconnect = NO;
+        [self accessModeRestartVPN];
+    }
+}
+
+- (void)setVPNStatusAsDisconnecting {
+    [self.activityIndicator startAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_NORMAL;
+    self.statusLabel.text = NSLocalizedString(@"Disconnecting...", nil);
+    self.statusImageView.hidden = YES;
+    self.vpnEnableSwitch.on = NO;
+    [self showMessageViewWithInfo:nil];
+}
+
+- (void)setVPNStatusAsError:(NSString *)errorMessage {
+    [self.activityIndicator stopAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_WARNING;
+    self.statusLabel.text = NSLocalizedString(@"Connect failed", nil);
+    self.statusImageView.image = [UIImage imageNamed:@"ResourceConnectError"];
+    self.statusImageView.hidden = NO;
+    self.vpnEnableSwitch.on = NO;
+    [self showMessageViewWithInfo:errorMessage];
+}
+
+- (void)showMessageViewWithInfo:(NSString *)info {
+    if (info) {
+        self.messageLabel.text = info;
+        self.messageView.hidden = NO;
+    } else {
+        self.messageLabel.text = @"";
+        self.messageView.hidden = YES;
+    }
+}
+
+- (void)showEmptyResouceView {
+    self.emptyResourceView.hidden = NO;
+    self.resourceTableView.hidden = YES;
+    [self.view bringSubviewToFront:self.emptyResourceView];
+}
+
+- (void)showResourceTableView {
+    self.emptyResourceView.hidden = YES;
+    self.resourceTableView.hidden = NO;
+    [self.view bringSubviewToFront:self.resourceTableView];
+}
+
+#pragma mark - VPN Related
+- (BOOL)autoStartVPN {
+    BOOL isAutoStart = NO;
+    Gateway *gateway = [self getCurrentGateway];
+    
+    if (!gateway) {
+        isAutoStart = YES;
+        ANInfo(@"No gateway is selected, it is auto start vpn.");
+    } else {
+        if (!gateway.isSecureTunnelEnabled) {
+            ANInfo(@"Auto start VPN is not enabled.");
+            return NO;
+        }
+    }
+
+    return [self startVPN:isAutoStart];
+}
+
+- (BOOL)startVPN:(BOOL)isAutoStart {
+    //Gateway *gateway = [self getCurrentGateway];
+    //NSString *session = [AAAManager sharedInstance].sessionID;
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    
+#if TARGET_OS_IPHONE
+    //Reset connect fail reason.
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameResource];
+    [userDefaults removeObjectForKey:@"tunnel_result"];
+    [userDefaults removeObjectForKey:@"dns_list"];
+#endif
+    
+    [vpnWrapper startSSLVPN];
+    
+#if TARGET_OS_IPHONE
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleVPNTunnelError:)
+                                                 name:kArrayVPNTunelErrorMsgResource object:nil];
+#endif
+    
+    return YES;
+    
+//    if (isAutoStart) {
+//        [vpnWrapper startSSLVPN];
+//    }
+//
+//    return [vpnWrapper validateSessionWithHost:gateway.host
+//                                          port:gateway.port
+//                                       session:session
+//                                    completion:^(BOOL isSuccess, NSError *error) {
+//                                        if (isSuccess) {
+//                                            [vpnWrapper startSSLVPN];
+//                                        } else {
+//                                            NSString *message = NSLocalizedString(@"Session is invalid, please login again!", nil);
+//                                            PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+//                                                                                                          message:message
+//                                                                                                           action:^{
+//                                                                                                               [[NSNotificationCenter defaultCenter]
+//                                                                                                                postNotificationName:kAutoLogoutNotification
+//                                                                                                                object:nil];
+//                                                                                                           }];
+//                                            [self presentViewController:dialog animated:YES completion:nil];
+//                                        }
+//                                    }];
+}
+
+- (void)stopVPN {
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    [vpnWrapper stopSSLVPN];
+}
+
+- (void)stopVPNAndLogout:(BOOL)isSilent {
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{  // Stop timer rules fisrt.
+        [[RulesManager sharedInstance] stopAllRules];
+    });
+    
+    AAAManager *manager = [AAAManager sharedInstance];
+    [manager continueVPNThreadWithAccount:nil];
+    [self stopVPN];
+    
+    [self clearCookies];
+    
+    if (!isSilent) {
+        __weak typeof(self) weakSelf = self;
+        [self.view makeToastActivity:CSToastPositionCenter];
+        dispatch_async(dispatch_get_global_queue(0, 0), ^{
+            NSInteger ret = [[AAAManager sharedInstance] stopL3VPNDirectly];
+            if (ret != ERR_SUCCESS) {
+                ANError(@"Logout failed with error code: %zi.", ret);
+            }
+            
+            __strong typeof(weakSelf) strongSelf = weakSelf;
+            dispatch_async(dispatch_get_main_queue(), ^{
+                [strongSelf.view hideToastActivity];
+                [strongSelf dismissViewControllerAnimated:YES completion:nil];
+            });
+        });
+    }
+}
+
+- (void)logoutSilently {
+    [self stopVPNAndLogout:YES];
+    
+    [self.navigationController dismissViewControllerAnimated:NO completion:nil];  // Dismiss modal view if exists.
+    [self dismissViewControllerAnimated:YES completion:nil];
+}
+
+- (Gateway *)getCurrentGateway {
+    VPNAccount *account = [AAAManager sharedInstance].account;
+    GatewayManager *gm = [GatewayManager sharedInstance];
+    NSString *url = account.vsURL;
+    NSString *port = account.vsPort;
+    NSInteger index = [gm indexOfUrl:url andport:port];
+    
+    return [gm gatewayAtIndex:index];
+}
+
+#pragma mark - VPN Status Handler
+- (void)handleVPNStatus:(NSNotification *)notification {
+    ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+    
+    ANDebug(@"Array VPN tunnel status = %zi", tunnelStatus);
+    
+    [self updateUIWithVPNStatus:tunnelStatus];
+}
+
+- (void)updateUIWithVPNStatus:(ArrayVPNStatus)status {
+    switch (status) {
+        case ArrayVPNInavlid:
+        case ArrayVPNDisconnected:
+            [self setVPNStatusAsDisconnected];
+            break;
+        case ArrayVPNDisconnecting:
+            [self setVPNStatusAsDisconnecting];
+            break;
+        case ArrayVPNConnecting:
+        case ArrayVPNReasserting:
+            [self setVPNStatusAsConnecting];
+            break;
+        case ArrayVPNConnected:
+            [self setVPNSStatusAsConnected];
+            break;
+            
+        default:
+            break;
+    }
+}
+
+- (void)handleVPNTunnelError:(NSNotification *)notification {
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    NSString *errMessage = [vpnWrapper getErrorMsgWithCode];
+    if (errMessage && errMessage.length > 0) {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:errMessage];
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+#pragma mark - Number of Sections & Rows
+- (BOOL)isWebAppToShow {
+    PortalTabsConfiguration *portalConfiguration = [ConfigurationManager sharedInstance].portalTabs;
+    
+    return portalConfiguration.isWebAppConfigured && self.model.webApps.children.count > 0;
+}
+
+- (BOOL)isNativeAppToShow {
+    PortalTabsConfiguration *portalConfiguration = [ConfigurationManager sharedInstance].portalTabs;
+    
+    return portalConfiguration.isNativeAppConfigured && self.model.nativeApps.children.count > 0;
+}
+
+- (BOOL)isDesktopToShow {
+    PortalTabsConfiguration *portalConfiguration = [ConfigurationManager sharedInstance].portalTabs;
+    
+    return portalConfiguration.isDesktopConfigured && self.model.desktopApps.resourceItems.count > 0;
+}
+
+- (NSInteger)totalSections {
+    NSInteger totalSections = 0;
+    NSInteger webSection = [self isWebAppToShow] ? 1 : 0;
+    NSInteger nativeSection = [self isNativeAppToShow] ? 1 : 0;
+    NSInteger desktopSection = [self isDesktopToShow] ? 1 : 0;
+    
+    totalSections = webSection + nativeSection + desktopSection;
+    
+    return totalSections;
+}
+
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([segue.identifier isEqualToString:kSegueToSubResource]) {
+        SubResourceViewController *viewController = segue.destinationViewController;
+        [viewController setupModel:(NSArray *)sender];
+    }
+    if ([segue.identifier isEqualToString:kSegueToAccessModeSelect]) {
+        NSArray *cells = [self cellsForTableView:self.acsModeTableView];
+        if ([cells count] == 1) {
+            UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
+            AccessModeSelectViewController *controller = (AccessModeSelectViewController *)navController.topViewController;
+            controller.selectedAcsModeString = self.acsSelectedInfo;
+            controller.delegate = self;
+        }
+    }
+}
+
+#pragma mark - Get Child at Index
+- (NSArray *)didSelectWebAppAtIndexPath:(NSIndexPath *)indexPath {
+    NSInteger row = indexPath.row;
+    
+    if (row >= self.model.webApps.children.count) {
+        ANError(@"Index (%zi) is out range of web apps count.", row);
+        return nil;
+    }
+    
+    WebApp *app = [self.model.webApps.children objectAtIndex:row];
+    if (app.type == APP_TYPE_WEBAPP) {
+        ZTWKWebViewController *control = [[ZTWKWebViewController alloc] init];
+        control.webUrl = [app.url absoluteString];
+        [self.navigationController pushViewController:control animated:YES];
+
+        
+        return nil;
+    }
+    
+    return app.children;
+}
+
+- (NSArray *)didSelectNativeAppAtIndexPath:(NSIndexPath *)indexPath {
+    NSInteger row = indexPath.row;
+    
+    if (row >= self.model.nativeApps.children.count) {
+        ANError(@"Index (%zi) is out range of native apps count.", row);
+        return nil;
+    }
+    
+    NativeApp *app = [self.model.nativeApps.children objectAtIndex:row];
+    NSURL *url = [NSURL URLWithString:app.scheme];
+    if (url.scheme == nil) {
+        url = [NSURL URLWithString:[NSString stringWithFormat:@"%@://", app.scheme]];
+    }
+    
+    ANInfo(@"open app url=%@", url);
+    if (!OpenURL(url)) {
+        BOOL isAppStoreApp = (app.installUrl != nil);
+        if (!isAppStoreApp) {
+            NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Application %@ has not been installed, Would you like to search it on App Store?", nil), app.name];
+            PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:@""
+                                                                           message:message
+                                                                     confirmAction:^{
+                                                                         NSString *string = [NSString stringWithFormat:APPSTORE_SEARCH_STRING,
+                                                                                             [app.name stringByAddingPercentEncodingWithAllowedCharacters:
+                                                                                              NSCharacterSet.URLQueryAllowedCharacterSet]];
+                                                                         OpenURL([NSURL URLWithString:string]);
+                                                                     }
+                                                                      cancelAction:nil];
+            
+            [self presentViewController:dialog animated:YES completion:nil];
+        } else {
+            NSString *urlString = [NSString stringWithFormat:ITMS_SERVICE_PREFIX, app.installUrl];
+            ANInfo(@"Download app url=%@, scheme=%@", urlString, app.scheme);
+            if ([app.scheme containsString:@"voffice"]) {
+                urlString = @"http://app.arraynetworks.com.cn/voffice2";
+            }
+            if ([app.scheme containsString:@"zrOA"]) {
+                urlString = @"http://app.arraynetworks.com.cn/sufei";
+            }
+            if ([app.scheme containsString:@"zrlcsApp"]) {
+                urlString = @"http://app.arraynetworks.com.cn/staf";
+            }
+            OpenURL([NSURL URLWithString:urlString]);  // Install directly from AG.
+        }
+    }
+    
+    return nil;
+}
+
+- (NSArray *)didSelectDesktopAtIndexPath:(NSIndexPath *)indexPath {
+    NSInteger row = indexPath.row;
+    
+    if (row >= self.model.desktopApps.resourceItems.count) {
+        ANError(@"Index (%zi) is out range of desktop apps count.", row);
+        return nil;
+    }
+    
+    FolderItem *item = [self.desktops objectAtIndex:row];
+    if ([item isKindOfClass:[GCustomItem class]] && [item.name isEqualToString:NSLocalizedString(@"Other", nil)]) {
+        [self performSegueWithIdentifier:kSegueToCustomDesktop sender:self];
+        return nil;
+    } else if ([item isKindOfClass:[HostItem class]]) {
+        [self didSelectHostItem:(HostItem *)item atIndexPath:indexPath];
+        return nil;
+    }
+    
+    return [self getSortedArray:[item.resourceItems allValues]];
+}
+
+#pragma mark - DesktopDirect
+- (void)didSelectHostItem:(HostItem *)hostItem atIndexPath:(NSIndexPath *)indexPath {
+    if (self.currentIndex
+        && self.currentIndex.row == indexPath.row
+        && hostItem.status < ResourceStatusReady) {
+        return;
+    }
+    
+    self.currentIndex = indexPath;
+    self.currentItem = hostItem;
+    
+    ResourceCell *cell = (ResourceCell *)[self.resourceTableView cellForRowAtIndexPath:indexPath];
+    
+    __weak typeof(self) weakSelf = self;
+    [self.kvoController observe:hostItem
+                        keyPath:@"status"
+                        options:NSKeyValueObservingOptionNew
+                          block:^(ResourcesViewController *observer, HostItem *host, NSDictionary *change) {
+                              NSInteger hostStatus = host.status;
+                              dispatch_async(dispatch_get_main_queue(), ^{
+                                  [cell updateUI:host];
+                                  if (observer.currentIndex.row != indexPath.row) {
+                                      return;
+                                  }
+                                  
+                                  if (observer.silence) {
+                                      return;
+                                  }
+                                  if (host.status == ResourceStatusReady) {
+                                      [observer.kvoController unobserve:host];
+                                      NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
+                                      AppManager *appManager = [AppManager sharedInstance];
+                                      BOOL cliEnabledNEC = NO;
+                                      NSString *enabledNEC = appManager.desktopSettings.settings[@"jp-rdp"];
+                                      if (enabledNEC && [enabledNEC isEqualToString:@"1"])
+                                          cliEnabledNEC = YES;
+                                      if (cliEnabledNEC || [userDefaults integerForKey:@"desktop_client_vendor"] == 1) {
+                                          [observer openRDClientNEC:host];
+                                      } else {
+                                          [observer openRDClient:host];
+                                      }
+                                      // Reset power state
+                                      host.powerState = HostPowerStateDown;
+                                      return;
+                                  } else if (hostStatus >= ResourceStatusFailed && hostStatus < ResourceStatusResolveHostNameFailed) {
+                                      ANError(@"Cannot connect to remote host, error code: %zi", hostStatus);
+                                      
+                                      if (hostStatus == ResourceStatusPowerDown) {
+                                          NSString *message = NSLocalizedString(@"It seems the remote host is turned off. Would you like to try and wake it up?", nil);
+                                          
+                                          PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Cannot connect to remote host", nil)
+                                                                                                         message:message
+                                                                                                   confirmAction:^{
+                                                                                                       NSInteger row = weakSelf.currentIndex.row;
+                                                                                                       HostItem *host = weakSelf.desktops[row];
+                                                                                                       [host wakeUp];
+                                                                                                   }
+                                                                                                    cancelAction:nil];
+                                          
+                                          [weakSelf presentViewController:dialog animated:YES completion:nil];
+                                          
+                                          return;
+                                      } else {
+                                          [observer.kvoController unobserve:host];
+                                      }
+                                  }
+                              });
+                          }];
+    
+    [hostItem prepare];
+}
+
+- (void)openRDClient:(HostItem *)hostItem {
+    NSURL *url = hostItem.url;
+    if (!url) {
+        return;
+    }
+    
+    if (!OpenURL(url)) {
+        NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Application %@ has not been installed, Would you like to search it on App Store?", nil), @"RD client"];
+        PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Cannot connect to remote host", nil)
+                                                                       message:message
+                                                                 confirmAction:^{
+                                                                     NSString *string = [NSString stringWithFormat:APPSTORE_SEARCH_STRING,
+                                                                                         [@"RD client" stringByAddingPercentEncodingWithAllowedCharacters:
+                                                                                          NSCharacterSet.URLQueryAllowedCharacterSet]];
+                                                                     
+                                                                     OpenURL([NSURL URLWithString:string]);
+                                                                 }
+                                                                  cancelAction:nil];
+        
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+- (void)openRDClientNEC:(HostItem *)hostItem {
+    NSURL *url = hostItem.urlVendorNEC;
+    if (!url) {
+        return;
+    }
+    
+    if (!OpenURL(url)) {
+        NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Application %@ has not been installed, Would you like to search it on App Store?", nil),@"RD"];
+        PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Cannot connect to remote host", nil)
+                                                                       message:message
+                                                                 confirmAction:^{
+                                                                     NSString *string = @"https://itunes.apple.com/jp/app/rd-v1.3/id771611106?mt=8";
+                                                                     OpenURL([NSURL URLWithString:string]);
+                                                                 }
+                                                                  cancelAction:nil];
+        
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+- (NSArray *)desktops {
+    if (!_desktops) {
+        _desktops = [self getSortedArray:[self.model.desktopApps.resourceItems allValues]];
+    }
+    
+    return _desktops;
+}
+
+- (NSArray *)getSortedArray:(NSArray *)array {
+    if (!array || array.count == 0) {
+        ANWarn(@"Empty array, should not be sorted.");
+        return nil;
+    }
+    
+    NSSortDescriptor *byClass = [NSSortDescriptor sortDescriptorWithKey:@"class" ascending:YES comparator:^NSComparisonResult(id obj1, id obj2) {
+        // Sort by class name
+        return [NSStringFromClass(obj1) compare:NSStringFromClass(obj2)];
+        
+    }];
+    
+    NSSortDescriptor *byName = [NSSortDescriptor sortDescriptorWithKey:@"name"
+                                                             ascending:YES
+                                                              selector:@selector(localizedStandardCompare:)];
+    
+    NSArray *sortDescriptors = [NSArray arrayWithObjects:byClass, byName, nil];
+    
+    return [array sortedArrayUsingDescriptors:sortDescriptors];
+}
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    if ([tableView isEqual:self.resourceTableView]) {
+        return [self totalSections];
+    } else if ([tableView isEqual:self.acsModeTableView]) {
+        return 1;
+    }
+    
+    return 0;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    if ([tableView isEqual:self.resourceTableView]) {
+        NSInteger totalSections = [self totalSections];
+        if (section > totalSections) {
+            ANError(@"Section (%zi) is larger than total sections (%zi).", section, totalSections);
+            
+            return 0;
+        }
+        
+        __weak typeof(self) weakSelf = self;
+        NSNumber *result = [self getCellInfoInSection:section
+                                         totalSection:totalSections
+                                               object:nil
+                                              action1:^id(id param) {
+                                                  __strong typeof(weakSelf) strongSelf = weakSelf;
+                                                  NSInteger rows = strongSelf.model.webApps.children.count;
+                                                  return [NSNumber numberWithInteger:rows];
+                                              }
+                                              action2:^id(id param) {
+                                                  __strong typeof(weakSelf) strongSelf = weakSelf;
+                                                  NSInteger rows = strongSelf.model.nativeApps.children.count;
+                                                  return [NSNumber numberWithInteger:rows];
+                                              }
+                                              action3:^id(id param) {
+                                                  __strong typeof(weakSelf) strongSelf = weakSelf;
+                                                  NSInteger rows = strongSelf.model.desktopApps.resourceItems.count;
+                                                  return [NSNumber numberWithInteger:rows];
+                                              }];
+        
+        return [result integerValue];
+    } else if ([tableView isEqual:self.acsModeTableView]) {
+        return 1;
+    }
+    
+    return 0;
+}
+
+- (UITableViewCell *)configureWebAppWithRow:(NSInteger)row {
+    ResourceCell *cell = [self.resourceTableView dequeueReusableCellWithIdentifier:kResourceCellID];
+    if (!cell) {
+        cell = [[ResourceCell alloc] init];
+    }
+    
+    WebApp *app = [self.model.webApps.children objectAtIndex:row];
+    UIImage *image = nil;
+    BOOL isFolder = app.type == APP_TYPE_FOLDER;
+    if (isFolder) {
+        image = [UIImage imageNamed:FOLDER_APP_IMAGE_NAME];
+    } else {
+        image = [UIImage imageNamed:WEB_APP_IMAGE_NAME];
+        UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self
+                                                                                                       action:@selector(cellLongPressed:)];
+        [cell addGestureRecognizer:longPressGesture];
+    }
+    [cell configureCellWithImage:image name:app.name isFolder:isFolder];
+    
+    return cell;
+}
+
+- (UITableViewCell *)configureNativeAppWithRow:(NSInteger)row {
+    NativeAppCell *cell = [self.resourceTableView dequeueReusableCellWithIdentifier:kNativeAppCellID];
+    if (!cell) {
+        cell = [[NativeAppCell alloc] init];
+    }
+    
+    NativeApp *app = [self.model.nativeApps.children objectAtIndex:row];
+    UIImage *image = nil;
+    if (app.customIcon) {
+        image = app.customIcon;
+    } else if (app.appIcon) {
+        image = app.appIcon;
+    } else {
+        image = [UIImage imageNamed:NATIVE_APP_IMAGE_NAME];
+    }
+    [cell configureCellWithImage:image name:app.name isFolder:NO];  // Native app doesn't support folder.
+    [cell setDescriptionContent:app.desc];
+    
+    return cell;
+}
+
+- (UITableViewCell *)configureDesktopAppWithRow:(NSInteger)row {
+    ResourceCell *cell = [self.resourceTableView dequeueReusableCellWithIdentifier:kResourceCellID];
+    if (!cell) {
+        cell = [[ResourceCell alloc] init];
+    }
+    
+    ResourceItem *item = [self.desktops objectAtIndex:row];
+    BOOL isFolder = [item isKindOfClass:[FolderItem class]];  // Only pub-app & self-defined desktop has folder.
+    BOOL isCustomDesktop = [item isKindOfClass:[GCustomItem class]];
+    if (isCustomDesktop) {
+        isFolder = YES;
+    }
+    UIImage *image = nil;
+    if (item.icon != nil) {
+        if ([item.description containsString:@"http.ico"]) {
+            image = [UIImage imageNamed:ZRT_HTTP_IMAGE_NAME];
+        } else if ([item.description containsString:@"HSValuate1.ico"]) {
+            image = [UIImage imageNamed:ZRT_HSVALUATE1_IMAGE_NAME];
+        } else if ([item.description containsString:@"HSValuate2.ico"]) {
+            image = [UIImage imageNamed:ZRT_HSVALUATE2_IMAGE_NAME];
+        } else if ([item.description containsString:@"fundclient1.ico"]) {
+            image = [UIImage imageNamed:ZRT_FUNDCLIENT1_IMAGE_NAME];
+        } else if ([item.description containsString:@"fundclient2.ico"]) {
+            image = [UIImage imageNamed:ZRT_FUNDCLIENT2_IMAGE_NAME];
+        } else {
+            image = item.icon;
+        }
+    } else {
+        image = (isFolder && !isCustomDesktop) ? [UIImage imageNamed:FOLDER_APP_IMAGE_NAME] : [UIImage imageNamed:DESKTOP_IMAGE_NAME];
+    }
+    [cell configureCellWithImage:image name:item.name isFolder:isFolder];
+    
+    return cell;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell *cell = nil;
+    if ([tableView isEqual:self.resourceTableView]) {
+        NSInteger row = indexPath.row;
+        NSInteger section = indexPath.section;
+        NSInteger totalSections = [self totalSections];
+        
+        __weak typeof(self) weakSelf = self;
+        cell = [self getCellInfoInSection:section
+                             totalSection:totalSections
+                                   object:[NSNumber numberWithInteger:row]
+                                  action1:^id(id param) {
+                                      __strong typeof(weakSelf) strongSelf = weakSelf;
+                                      NSInteger row = [(NSNumber *)param integerValue];
+                                      return [strongSelf configureWebAppWithRow:row];
+                                  }
+                                  action2:^id(id param) {
+                                      __strong typeof(weakSelf) strongSelf = weakSelf;
+                                      NSInteger row = [(NSNumber *)param integerValue];
+                                      return [strongSelf configureNativeAppWithRow:row];
+                                  }
+                                  action3:^id(id param) {
+                                      __strong typeof(weakSelf) strongSelf = weakSelf;
+                                      NSInteger row = [(NSNumber *)param integerValue];
+                                      return [strongSelf configureDesktopAppWithRow:row];
+                                  }];
+    } else if([tableView isEqual:self.acsModeTableView]) {
+        if ([self.acsDescList count] > 0) {
+            AccessModeCell *accessModeCell = [self.acsModeTableView dequeueReusableCellWithIdentifier:kAccessModeCellID];
+            if (!accessModeCell) {
+                accessModeCell = [[AccessModeCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kAccessModeCellID];
+            }
+            NSString *showAcsDesc = [self.acsDescList objectAtIndex:0];
+            if ([self.acsDescList count] > 1) {
+                showAcsDesc = [NSString stringWithFormat:@"%@...", showAcsDesc];
+            }
+            
+            [accessModeCell configureCellWithMessage:showAcsDesc isDescList:NO];
+            [accessModeCell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+            
+            return accessModeCell;
+        } else {
+            cell = [[UITableViewCell alloc] init];
+        }
+        
+    }
+    
+    return cell;
+}
+
+- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
+    NSString *title = @"";
+    if ([tableView isEqual:self.resourceTableView]) {
+        NSInteger totalSections = [self totalSections];
+
+        title = [self getCellInfoInSection:section
+                              totalSection:totalSections
+                                    object:nil
+                                   action1:^id(id param) {
+                                       return NSLocalizedString(@"Web App", nil);
+                                   }
+                                   action2:^id(id param) {
+                                       return NSLocalizedString(@"Native App", nil);
+                                   }
+                                   action3:^id(id param) {
+                                       return NSLocalizedString(@"Remote Desktop", nil);
+                                   }];
+    }
+
+    return title;
+}
+
+#pragma mark - Long press handler for WebApp
+- (void)cellLongPressed:(UIGestureRecognizer *)recognizer {
+    if (recognizer.state == UIGestureRecognizerStateBegan) {
+        CGPoint location = [recognizer locationInView:self.resourceTableView];
+        NSIndexPath *indexPath = [self.resourceTableView indexPathForRowAtPoint:location];
+        _longPressedIndex = indexPath.row;
+        ResourceCell *cell = [self.resourceTableView cellForRowAtIndexPath:indexPath];
+        
+        [self showMenuWithCell:cell];
+    }
+}
+
+- (void)showMenuWithCell:(ResourceCell *)cell {
+    [cell becomeFirstResponder];
+    
+    UIMenuController *controller = [UIMenuController sharedMenuController];
+    UIMenuItem *openItem = [[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Open in Safari", nil) action:@selector(openWebPage:)];
+    [controller setMenuItems:[NSArray arrayWithObjects:openItem, nil]];
+    [controller setTargetRect:cell.contentView.frame inView:cell.contentView];
+    [controller setMenuVisible:YES animated:YES];
+}
+
+- (void)openWebPage:(id)sender {
+    if (_longPressedIndex >= self.model.webApps.children.count) {
+        ANError(@"Index (%zi) is out range of web apps count.", _longPressedIndex);
+        return;
+    }
+    
+    WebApp *app = [self.model.webApps.children objectAtIndex:_longPressedIndex];
+    if (app.type == APP_TYPE_WEBAPP) {
+        [[UIApplication sharedApplication] openURL:app.url];
+    }
+}
+
+#pragma mark - TimerRuleDelegate
+- (void)shouldSignOut {
+    [self logoutSilently];
+}
+
+#pragma mark - UITableViewDelegate
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    if ([tableView isEqual:self.resourceTableView]) {
+        [self.resourceTableView deselectRowAtIndexPath:indexPath animated:YES];
+        
+        NSInteger totalSections = [self totalSections];
+        NSInteger section = indexPath.section;
+        NSArray *children = nil;
+        
+        __weak typeof(self) weakSelf = self;
+        children = [self getCellInfoInSection:section
+                                 totalSection:totalSections
+                                       object:indexPath
+                                      action1:^id(id param) {
+                                          __strong typeof(weakSelf) strongSelf = weakSelf;
+                                          return [strongSelf didSelectWebAppAtIndexPath:indexPath];
+                                      }
+                                      action2:^id(id param) {
+                                          __strong typeof(weakSelf) strongSelf = weakSelf;
+                                          return [strongSelf didSelectNativeAppAtIndexPath:indexPath];
+                                      }
+                                      action3:^id(id param) {
+                                          __strong typeof(weakSelf) strongSelf = weakSelf;
+                                          return [strongSelf didSelectDesktopAtIndexPath:indexPath];
+                                      }];
+        
+        if (children != nil) {
+            [self performSegueWithIdentifier:kSegueToSubResource sender:children];
+        }
+    } else if ([tableView isEqual:self.acsModeTableView]) {
+        [self.acsModeTableView deselectRowAtIndexPath:indexPath animated:YES];
+        if ([self.acsDescList count] > 0) {
+            [self performSegueWithIdentifier:kSegueToAccessModeSelect sender:self];
+        }
+    }
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    if ([tableView isEqual:self.resourceTableView]) {
+        return 39;
+    } 
+    
+    return 0;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
+    if ([tableView isEqual:self.resourceTableView]) {
+        static CGFloat kDefaultCellHeight = 44.0;
+        static CGFloat kNativeCellHeight = 66.0;
+        NSInteger section = indexPath.section;
+        NSInteger totalSections = [self totalSections];
+        
+        NSNumber *result = [self getCellInfoInSection:section
+                                         totalSection:totalSections
+                                               object:nil
+                                              action1:^id(id param) {
+                                                  return [NSNumber numberWithFloat:kDefaultCellHeight];
+                                              }
+                                              action2:^id(id param) {
+                                                  return [NSNumber numberWithFloat:kNativeCellHeight];
+                                              }
+                                              action3:^id(id param) {
+                                                  return [NSNumber numberWithFloat:kDefaultCellHeight];
+                                              }];
+        
+        return [result integerValue];
+    } else if ([tableView isEqual:self.acsModeTableView]) {
+        return 44;
+    }
+    
+    return 0;
+}
+
+#pragma mark - Helper
+typedef id (^Action)(id param);
+
+- (id)getCellInfoInSection:(NSInteger)section
+              totalSection:(NSInteger)totalSection
+                    object:(id)object
+                   action1:(Action)action1
+                   action2:(Action)action2
+                   action3:(Action)action3 {
+    id result = nil;
+    
+    switch (totalSection) {
+        case kResourceSectionOne: {
+            if ([self isWebAppToShow]) {
+                result = action1(object);
+            } else if ([self isNativeAppToShow]) {
+                result = action2(object);
+            } else if ([self isDesktopToShow]) {
+                result = action3(object);
+            }
+            break;
+        }
+        case kResourceSectionTwo:
+            if ([self isWebAppToShow]) {
+                if ([self isNativeAppToShow]) {
+                    if (section == kResourceSectionIndex0) {
+                        result = action1(object);
+                    } else if (section == kResourceSectionIndex1) {
+                        result = action2(object);
+                    }
+                } else if ([self isDesktopToShow]) {
+                    if ([self isDesktopToShow]) {
+                        if (section == kResourceSectionIndex0) {
+                            result = action1(object);
+                        } else if (section == kResourceSectionIndex1) {
+                            result = action3(object);
+                        }
+                    }
+                }
+            } else if ([self isNativeAppToShow]) {
+                if ([self isDesktopToShow]) {
+                    if (section == kResourceSectionIndex0) {
+                        result = action2(object);
+                    } else if (section == kResourceSectionIndex1) {
+                        result = action3(object);
+                    }
+                }
+            }
+            break;
+        case kResourceSectionThree:
+            if (section == kResourceSectionIndex0) {
+                result = action1(object);
+            } else if (section == kResourceSectionIndex1) {
+                result = action2(object);
+            } else if (section == kResourceSectionIndex2) {
+                result = action3(object);
+            }
+            break;
+            
+        default:
+            ANError(@"Invalid sections number of (%zi) received.", section);
+            break;
+    }
+    
+    return result;
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ResourcesViewController.m.InfosecStore
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ResourcesViewController.m.InfosecStore	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ResourcesViewController.m.InfosecStore	(working copy)
@@ -0,0 +1,1308 @@
+//
+//  ResourcesViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/27.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "ANLogger.h"
+#import "AAAManager.h"
+#import "AppManager.h"
+#import "GCustomItem.h"
+#import "PubAppItem.h"
+#import "FBKVOController.h"
+#import "ArrayVPNWrapper.h"
+#import "ANPopupDialog.h"
+#import "GatewayManager.h"
+#import "CertificateManager.h"
+#import "ConfigurationManager.h"
+#import "RulesManager.h"
+#import "ResourceCell.h"
+#import "MJRefresh.h"
+#import "NativeAppCell.h"
+#import "AutoLoginHandler.h"
+#import "SubResourceViewController.h"
+#import "UIView+Toast.h"
+#import "ResourcesViewController.h"
+#import "AccessModeCell.h"
+#import "AccessModeSelectViewController.h"
+#import "ZTWKWebViewController.h"
+
+static NSString * const kSegueToSubResource = @"ResourceToSubResource";
+static NSString * const kSegueToCustomDesktop = @"ResourceToCustomDesktop";
+static NSString * const kSegueToAccessModeSelect = @"ResourceToAccessModeSelect";
+
+#if TARGET_OS_IPHONE
+NSString * const kAppGroupNameResource = @"group.net.infosec.MotionPro";
+NSString * const kArrayVPNTunelErrorMsgResource = @"net.arraynetworks.sslvpn.errormsg";
+#elif TARGET_OS_MAC
+NSString * const kAppGroupNameResource = @"5VZLZ3YQ9P.net.arraynetworks.MacTunnel";
+#endif
+
+typedef NS_ENUM(NSInteger, ResourceSectionNumber) {
+    kResourceSectionZero = 0,
+    kResourceSectionOne,
+    kResourceSectionTwo,
+    kResourceSectionThree
+};
+
+typedef NS_ENUM(NSInteger, ResourceSectionIndex) {
+    kResourceSectionIndex0 = 0,
+    kResourceSectionIndex1,
+    kResourceSectionIndex2
+};
+
+@interface ResourcesViewController () <TimerRuleDelegate, AcsModeSelectControllerDelegate> {
+    NSInteger _longPressedIndex;
+}
+
+@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator;
+@property (weak, nonatomic) IBOutlet UILabel *statusLabel;
+@property (weak, nonatomic) IBOutlet UISwitch *vpnEnableSwitch;
+@property (weak, nonatomic) IBOutlet UIImageView *statusImageView;
+
+@property (weak, nonatomic) IBOutlet UIView *messageView;
+@property (weak, nonatomic) IBOutlet UILabel *messageLabel;
+
+@property (weak, nonatomic) IBOutlet UIView *emptyResourceView;
+@property (weak, nonatomic) IBOutlet UIImageView *emptyResourceImageView;
+@property (weak, nonatomic) IBOutlet UILabel *emptyResourceLabel;
+
+@property (weak, nonatomic) IBOutlet UITableView *resourceTableView;
+
+@property (weak, nonatomic) IBOutlet UITableView *acsModeTableView;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *resourceViewTopConstraint;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *emptyViewTopConstraint;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *messageViewTopConstraint;
+
+@property (strong, nonatomic) AppManager *model;
+@property (strong, nonatomic) NSArray *desktops;  // As a cache
+
+@property (strong, nonatomic) NSArray *acsDescList;
+@property (strong, nonatomic) NSArray *acsNameList;
+@property (strong, nonatomic) NSString *acsSelectedInfo;
+
+
+@property (strong, nonatomic) id browser;
+
+// For DesktopDirect
+@property (nonatomic, strong) NSIndexPath *currentIndex;
+@property (nonatomic, strong) ResourceItem *currentItem;
+@property (nonatomic, strong) FBKVOController *kvoController;
+@property (nonatomic, strong) UIControl *darkView;
+@property (nonatomic) BOOL silence;
+@property (nonatomic) BOOL needReconnect;
+
+@end
+
+@implementation ResourcesViewController
+
+@synthesize desktops = _desktops;
+
+- (void)dealloc {
+#if TARGET_OS_IPHONE
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:kArrayVPNTunelErrorMsgResource object:nil];
+#endif
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    self.model = [AppManager sharedInstance];
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(handleVPNStatus:)
+                                                 name:kArrayVPNStatusNotification
+                                               object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(handleAutoLogout:)
+                                                 name:kAutoLogoutNotification
+                                               object:nil];
+    
+    [self setVPNStatusAsDisconnected];
+    [self autoStartVPN];
+    [self doPostLoginCV];
+    
+    [self initKVOController];
+    
+    [self initTopView];
+    [self initAccessModeView];
+    [self initPullToRefresh];
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [super viewWillDisappear:animated];
+    
+    self.silence = YES;
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    
+    self.silence = NO;
+}
+
+- (void)viewDidAppear:(BOOL)animated {
+    [super viewDidAppear:animated];
+    
+    RulesManager *manager = [RulesManager sharedInstance];
+    if (manager.didEndSession) {
+        manager.didEndSession = NO;
+        
+        [self logoutSilently];
+    }
+}
+
+- (void)initAccessModeView {
+    BOOL bShowAcsModeView = NO;
+    
+    self.acsSelectedInfo = nil;
+    self.acsDescList = [AAAManager sharedInstance].acsModeDesc;
+    self.acsNameList = [AAAManager sharedInstance].acsModeName;
+    if (self.acsDescList != nil) {
+        bShowAcsModeView = YES;
+    }
+    
+    if (bShowAcsModeView) {
+        self.acsModeTableView.hidden = NO;
+        self.resourceViewTopConstraint.constant = 95;
+        self.emptyViewTopConstraint.constant = 100;
+        self.messageViewTopConstraint.constant = 100;
+        self.acsModeTableView.tableHeaderView = [[UIView alloc]initWithFrame:CGRectMake(0,0,0,0.01)];
+    } else {
+        self.acsModeTableView.hidden = YES;
+        self.resourceViewTopConstraint.constant = 45;
+        self.emptyViewTopConstraint.constant = 50;
+        self.messageViewTopConstraint.constant = 50;
+    }
+    
+    self.needReconnect = NO;
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (IBAction)exitButtonClicked:(id)sender {
+    __weak typeof(self) weakSelf = self;
+    PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+                                                                   message:NSLocalizedString(@"Would you like to sign out?", nil)
+                                                             confirmAction:^{
+                                                                 [weakSelf stopVPNAndLogout:NO];
+                                                             }
+                                                              cancelAction:nil];
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (IBAction)vpnEnableSwitched:(id)sender {
+    if (self.vpnEnableSwitch.on) {
+        BOOL ret = [self startVPN:NO];
+        if (!ret) {
+            [self setVPNStatusAsError:NSLocalizedString(@"Can't start VPN.", nil)];
+        }
+    } else {
+        [self stopVPN];
+    }
+}
+
+- (void)initTopView {
+    [self.acsModeTableView registerNib:[UINib nibWithNibName:@"AccessModeCell" bundle:nil] forCellReuseIdentifier:kAccessModeCellID];
+    if (self.model.isEmpty) {
+        [self showEmptyResouceView];
+    } else {
+        [self showResourceTableView];
+        [self.resourceTableView registerNib:[UINib nibWithNibName:@"ResourceCell" bundle:nil] forCellReuseIdentifier:kResourceCellID];
+        [self.resourceTableView registerNib:[UINib nibWithNibName:@"NativeAppCell" bundle:nil] forCellReuseIdentifier:kNativeAppCellID];
+    }
+}
+
+- (void)initPullToRefresh {
+    __weak typeof(self) weakSelf = self;
+    self.resourceTableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
+        __strong typeof(weakSelf) strongSelf = weakSelf;
+        [strongSelf endRefresh];
+        
+        Gateway *currentGateway = [self getCurrentGateway];
+        if (currentGateway) {
+            [[AppManager sharedInstance] fetchAppsFromServer:currentGateway.host
+                                                        port:currentGateway.port
+                                                  completion:^(BOOL isNeedUpdate) {
+                                                      [strongSelf.resourceTableView reloadData];
+                                                  }];
+        }
+    }];
+}
+
+- (void)endRefresh{
+    [self.resourceTableView.mj_header endRefreshing];
+}
+
+- (void)doPostLoginCV {
+    [[RulesManager sharedInstance] setDelegate:self];
+    
+    /**
+     * It may not be a reliable way to do post login Client Verification.
+     * Maybe we should listen to the VPN_CB_CV_USER message.
+     */
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{
+        RulesManager *manager = [RulesManager sharedInstance];
+        [manager cleanTimerRuleInteraction];
+        [manager kickoffTimerRules];
+    });
+    
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{
+        [[RulesManager sharedInstance].interactionHandler takeAction];
+    });
+}
+
+- (void)initKVOController {
+    self.kvoController = [FBKVOController controllerWithObserver:self];
+}
+
+#pragma mark - Access Mode
+
+- (NSArray *)cellsForTableView:(UITableView *)tableView
+{
+    NSInteger sections = tableView.numberOfSections;
+    NSMutableArray *cells = [[NSMutableArray alloc]  init];
+    for (int section = 0; section < sections; section++) {
+        NSInteger rows =  [tableView numberOfRowsInSection:section];
+        for (int row = 0; row < rows; row++) {
+            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
+            [cells addObject:[tableView cellForRowAtIndexPath:indexPath]];
+        }
+    }
+    return cells;
+}
+
+- (int)switchAccessMode:(NSString *)acsDesc {
+    int ret = ERROR_ACM_SUCCESS;
+    BOOL isMatchDesc = NO;
+    
+    if ([self.acsDescList count] == [self.acsNameList count]) {
+        for (NSUInteger i =0; i < [self.acsDescList count]; i++) {
+            if ([[self.acsDescList objectAtIndex:i] isEqualToString:acsDesc]) {
+                isMatchDesc = YES;
+                ret = array_vpn_access_mode_set([[self.acsNameList objectAtIndex:i] UTF8String], NULL, NULL, 0);
+                break;
+            }
+        }
+    }
+    
+    if (!isMatchDesc) {
+        ANError(@"switchAccessMode: get match access mode message failed, switch failed return error.");
+        ret = ERROR_ACM_UNDEFINE;
+    }
+    
+    return ret;
+}
+
+- (void)accessModeRestartVPN{
+    BOOL ret = [self startVPN:NO];
+    if (!ret) {
+        [self setVPNStatusAsError:NSLocalizedString(@"Can't start VPN.", nil)];
+    }
+    
+    NSArray *cells = [self cellsForTableView:self.acsModeTableView];
+    if ([cells count] == 1) {
+        AccessModeCell *cell = (AccessModeCell *)[cells objectAtIndex:0];
+        [cell showActiveView:NO];
+        [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+    }
+}
+
+- (void)didFinishSelect:(NSString *)selectAcsDesc {
+    NSArray *cells = [self cellsForTableView:self.acsModeTableView];
+    if ([cells count] == 1) {
+        AccessModeCell *cell = (AccessModeCell *)[cells objectAtIndex:0];
+        NSString *currentAcsDesc = [cell getCellText];
+        if ([selectAcsDesc length] > 0) {
+            if ([currentAcsDesc isEqualToString:selectAcsDesc]) {
+                ANInfo(@"didFinishSelect: user select same access mode ,do nothing.");
+            } else {
+                ANInfo(@"didFinishSelect: user select access mode[%@]", selectAcsDesc);
+                [cell setCellText:selectAcsDesc];
+                [cell showActiveView:YES];
+                [cell setCellImage:ACCESS_MODE_IMAGE_INACTIVE_NAME];
+                dispatch_async(dispatch_get_main_queue(), ^{
+                    int ret = [self switchAccessMode:selectAcsDesc];
+                    NSString *errorMessage = nil;
+                    switch (ret) {
+                        case ERROR_ACM_SUCCESS:
+                            ANInfo(@"didFinishSelect:switch access mode successfully.");
+                            [cell showActiveView:NO];
+                            [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+                            break;
+                        case ERROR_ACM_SUCCESS_RECONN:
+                            ANInfo(@"didFinishSelect:switch access mode successfully.");
+                            ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+                            if (tunnelStatus == ArrayVPNConnected) {
+                                ANInfo(@"didFinishSelect:vpn status is connected, need reconnect.");
+                                self.needReconnect = YES;
+                                [self stopVPN];
+                            } else {
+                                [cell showActiveView:NO];
+                                [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+                            }
+                            break;
+                        case ERROR_ACM_WITHOUT_SESSION:
+                            errorMessage = NSLocalizedString(@"Switching failure: invalid user session. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_NAME_INVALID:
+                            errorMessage = NSLocalizedString(@"Switching failure: illegal mode information. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_NAME_NONE:
+                            errorMessage = NSLocalizedString(@"Switching failure: mode information does not exist. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_INVALID_PARAMETER:
+                            errorMessage = NSLocalizedString(@"Switching failure: incorrect parameter. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_ACL_CHANGE_FAILED:
+                            errorMessage = NSLocalizedString(@"Switching failure: the server fails to switch. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_NETWORK:
+                            errorMessage = NSLocalizedString(@"Switching failure: network error. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_UNDEFINE:
+                            errorMessage = NSLocalizedString(@"Switching failure: unknown error. Please switch again or contact the administrator.", nil);
+                            break;
+                        default:
+                            errorMessage = NSLocalizedString(@"Switching failure: unknown error. Please switch again or contact the administrator.", nil);
+                            break;
+                    }
+                    if (errorMessage && errorMessage.length > 0) {
+                        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error",nil) message:errorMessage];
+                        [self presentViewController:dialog animated:YES completion:nil];
+                        [cell showActiveView:NO];
+                        [cell setCellText:currentAcsDesc];
+                        [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+                    } else {
+                        for (NSString *info in self.acsDescList) {
+                            if ([selectAcsDesc isEqualToString:info]) {
+                                self.acsSelectedInfo = info;
+                            }
+                        }
+                    }
+                    ANInfo(@"didFinishSelect:switch access mode finished, select access mode=%@.", self.acsSelectedInfo);
+                });
+            }
+        }
+    }
+}
+
+#pragma mark - Auto Logout
+- (void)handleAutoLogout:(NSNotification *)notification {
+    [self logoutSilently];
+}
+
+- (void)clearCookies {  // ANsession should be cleared on logout. (for WebAuth)
+#define MP_SESSION_PREFIX   @"ANsession"
+#define MP_USERNAME_COOKIE  @"username"
+#define MP_ACCESS_NAME      @"acs_mode"
+#define MP_ACCESS_DESC      @"acs_desc"
+    
+    NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
+    NSArray *cookies = cookieJar.cookies;
+    for (NSHTTPCookie *cookie in cookies) {
+        if (cookie.name) {
+            if ([cookie.name isEqualToString:MP_USERNAME_COOKIE] ||[cookie.name containsString:MP_SESSION_PREFIX] || [cookie.name containsString:MP_ACCESS_NAME] || [cookie.name containsString:MP_ACCESS_DESC]) {
+                [cookieJar deleteCookie:cookie];
+            }
+        }
+    }
+}
+
+#pragma mark - VPN Status
+#define STATUS_LABEL_COLOR_NORMAL   UIColorFromRGBA(0x666666, 1.0)
+#define STATUS_LABEL_COLOR_WARNING  UIColorFromRGBA(0xff0000, 1.0)
+#define STATUS_LABEL_COLOR_GREEN    UIColorFromRGBA(0x42a009, 1.0)
+
+- (void)setVPNStatusAsConnecting {
+    self.activityIndicator.hidden = NO;
+    [self.activityIndicator startAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_NORMAL;
+    self.statusLabel.text = NSLocalizedString(@"Connecting...", nil);
+    self.statusImageView.hidden = YES;
+    self.vpnEnableSwitch.on = YES;
+    [self showMessageViewWithInfo:nil];
+}
+
+- (void)setVPNSStatusAsConnected {
+    [self.activityIndicator stopAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_GREEN;
+    self.statusLabel.text = NSLocalizedString(@"Connected", nil);
+    self.statusImageView.image = [UIImage imageNamed:@"ResourceConnectSuccess"];
+    self.statusImageView.hidden = NO;
+    self.vpnEnableSwitch.on = YES;
+    [self showMessageViewWithInfo:nil];
+}
+
+- (void)setVPNStatusAsDisconnected {
+    [self.activityIndicator stopAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_NORMAL;
+    self.statusLabel.text = NSLocalizedString(@"Disconnected", nil);
+    self.statusImageView.image = [UIImage imageNamed:@"ResourceConnectError"];
+    self.statusImageView.hidden = NO;
+    self.vpnEnableSwitch.on = NO;
+    [self showMessageViewWithInfo:nil];
+    if (self.needReconnect) {
+        ANInfo(@"access mode disconnect vpn finished, now need restart vpn.");
+        self.needReconnect = NO;
+        [self accessModeRestartVPN];
+    }
+}
+
+- (void)setVPNStatusAsDisconnecting {
+    [self.activityIndicator startAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_NORMAL;
+    self.statusLabel.text = NSLocalizedString(@"Disconnecting...", nil);
+    self.statusImageView.hidden = YES;
+    self.vpnEnableSwitch.on = NO;
+    [self showMessageViewWithInfo:nil];
+}
+
+- (void)setVPNStatusAsError:(NSString *)errorMessage {
+    [self.activityIndicator stopAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_WARNING;
+    self.statusLabel.text = NSLocalizedString(@"Connect failed", nil);
+    self.statusImageView.image = [UIImage imageNamed:@"ResourceConnectError"];
+    self.statusImageView.hidden = NO;
+    self.vpnEnableSwitch.on = NO;
+    [self showMessageViewWithInfo:errorMessage];
+}
+
+- (void)showMessageViewWithInfo:(NSString *)info {
+    if (info) {
+        self.messageLabel.text = info;
+        self.messageView.hidden = NO;
+    } else {
+        self.messageLabel.text = @"";
+        self.messageView.hidden = YES;
+    }
+}
+
+- (void)showEmptyResouceView {
+    self.emptyResourceView.hidden = NO;
+    self.resourceTableView.hidden = YES;
+    [self.view bringSubviewToFront:self.emptyResourceView];
+}
+
+- (void)showResourceTableView {
+    self.emptyResourceView.hidden = YES;
+    self.resourceTableView.hidden = NO;
+    [self.view bringSubviewToFront:self.resourceTableView];
+}
+
+#pragma mark - VPN Related
+- (BOOL)autoStartVPN {
+    BOOL isAutoStart = NO;
+    Gateway *gateway = [self getCurrentGateway];
+    
+    if (!gateway) {
+        isAutoStart = YES;
+        ANInfo(@"No gateway is selected, it is auto start vpn.");
+    } else {
+        if (!gateway.isSecureTunnelEnabled) {
+            ANInfo(@"Auto start VPN is not enabled.");
+            return NO;
+        }
+    }
+
+    return [self startVPN:isAutoStart];
+}
+
+- (BOOL)startVPN:(BOOL)isAutoStart {
+    //Gateway *gateway = [self getCurrentGateway];
+    //NSString *session = [AAAManager sharedInstance].sessionID;
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    
+#if TARGET_OS_IPHONE
+    //Reset connect fail reason.
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameResource];
+    [userDefaults removeObjectForKey:@"tunnel_result"];
+    [userDefaults removeObjectForKey:@"dns_list"];
+#endif
+    
+    [vpnWrapper startSSLVPN];
+    
+#if TARGET_OS_IPHONE
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleVPNTunnelError:)
+                                                 name:kArrayVPNTunelErrorMsgResource object:nil];
+#endif
+    
+    return YES;
+    
+//    if (isAutoStart) {
+//        [vpnWrapper startSSLVPN];
+//    }
+//
+//    return [vpnWrapper validateSessionWithHost:gateway.host
+//                                          port:gateway.port
+//                                       session:session
+//                                    completion:^(BOOL isSuccess, NSError *error) {
+//                                        if (isSuccess) {
+//                                            [vpnWrapper startSSLVPN];
+//                                        } else {
+//                                            NSString *message = NSLocalizedString(@"Session is invalid, please login again!", nil);
+//                                            PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+//                                                                                                          message:message
+//                                                                                                           action:^{
+//                                                                                                               [[NSNotificationCenter defaultCenter]
+//                                                                                                                postNotificationName:kAutoLogoutNotification
+//                                                                                                                object:nil];
+//                                                                                                           }];
+//                                            [self presentViewController:dialog animated:YES completion:nil];
+//                                        }
+//                                    }];
+}
+
+- (void)stopVPN {
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    [vpnWrapper stopSSLVPN];
+}
+
+- (void)stopVPNAndLogout:(BOOL)isSilent {
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{  // Stop timer rules fisrt.
+        [[RulesManager sharedInstance] stopAllRules];
+    });
+    
+    AAAManager *manager = [AAAManager sharedInstance];
+    [manager continueVPNThreadWithAccount:nil];
+    [self stopVPN];
+    
+    [self clearCookies];
+    
+    if (!isSilent) {
+        __weak typeof(self) weakSelf = self;
+        [self.view makeToastActivity:CSToastPositionCenter];
+        dispatch_async(dispatch_get_global_queue(0, 0), ^{
+            NSInteger ret = [[AAAManager sharedInstance] stopL3VPNDirectly];
+            if (ret != ERR_SUCCESS) {
+                ANError(@"Logout failed with error code: %zi.", ret);
+            }
+            
+            __strong typeof(weakSelf) strongSelf = weakSelf;
+            dispatch_async(dispatch_get_main_queue(), ^{
+                [strongSelf.view hideToastActivity];
+                [strongSelf dismissViewControllerAnimated:YES completion:nil];
+            });
+        });
+    }
+}
+
+- (void)logoutSilently {
+    [self stopVPNAndLogout:YES];
+    
+    [self.navigationController dismissViewControllerAnimated:NO completion:nil];  // Dismiss modal view if exists.
+    [self dismissViewControllerAnimated:YES completion:nil];
+}
+
+- (Gateway *)getCurrentGateway {
+    VPNAccount *account = [AAAManager sharedInstance].account;
+    GatewayManager *gm = [GatewayManager sharedInstance];
+    NSString *url = account.vsURL;
+    NSString *port = account.vsPort;
+    NSInteger index = [gm indexOfUrl:url andport:port];
+    
+    return [gm gatewayAtIndex:index];
+}
+
+#pragma mark - VPN Status Handler
+- (void)handleVPNStatus:(NSNotification *)notification {
+    ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+    
+    ANDebug(@"Array VPN tunnel status = %zi", tunnelStatus);
+    
+    [self updateUIWithVPNStatus:tunnelStatus];
+}
+
+- (void)updateUIWithVPNStatus:(ArrayVPNStatus)status {
+    switch (status) {
+        case ArrayVPNInavlid:
+        case ArrayVPNDisconnected:
+            [self setVPNStatusAsDisconnected];
+            break;
+        case ArrayVPNDisconnecting:
+            [self setVPNStatusAsDisconnecting];
+            break;
+        case ArrayVPNConnecting:
+        case ArrayVPNReasserting:
+            [self setVPNStatusAsConnecting];
+            break;
+        case ArrayVPNConnected:
+            [self setVPNSStatusAsConnected];
+            break;
+            
+        default:
+            break;
+    }
+}
+
+- (void)handleVPNTunnelError:(NSNotification *)notification {
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    NSString *errMessage = [vpnWrapper getErrorMsgWithCode];
+    if (errMessage && errMessage.length > 0) {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:errMessage];
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+#pragma mark - Number of Sections & Rows
+- (BOOL)isWebAppToShow {
+    PortalTabsConfiguration *portalConfiguration = [ConfigurationManager sharedInstance].portalTabs;
+    
+    return portalConfiguration.isWebAppConfigured && self.model.webApps.children.count > 0;
+}
+
+- (BOOL)isNativeAppToShow {
+    PortalTabsConfiguration *portalConfiguration = [ConfigurationManager sharedInstance].portalTabs;
+    
+    return portalConfiguration.isNativeAppConfigured && self.model.nativeApps.children.count > 0;
+}
+
+- (BOOL)isDesktopToShow {
+    PortalTabsConfiguration *portalConfiguration = [ConfigurationManager sharedInstance].portalTabs;
+    
+    return portalConfiguration.isDesktopConfigured && self.model.desktopApps.resourceItems.count > 0;
+}
+
+- (NSInteger)totalSections {
+    NSInteger totalSections = 0;
+    NSInteger webSection = [self isWebAppToShow] ? 1 : 0;
+    NSInteger nativeSection = [self isNativeAppToShow] ? 1 : 0;
+    NSInteger desktopSection = [self isDesktopToShow] ? 1 : 0;
+    
+    totalSections = webSection + nativeSection + desktopSection;
+    
+    return totalSections;
+}
+
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([segue.identifier isEqualToString:kSegueToSubResource]) {
+        SubResourceViewController *viewController = segue.destinationViewController;
+        [viewController setupModel:(NSArray *)sender];
+    }
+    if ([segue.identifier isEqualToString:kSegueToAccessModeSelect]) {
+        NSArray *cells = [self cellsForTableView:self.acsModeTableView];
+        if ([cells count] == 1) {
+            UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
+            AccessModeSelectViewController *controller = (AccessModeSelectViewController *)navController.topViewController;
+            controller.selectedAcsModeString = self.acsSelectedInfo;
+            controller.delegate = self;
+        }
+    }
+}
+
+#pragma mark - Get Child at Index
+- (NSArray *)didSelectWebAppAtIndexPath:(NSIndexPath *)indexPath {
+    NSInteger row = indexPath.row;
+    
+    if (row >= self.model.webApps.children.count) {
+        ANError(@"Index (%zi) is out range of web apps count.", row);
+        return nil;
+    }
+    
+    WebApp *app = [self.model.webApps.children objectAtIndex:row];
+    if (app.type == APP_TYPE_WEBAPP) {
+        ZTWKWebViewController *control = [[ZTWKWebViewController alloc] init];
+        control.webUrl = [app.url absoluteString];
+        [self.navigationController pushViewController:control animated:YES];
+
+        
+        return nil;
+    }
+    
+    return app.children;
+}
+
+- (NSArray *)didSelectNativeAppAtIndexPath:(NSIndexPath *)indexPath {
+    NSInteger row = indexPath.row;
+    
+    if (row >= self.model.nativeApps.children.count) {
+        ANError(@"Index (%zi) is out range of native apps count.", row);
+        return nil;
+    }
+    
+    NativeApp *app = [self.model.nativeApps.children objectAtIndex:row];
+    NSURL *url = [NSURL URLWithString:app.scheme];
+    if (url.scheme == nil) {
+        url = [NSURL URLWithString:[NSString stringWithFormat:@"%@://", app.scheme]];
+    }
+    
+    ANInfo(@"open app url=%@", url);
+    if (!OpenURL(url)) {
+        BOOL isAppStoreApp = (app.installUrl != nil);
+        if (!isAppStoreApp) {
+            NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Application %@ has not been installed, Would you like to search it on App Store?", nil), app.name];
+            PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:@""
+                                                                           message:message
+                                                                     confirmAction:^{
+                                                                         NSString *string = [NSString stringWithFormat:APPSTORE_SEARCH_STRING,
+                                                                                             [app.name stringByAddingPercentEncodingWithAllowedCharacters:
+                                                                                              NSCharacterSet.URLQueryAllowedCharacterSet]];
+                                                                         OpenURL([NSURL URLWithString:string]);
+                                                                     }
+                                                                      cancelAction:nil];
+            
+            [self presentViewController:dialog animated:YES completion:nil];
+        } else {
+            ANError(@"appstore client don't support this case any more.");
+        }
+    }
+    
+    return nil;
+}
+
+- (NSArray *)didSelectDesktopAtIndexPath:(NSIndexPath *)indexPath {
+    NSInteger row = indexPath.row;
+    
+    if (row >= self.model.desktopApps.resourceItems.count) {
+        ANError(@"Index (%zi) is out range of desktop apps count.", row);
+        return nil;
+    }
+    
+    FolderItem *item = [self.desktops objectAtIndex:row];
+    if ([item isKindOfClass:[GCustomItem class]] && [item.name isEqualToString:NSLocalizedString(@"Other", nil)]) {
+        [self performSegueWithIdentifier:kSegueToCustomDesktop sender:self];
+        return nil;
+    } else if ([item isKindOfClass:[HostItem class]]) {
+        [self didSelectHostItem:(HostItem *)item atIndexPath:indexPath];
+        return nil;
+    }
+    
+    return [self getSortedArray:[item.resourceItems allValues]];
+}
+
+#pragma mark - DesktopDirect
+- (void)didSelectHostItem:(HostItem *)hostItem atIndexPath:(NSIndexPath *)indexPath {
+    if (self.currentIndex
+        && self.currentIndex.row == indexPath.row
+        && hostItem.status < ResourceStatusReady) {
+        return;
+    }
+    
+    self.currentIndex = indexPath;
+    self.currentItem = hostItem;
+    
+    ResourceCell *cell = (ResourceCell *)[self.resourceTableView cellForRowAtIndexPath:indexPath];
+    
+    __weak typeof(self) weakSelf = self;
+    [self.kvoController observe:hostItem
+                        keyPath:@"status"
+                        options:NSKeyValueObservingOptionNew
+                          block:^(ResourcesViewController *observer, HostItem *host, NSDictionary *change) {
+                              NSInteger hostStatus = host.status;
+                              dispatch_async(dispatch_get_main_queue(), ^{
+                                  [cell updateUI:host];
+                                  if (observer.currentIndex.row != indexPath.row) {
+                                      return;
+                                  }
+                                  
+                                  if (observer.silence) {
+                                      return;
+                                  }
+                                  if (host.status == ResourceStatusReady) {
+                                      [observer.kvoController unobserve:host];
+                                      NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
+                                      AppManager *appManager = [AppManager sharedInstance];
+                                      BOOL cliEnabledNEC = NO;
+                                      NSString *enabledNEC = appManager.desktopSettings.settings[@"jp-rdp"];
+                                      if (enabledNEC && [enabledNEC isEqualToString:@"1"])
+                                          cliEnabledNEC = YES;
+                                      if (cliEnabledNEC || [userDefaults integerForKey:@"desktop_client_vendor"] == 1) {
+                                          [observer openRDClientNEC:host];
+                                      } else {
+                                          [observer openRDClient:host];
+                                      }
+                                      // Reset power state
+                                      host.powerState = HostPowerStateDown;
+                                      return;
+                                  } else if (hostStatus >= ResourceStatusFailed && hostStatus < ResourceStatusResolveHostNameFailed) {
+                                      ANError(@"Cannot connect to remote host, error code: %zi", hostStatus);
+                                      
+                                      if (hostStatus == ResourceStatusPowerDown) {
+                                          NSString *message = NSLocalizedString(@"It seems the remote host is turned off. Would you like to try and wake it up?", nil);
+                                          
+                                          PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Cannot connect to remote host", nil)
+                                                                                                         message:message
+                                                                                                   confirmAction:^{
+                                                                                                       NSInteger row = weakSelf.currentIndex.row;
+                                                                                                       HostItem *host = weakSelf.desktops[row];
+                                                                                                       [host wakeUp];
+                                                                                                   }
+                                                                                                    cancelAction:nil];
+                                          
+                                          [weakSelf presentViewController:dialog animated:YES completion:nil];
+                                          
+                                          return;
+                                      } else {
+                                          [observer.kvoController unobserve:host];
+                                      }
+                                  }
+                              });
+                          }];
+    
+    [hostItem prepare];
+}
+
+- (void)openRDClient:(HostItem *)hostItem {
+    NSURL *url = hostItem.url;
+    if (!url) {
+        return;
+    }
+    
+    if (!OpenURL(url)) {
+        NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Application %@ has not been installed, Would you like to search it on App Store?", nil), @"RD client"];
+        PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Cannot connect to remote host", nil)
+                                                                       message:message
+                                                                 confirmAction:^{
+                                                                     NSString *string = [NSString stringWithFormat:APPSTORE_SEARCH_STRING,
+                                                                                         [@"RD client" stringByAddingPercentEncodingWithAllowedCharacters:
+                                                                                          NSCharacterSet.URLQueryAllowedCharacterSet]];
+                                                                     
+                                                                     OpenURL([NSURL URLWithString:string]);
+                                                                 }
+                                                                  cancelAction:nil];
+        
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+- (void)openRDClientNEC:(HostItem *)hostItem {
+    NSURL *url = hostItem.urlVendorNEC;
+    if (!url) {
+        return;
+    }
+    
+    if (!OpenURL(url)) {
+        NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Application %@ has not been installed, Would you like to search it on App Store?", nil),@"RD"];
+        PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Cannot connect to remote host", nil)
+                                                                       message:message
+                                                                 confirmAction:^{
+                                                                     NSString *string = @"https://itunes.apple.com/jp/app/rd-v1.3/id771611106?mt=8";
+                                                                     OpenURL([NSURL URLWithString:string]);
+                                                                 }
+                                                                  cancelAction:nil];
+        
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+- (NSArray *)desktops {
+    if (!_desktops) {
+        _desktops = [self getSortedArray:[self.model.desktopApps.resourceItems allValues]];
+    }
+    
+    return _desktops;
+}
+
+- (NSArray *)getSortedArray:(NSArray *)array {
+    if (!array || array.count == 0) {
+        ANWarn(@"Empty array, should not be sorted.");
+        return nil;
+    }
+    
+    NSSortDescriptor *byClass = [NSSortDescriptor sortDescriptorWithKey:@"class" ascending:YES comparator:^NSComparisonResult(id obj1, id obj2) {
+        // Sort by class name
+        return [NSStringFromClass(obj1) compare:NSStringFromClass(obj2)];
+        
+    }];
+    
+    NSSortDescriptor *byName = [NSSortDescriptor sortDescriptorWithKey:@"name"
+                                                             ascending:YES
+                                                              selector:@selector(localizedStandardCompare:)];
+    
+    NSArray *sortDescriptors = [NSArray arrayWithObjects:byClass, byName, nil];
+    
+    return [array sortedArrayUsingDescriptors:sortDescriptors];
+}
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    if ([tableView isEqual:self.resourceTableView]) {
+        return [self totalSections];
+    } else if ([tableView isEqual:self.acsModeTableView]) {
+        return 1;
+    }
+    
+    return 0;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    if ([tableView isEqual:self.resourceTableView]) {
+        NSInteger totalSections = [self totalSections];
+        if (section > totalSections) {
+            ANError(@"Section (%zi) is larger than total sections (%zi).", section, totalSections);
+            
+            return 0;
+        }
+        
+        __weak typeof(self) weakSelf = self;
+        NSNumber *result = [self getCellInfoInSection:section
+                                         totalSection:totalSections
+                                               object:nil
+                                              action1:^id(id param) {
+                                                  __strong typeof(weakSelf) strongSelf = weakSelf;
+                                                  NSInteger rows = strongSelf.model.webApps.children.count;
+                                                  return [NSNumber numberWithInteger:rows];
+                                              }
+                                              action2:^id(id param) {
+                                                  __strong typeof(weakSelf) strongSelf = weakSelf;
+                                                  NSInteger rows = strongSelf.model.nativeApps.children.count;
+                                                  return [NSNumber numberWithInteger:rows];
+                                              }
+                                              action3:^id(id param) {
+                                                  __strong typeof(weakSelf) strongSelf = weakSelf;
+                                                  NSInteger rows = strongSelf.model.desktopApps.resourceItems.count;
+                                                  return [NSNumber numberWithInteger:rows];
+                                              }];
+        
+        return [result integerValue];
+    } else if ([tableView isEqual:self.acsModeTableView]) {
+        return 1;
+    }
+    
+    return 0;
+}
+
+- (UITableViewCell *)configureWebAppWithRow:(NSInteger)row {
+    ResourceCell *cell = [self.resourceTableView dequeueReusableCellWithIdentifier:kResourceCellID];
+    if (!cell) {
+        cell = [[ResourceCell alloc] init];
+    }
+    
+    WebApp *app = [self.model.webApps.children objectAtIndex:row];
+    UIImage *image = nil;
+    BOOL isFolder = app.type == APP_TYPE_FOLDER;
+    if (isFolder) {
+        image = [UIImage imageNamed:FOLDER_APP_IMAGE_NAME];
+    } else {
+        image = [UIImage imageNamed:WEB_APP_IMAGE_NAME];
+        UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self
+                                                                                                       action:@selector(cellLongPressed:)];
+        [cell addGestureRecognizer:longPressGesture];
+    }
+    [cell configureCellWithImage:image name:app.name isFolder:isFolder];
+    
+    return cell;
+}
+
+- (UITableViewCell *)configureNativeAppWithRow:(NSInteger)row {
+    NativeAppCell *cell = [self.resourceTableView dequeueReusableCellWithIdentifier:kNativeAppCellID];
+    if (!cell) {
+        cell = [[NativeAppCell alloc] init];
+    }
+    
+    NativeApp *app = [self.model.nativeApps.children objectAtIndex:row];
+    UIImage *image = nil;
+    if (app.customIcon) {
+        image = app.customIcon;
+    } else if (app.appIcon) {
+        image = app.appIcon;
+    } else {
+        image = [UIImage imageNamed:NATIVE_APP_IMAGE_NAME];
+    }
+    [cell configureCellWithImage:image name:app.name isFolder:NO];  // Native app doesn't support folder.
+    [cell setDescriptionContent:app.desc];
+    
+    return cell;
+}
+
+- (UITableViewCell *)configureDesktopAppWithRow:(NSInteger)row {
+    ResourceCell *cell = [self.resourceTableView dequeueReusableCellWithIdentifier:kResourceCellID];
+    if (!cell) {
+        cell = [[ResourceCell alloc] init];
+    }
+    
+    ResourceItem *item = [self.desktops objectAtIndex:row];
+    BOOL isFolder = [item isKindOfClass:[FolderItem class]];  // Only pub-app & self-defined desktop has folder.
+    BOOL isCustomDesktop = [item isKindOfClass:[GCustomItem class]];
+    if (isCustomDesktop) {
+        isFolder = YES;
+    }
+    UIImage *image = nil;
+    if (item.icon != nil) {
+        if ([item.description containsString:@"http.ico"]) {
+            image = [UIImage imageNamed:ZRT_HTTP_IMAGE_NAME];
+        } else if ([item.description containsString:@"HSValuate1.ico"]) {
+            image = [UIImage imageNamed:ZRT_HSVALUATE1_IMAGE_NAME];
+        } else if ([item.description containsString:@"HSValuate2.ico"]) {
+            image = [UIImage imageNamed:ZRT_HSVALUATE2_IMAGE_NAME];
+        } else if ([item.description containsString:@"fundclient1.ico"]) {
+            image = [UIImage imageNamed:ZRT_FUNDCLIENT1_IMAGE_NAME];
+        } else if ([item.description containsString:@"fundclient2.ico"]) {
+            image = [UIImage imageNamed:ZRT_FUNDCLIENT2_IMAGE_NAME];
+        } else {
+            image = item.icon;
+        }
+    } else {
+        image = (isFolder && !isCustomDesktop) ? [UIImage imageNamed:FOLDER_APP_IMAGE_NAME] : [UIImage imageNamed:DESKTOP_IMAGE_NAME];
+    }
+    [cell configureCellWithImage:image name:item.name isFolder:isFolder];
+    
+    return cell;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell *cell = nil;
+    if ([tableView isEqual:self.resourceTableView]) {
+        NSInteger row = indexPath.row;
+        NSInteger section = indexPath.section;
+        NSInteger totalSections = [self totalSections];
+        
+        __weak typeof(self) weakSelf = self;
+        cell = [self getCellInfoInSection:section
+                             totalSection:totalSections
+                                   object:[NSNumber numberWithInteger:row]
+                                  action1:^id(id param) {
+                                      __strong typeof(weakSelf) strongSelf = weakSelf;
+                                      NSInteger row = [(NSNumber *)param integerValue];
+                                      return [strongSelf configureWebAppWithRow:row];
+                                  }
+                                  action2:^id(id param) {
+                                      __strong typeof(weakSelf) strongSelf = weakSelf;
+                                      NSInteger row = [(NSNumber *)param integerValue];
+                                      return [strongSelf configureNativeAppWithRow:row];
+                                  }
+                                  action3:^id(id param) {
+                                      __strong typeof(weakSelf) strongSelf = weakSelf;
+                                      NSInteger row = [(NSNumber *)param integerValue];
+                                      return [strongSelf configureDesktopAppWithRow:row];
+                                  }];
+    } else if([tableView isEqual:self.acsModeTableView]) {
+        if ([self.acsDescList count] > 0) {
+            AccessModeCell *accessModeCell = [self.acsModeTableView dequeueReusableCellWithIdentifier:kAccessModeCellID];
+            if (!accessModeCell) {
+                accessModeCell = [[AccessModeCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kAccessModeCellID];
+            }
+            NSString *showAcsDesc = [self.acsDescList objectAtIndex:0];
+            if ([self.acsDescList count] > 1) {
+                showAcsDesc = [NSString stringWithFormat:@"%@...", showAcsDesc];
+            }
+            
+            [accessModeCell configureCellWithMessage:showAcsDesc isDescList:NO];
+            [accessModeCell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+            
+            return accessModeCell;
+        } else {
+            cell = [[UITableViewCell alloc] init];
+        }
+        
+    }
+    
+    return cell;
+}
+
+- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
+    NSString *title = @"";
+    if ([tableView isEqual:self.resourceTableView]) {
+        NSInteger totalSections = [self totalSections];
+
+        title = [self getCellInfoInSection:section
+                              totalSection:totalSections
+                                    object:nil
+                                   action1:^id(id param) {
+                                       return NSLocalizedString(@"Web App", nil);
+                                   }
+                                   action2:^id(id param) {
+                                       return NSLocalizedString(@"Native App", nil);
+                                   }
+                                   action3:^id(id param) {
+                                       return NSLocalizedString(@"Remote Desktop", nil);
+                                   }];
+    }
+
+    return title;
+}
+
+#pragma mark - Long press handler for WebApp
+- (void)cellLongPressed:(UIGestureRecognizer *)recognizer {
+    if (recognizer.state == UIGestureRecognizerStateBegan) {
+        CGPoint location = [recognizer locationInView:self.resourceTableView];
+        NSIndexPath *indexPath = [self.resourceTableView indexPathForRowAtPoint:location];
+        _longPressedIndex = indexPath.row;
+        ResourceCell *cell = [self.resourceTableView cellForRowAtIndexPath:indexPath];
+        
+        [self showMenuWithCell:cell];
+    }
+}
+
+- (void)showMenuWithCell:(ResourceCell *)cell {
+    [cell becomeFirstResponder];
+    
+    UIMenuController *controller = [UIMenuController sharedMenuController];
+    UIMenuItem *openItem = [[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Open in Safari", nil) action:@selector(openWebPage:)];
+    [controller setMenuItems:[NSArray arrayWithObjects:openItem, nil]];
+    [controller setTargetRect:cell.contentView.frame inView:cell.contentView];
+    [controller setMenuVisible:YES animated:YES];
+}
+
+- (void)openWebPage:(id)sender {
+    if (_longPressedIndex >= self.model.webApps.children.count) {
+        ANError(@"Index (%zi) is out range of web apps count.", _longPressedIndex);
+        return;
+    }
+    
+    WebApp *app = [self.model.webApps.children objectAtIndex:_longPressedIndex];
+    if (app.type == APP_TYPE_WEBAPP) {
+        [[UIApplication sharedApplication] openURL:app.url];
+    }
+}
+
+#pragma mark - TimerRuleDelegate
+- (void)shouldSignOut {
+    [self logoutSilently];
+}
+
+#pragma mark - UITableViewDelegate
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    if ([tableView isEqual:self.resourceTableView]) {
+        [self.resourceTableView deselectRowAtIndexPath:indexPath animated:YES];
+        
+        NSInteger totalSections = [self totalSections];
+        NSInteger section = indexPath.section;
+        NSArray *children = nil;
+        
+        __weak typeof(self) weakSelf = self;
+        children = [self getCellInfoInSection:section
+                                 totalSection:totalSections
+                                       object:indexPath
+                                      action1:^id(id param) {
+                                          __strong typeof(weakSelf) strongSelf = weakSelf;
+                                          return [strongSelf didSelectWebAppAtIndexPath:indexPath];
+                                      }
+                                      action2:^id(id param) {
+                                          __strong typeof(weakSelf) strongSelf = weakSelf;
+                                          return [strongSelf didSelectNativeAppAtIndexPath:indexPath];
+                                      }
+                                      action3:^id(id param) {
+                                          __strong typeof(weakSelf) strongSelf = weakSelf;
+                                          return [strongSelf didSelectDesktopAtIndexPath:indexPath];
+                                      }];
+        
+        if (children != nil) {
+            [self performSegueWithIdentifier:kSegueToSubResource sender:children];
+        }
+    } else if ([tableView isEqual:self.acsModeTableView]) {
+        [self.acsModeTableView deselectRowAtIndexPath:indexPath animated:YES];
+        if ([self.acsDescList count] > 0) {
+            [self performSegueWithIdentifier:kSegueToAccessModeSelect sender:self];
+        }
+    }
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    if ([tableView isEqual:self.resourceTableView]) {
+        return 39;
+    } 
+    
+    return 0;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
+    if ([tableView isEqual:self.resourceTableView]) {
+        static CGFloat kDefaultCellHeight = 44.0;
+        static CGFloat kNativeCellHeight = 66.0;
+        NSInteger section = indexPath.section;
+        NSInteger totalSections = [self totalSections];
+        
+        NSNumber *result = [self getCellInfoInSection:section
+                                         totalSection:totalSections
+                                               object:nil
+                                              action1:^id(id param) {
+                                                  return [NSNumber numberWithFloat:kDefaultCellHeight];
+                                              }
+                                              action2:^id(id param) {
+                                                  return [NSNumber numberWithFloat:kNativeCellHeight];
+                                              }
+                                              action3:^id(id param) {
+                                                  return [NSNumber numberWithFloat:kDefaultCellHeight];
+                                              }];
+        
+        return [result integerValue];
+    } else if ([tableView isEqual:self.acsModeTableView]) {
+        return 44;
+    }
+    
+    return 0;
+}
+
+#pragma mark - Helper
+typedef id (^Action)(id param);
+
+- (id)getCellInfoInSection:(NSInteger)section
+              totalSection:(NSInteger)totalSection
+                    object:(id)object
+                   action1:(Action)action1
+                   action2:(Action)action2
+                   action3:(Action)action3 {
+    id result = nil;
+    
+    switch (totalSection) {
+        case kResourceSectionOne: {
+            if ([self isWebAppToShow]) {
+                result = action1(object);
+            } else if ([self isNativeAppToShow]) {
+                result = action2(object);
+            } else if ([self isDesktopToShow]) {
+                result = action3(object);
+            }
+            break;
+        }
+        case kResourceSectionTwo:
+            if ([self isWebAppToShow]) {
+                if ([self isNativeAppToShow]) {
+                    if (section == kResourceSectionIndex0) {
+                        result = action1(object);
+                    } else if (section == kResourceSectionIndex1) {
+                        result = action2(object);
+                    }
+                } else if ([self isDesktopToShow]) {
+                    if ([self isDesktopToShow]) {
+                        if (section == kResourceSectionIndex0) {
+                            result = action1(object);
+                        } else if (section == kResourceSectionIndex1) {
+                            result = action3(object);
+                        }
+                    }
+                }
+            } else if ([self isNativeAppToShow]) {
+                if ([self isDesktopToShow]) {
+                    if (section == kResourceSectionIndex0) {
+                        result = action2(object);
+                    } else if (section == kResourceSectionIndex1) {
+                        result = action3(object);
+                    }
+                }
+            }
+            break;
+        case kResourceSectionThree:
+            if (section == kResourceSectionIndex0) {
+                result = action1(object);
+            } else if (section == kResourceSectionIndex1) {
+                result = action2(object);
+            } else if (section == kResourceSectionIndex2) {
+                result = action3(object);
+            }
+            break;
+            
+        default:
+            ANError(@"Invalid sections number of (%zi) received.", section);
+            break;
+    }
+    
+    return result;
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ResourcesViewController.m.MotionPro
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ResourcesViewController.m.MotionPro	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ResourcesViewController.m.MotionPro	(working copy)
@@ -0,0 +1,1308 @@
+//
+//  ResourcesViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/27.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "ANLogger.h"
+#import "AAAManager.h"
+#import "AppManager.h"
+#import "GCustomItem.h"
+#import "PubAppItem.h"
+#import "FBKVOController.h"
+#import "ArrayVPNWrapper.h"
+#import "ANPopupDialog.h"
+#import "GatewayManager.h"
+#import "CertificateManager.h"
+#import "ConfigurationManager.h"
+#import "RulesManager.h"
+#import "ResourceCell.h"
+#import "MJRefresh.h"
+#import "NativeAppCell.h"
+#import "AutoLoginHandler.h"
+#import "SubResourceViewController.h"
+#import "UIView+Toast.h"
+#import "ResourcesViewController.h"
+#import "AccessModeCell.h"
+#import "AccessModeSelectViewController.h"
+#import "ZTWKWebViewController.h"
+
+static NSString * const kSegueToSubResource = @"ResourceToSubResource";
+static NSString * const kSegueToCustomDesktop = @"ResourceToCustomDesktop";
+static NSString * const kSegueToAccessModeSelect = @"ResourceToAccessModeSelect";
+
+#if TARGET_OS_IPHONE
+NSString * const kAppGroupNameResource = @"group.net.arraynetworks.MotionPro";
+NSString * const kArrayVPNTunelErrorMsgResource = @"net.arraynetworks.sslvpn.errormsg";
+#elif TARGET_OS_MAC
+NSString * const kAppGroupNameResource = @"5VZLZ3YQ9P.net.arraynetworks.MacTunnel";
+#endif
+
+typedef NS_ENUM(NSInteger, ResourceSectionNumber) {
+    kResourceSectionZero = 0,
+    kResourceSectionOne,
+    kResourceSectionTwo,
+    kResourceSectionThree
+};
+
+typedef NS_ENUM(NSInteger, ResourceSectionIndex) {
+    kResourceSectionIndex0 = 0,
+    kResourceSectionIndex1,
+    kResourceSectionIndex2
+};
+
+@interface ResourcesViewController () <TimerRuleDelegate, AcsModeSelectControllerDelegate> {
+    NSInteger _longPressedIndex;
+}
+
+@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator;
+@property (weak, nonatomic) IBOutlet UILabel *statusLabel;
+@property (weak, nonatomic) IBOutlet UISwitch *vpnEnableSwitch;
+@property (weak, nonatomic) IBOutlet UIImageView *statusImageView;
+
+@property (weak, nonatomic) IBOutlet UIView *messageView;
+@property (weak, nonatomic) IBOutlet UILabel *messageLabel;
+
+@property (weak, nonatomic) IBOutlet UIView *emptyResourceView;
+@property (weak, nonatomic) IBOutlet UIImageView *emptyResourceImageView;
+@property (weak, nonatomic) IBOutlet UILabel *emptyResourceLabel;
+
+@property (weak, nonatomic) IBOutlet UITableView *resourceTableView;
+
+@property (weak, nonatomic) IBOutlet UITableView *acsModeTableView;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *resourceViewTopConstraint;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *emptyViewTopConstraint;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *messageViewTopConstraint;
+
+@property (strong, nonatomic) AppManager *model;
+@property (strong, nonatomic) NSArray *desktops;  // As a cache
+
+@property (strong, nonatomic) NSArray *acsDescList;
+@property (strong, nonatomic) NSArray *acsNameList;
+@property (strong, nonatomic) NSString *acsSelectedInfo;
+
+
+@property (strong, nonatomic) id browser;
+
+// For DesktopDirect
+@property (nonatomic, strong) NSIndexPath *currentIndex;
+@property (nonatomic, strong) ResourceItem *currentItem;
+@property (nonatomic, strong) FBKVOController *kvoController;
+@property (nonatomic, strong) UIControl *darkView;
+@property (nonatomic) BOOL silence;
+@property (nonatomic) BOOL needReconnect;
+
+@end
+
+@implementation ResourcesViewController
+
+@synthesize desktops = _desktops;
+
+- (void)dealloc {
+#if TARGET_OS_IPHONE
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:kArrayVPNTunelErrorMsgResource object:nil];
+#endif
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    self.model = [AppManager sharedInstance];
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(handleVPNStatus:)
+                                                 name:kArrayVPNStatusNotification
+                                               object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(handleAutoLogout:)
+                                                 name:kAutoLogoutNotification
+                                               object:nil];
+    
+    [self setVPNStatusAsDisconnected];
+    [self autoStartVPN];
+    [self doPostLoginCV];
+    
+    [self initKVOController];
+    
+    [self initTopView];
+    [self initAccessModeView];
+    [self initPullToRefresh];
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [super viewWillDisappear:animated];
+    
+    self.silence = YES;
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    
+    self.silence = NO;
+}
+
+- (void)viewDidAppear:(BOOL)animated {
+    [super viewDidAppear:animated];
+    
+    RulesManager *manager = [RulesManager sharedInstance];
+    if (manager.didEndSession) {
+        manager.didEndSession = NO;
+        
+        [self logoutSilently];
+    }
+}
+
+- (void)initAccessModeView {
+    BOOL bShowAcsModeView = NO;
+    
+    self.acsSelectedInfo = nil;
+    self.acsDescList = [AAAManager sharedInstance].acsModeDesc;
+    self.acsNameList = [AAAManager sharedInstance].acsModeName;
+    if (self.acsDescList != nil) {
+        bShowAcsModeView = YES;
+    }
+    
+    if (bShowAcsModeView) {
+        self.acsModeTableView.hidden = NO;
+        self.resourceViewTopConstraint.constant = 95;
+        self.emptyViewTopConstraint.constant = 100;
+        self.messageViewTopConstraint.constant = 100;
+        self.acsModeTableView.tableHeaderView = [[UIView alloc]initWithFrame:CGRectMake(0,0,0,0.01)];
+    } else {
+        self.acsModeTableView.hidden = YES;
+        self.resourceViewTopConstraint.constant = 45;
+        self.emptyViewTopConstraint.constant = 50;
+        self.messageViewTopConstraint.constant = 50;
+    }
+    
+    self.needReconnect = NO;
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (IBAction)exitButtonClicked:(id)sender {
+    __weak typeof(self) weakSelf = self;
+    PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+                                                                   message:NSLocalizedString(@"Would you like to sign out?", nil)
+                                                             confirmAction:^{
+                                                                 [weakSelf stopVPNAndLogout:NO];
+                                                             }
+                                                              cancelAction:nil];
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (IBAction)vpnEnableSwitched:(id)sender {
+    if (self.vpnEnableSwitch.on) {
+        BOOL ret = [self startVPN:NO];
+        if (!ret) {
+            [self setVPNStatusAsError:NSLocalizedString(@"Can't start VPN.", nil)];
+        }
+    } else {
+        [self stopVPN];
+    }
+}
+
+- (void)initTopView {
+    [self.acsModeTableView registerNib:[UINib nibWithNibName:@"AccessModeCell" bundle:nil] forCellReuseIdentifier:kAccessModeCellID];
+    if (self.model.isEmpty) {
+        [self showEmptyResouceView];
+    } else {
+        [self showResourceTableView];
+        [self.resourceTableView registerNib:[UINib nibWithNibName:@"ResourceCell" bundle:nil] forCellReuseIdentifier:kResourceCellID];
+        [self.resourceTableView registerNib:[UINib nibWithNibName:@"NativeAppCell" bundle:nil] forCellReuseIdentifier:kNativeAppCellID];
+    }
+}
+
+- (void)initPullToRefresh {
+    __weak typeof(self) weakSelf = self;
+    self.resourceTableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
+        __strong typeof(weakSelf) strongSelf = weakSelf;
+        [strongSelf endRefresh];
+        
+        Gateway *currentGateway = [self getCurrentGateway];
+        if (currentGateway) {
+            [[AppManager sharedInstance] fetchAppsFromServer:currentGateway.host
+                                                        port:currentGateway.port
+                                                  completion:^(BOOL isNeedUpdate) {
+                                                      [strongSelf.resourceTableView reloadData];
+                                                  }];
+        }
+    }];
+}
+
+- (void)endRefresh{
+    [self.resourceTableView.mj_header endRefreshing];
+}
+
+- (void)doPostLoginCV {
+    [[RulesManager sharedInstance] setDelegate:self];
+    
+    /**
+     * It may not be a reliable way to do post login Client Verification.
+     * Maybe we should listen to the VPN_CB_CV_USER message.
+     */
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{
+        RulesManager *manager = [RulesManager sharedInstance];
+        [manager cleanTimerRuleInteraction];
+        [manager kickoffTimerRules];
+    });
+    
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{
+        [[RulesManager sharedInstance].interactionHandler takeAction];
+    });
+}
+
+- (void)initKVOController {
+    self.kvoController = [FBKVOController controllerWithObserver:self];
+}
+
+#pragma mark - Access Mode
+
+- (NSArray *)cellsForTableView:(UITableView *)tableView
+{
+    NSInteger sections = tableView.numberOfSections;
+    NSMutableArray *cells = [[NSMutableArray alloc]  init];
+    for (int section = 0; section < sections; section++) {
+        NSInteger rows =  [tableView numberOfRowsInSection:section];
+        for (int row = 0; row < rows; row++) {
+            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
+            [cells addObject:[tableView cellForRowAtIndexPath:indexPath]];
+        }
+    }
+    return cells;
+}
+
+- (int)switchAccessMode:(NSString *)acsDesc {
+    int ret = ERROR_ACM_SUCCESS;
+    BOOL isMatchDesc = NO;
+    
+    if ([self.acsDescList count] == [self.acsNameList count]) {
+        for (NSUInteger i =0; i < [self.acsDescList count]; i++) {
+            if ([[self.acsDescList objectAtIndex:i] isEqualToString:acsDesc]) {
+                isMatchDesc = YES;
+                ret = array_vpn_access_mode_set([[self.acsNameList objectAtIndex:i] UTF8String], NULL, NULL, 0);
+                break;
+            }
+        }
+    }
+    
+    if (!isMatchDesc) {
+        ANError(@"switchAccessMode: get match access mode message failed, switch failed return error.");
+        ret = ERROR_ACM_UNDEFINE;
+    }
+    
+    return ret;
+}
+
+- (void)accessModeRestartVPN{
+    BOOL ret = [self startVPN:NO];
+    if (!ret) {
+        [self setVPNStatusAsError:NSLocalizedString(@"Can't start VPN.", nil)];
+    }
+    
+    NSArray *cells = [self cellsForTableView:self.acsModeTableView];
+    if ([cells count] == 1) {
+        AccessModeCell *cell = (AccessModeCell *)[cells objectAtIndex:0];
+        [cell showActiveView:NO];
+        [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+    }
+}
+
+- (void)didFinishSelect:(NSString *)selectAcsDesc {
+    NSArray *cells = [self cellsForTableView:self.acsModeTableView];
+    if ([cells count] == 1) {
+        AccessModeCell *cell = (AccessModeCell *)[cells objectAtIndex:0];
+        NSString *currentAcsDesc = [cell getCellText];
+        if ([selectAcsDesc length] > 0) {
+            if ([currentAcsDesc isEqualToString:selectAcsDesc]) {
+                ANInfo(@"didFinishSelect: user select same access mode ,do nothing.");
+            } else {
+                ANInfo(@"didFinishSelect: user select access mode[%@]", selectAcsDesc);
+                [cell setCellText:selectAcsDesc];
+                [cell showActiveView:YES];
+                [cell setCellImage:ACCESS_MODE_IMAGE_INACTIVE_NAME];
+                dispatch_async(dispatch_get_main_queue(), ^{
+                    int ret = [self switchAccessMode:selectAcsDesc];
+                    NSString *errorMessage = nil;
+                    switch (ret) {
+                        case ERROR_ACM_SUCCESS:
+                            ANInfo(@"didFinishSelect:switch access mode successfully.");
+                            [cell showActiveView:NO];
+                            [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+                            break;
+                        case ERROR_ACM_SUCCESS_RECONN:
+                            ANInfo(@"didFinishSelect:switch access mode successfully.");
+                            ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+                            if (tunnelStatus == ArrayVPNConnected) {
+                                ANInfo(@"didFinishSelect:vpn status is connected, need reconnect.");
+                                self.needReconnect = YES;
+                                [self stopVPN];
+                            } else {
+                                [cell showActiveView:NO];
+                                [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+                            }
+                            break;
+                        case ERROR_ACM_WITHOUT_SESSION:
+                            errorMessage = NSLocalizedString(@"Switching failure: invalid user session. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_NAME_INVALID:
+                            errorMessage = NSLocalizedString(@"Switching failure: illegal mode information. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_NAME_NONE:
+                            errorMessage = NSLocalizedString(@"Switching failure: mode information does not exist. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_INVALID_PARAMETER:
+                            errorMessage = NSLocalizedString(@"Switching failure: incorrect parameter. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_ACL_CHANGE_FAILED:
+                            errorMessage = NSLocalizedString(@"Switching failure: the server fails to switch. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_NETWORK:
+                            errorMessage = NSLocalizedString(@"Switching failure: network error. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_UNDEFINE:
+                            errorMessage = NSLocalizedString(@"Switching failure: unknown error. Please switch again or contact the administrator.", nil);
+                            break;
+                        default:
+                            errorMessage = NSLocalizedString(@"Switching failure: unknown error. Please switch again or contact the administrator.", nil);
+                            break;
+                    }
+                    if (errorMessage && errorMessage.length > 0) {
+                        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error",nil) message:errorMessage];
+                        [self presentViewController:dialog animated:YES completion:nil];
+                        [cell showActiveView:NO];
+                        [cell setCellText:currentAcsDesc];
+                        [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+                    } else {
+                        for (NSString *info in self.acsDescList) {
+                            if ([selectAcsDesc isEqualToString:info]) {
+                                self.acsSelectedInfo = info;
+                            }
+                        }
+                    }
+                    ANInfo(@"didFinishSelect:switch access mode finished, select access mode=%@.", self.acsSelectedInfo);
+                });
+            }
+        }
+    }
+}
+
+#pragma mark - Auto Logout
+- (void)handleAutoLogout:(NSNotification *)notification {
+    [self logoutSilently];
+}
+
+- (void)clearCookies {  // ANsession should be cleared on logout. (for WebAuth)
+#define MP_SESSION_PREFIX   @"ANsession"
+#define MP_USERNAME_COOKIE  @"username"
+#define MP_ACCESS_NAME      @"acs_mode"
+#define MP_ACCESS_DESC      @"acs_desc"
+    
+    NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
+    NSArray *cookies = cookieJar.cookies;
+    for (NSHTTPCookie *cookie in cookies) {
+        if (cookie.name) {
+            if ([cookie.name isEqualToString:MP_USERNAME_COOKIE] ||[cookie.name containsString:MP_SESSION_PREFIX] || [cookie.name containsString:MP_ACCESS_NAME] || [cookie.name containsString:MP_ACCESS_DESC]) {
+                [cookieJar deleteCookie:cookie];
+            }
+        }
+    }
+}
+
+#pragma mark - VPN Status
+#define STATUS_LABEL_COLOR_NORMAL   UIColorFromRGBA(0x666666, 1.0)
+#define STATUS_LABEL_COLOR_WARNING  UIColorFromRGBA(0xff0000, 1.0)
+#define STATUS_LABEL_COLOR_GREEN    UIColorFromRGBA(0x42a009, 1.0)
+
+- (void)setVPNStatusAsConnecting {
+    self.activityIndicator.hidden = NO;
+    [self.activityIndicator startAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_NORMAL;
+    self.statusLabel.text = NSLocalizedString(@"Connecting...", nil);
+    self.statusImageView.hidden = YES;
+    self.vpnEnableSwitch.on = YES;
+    [self showMessageViewWithInfo:nil];
+}
+
+- (void)setVPNSStatusAsConnected {
+    [self.activityIndicator stopAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_GREEN;
+    self.statusLabel.text = NSLocalizedString(@"Connected", nil);
+    self.statusImageView.image = [UIImage imageNamed:@"ResourceConnectSuccess"];
+    self.statusImageView.hidden = NO;
+    self.vpnEnableSwitch.on = YES;
+    [self showMessageViewWithInfo:nil];
+}
+
+- (void)setVPNStatusAsDisconnected {
+    [self.activityIndicator stopAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_NORMAL;
+    self.statusLabel.text = NSLocalizedString(@"Disconnected", nil);
+    self.statusImageView.image = [UIImage imageNamed:@"ResourceConnectError"];
+    self.statusImageView.hidden = NO;
+    self.vpnEnableSwitch.on = NO;
+    [self showMessageViewWithInfo:nil];
+    if (self.needReconnect) {
+        ANInfo(@"access mode disconnect vpn finished, now need restart vpn.");
+        self.needReconnect = NO;
+        [self accessModeRestartVPN];
+    }
+}
+
+- (void)setVPNStatusAsDisconnecting {
+    [self.activityIndicator startAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_NORMAL;
+    self.statusLabel.text = NSLocalizedString(@"Disconnecting...", nil);
+    self.statusImageView.hidden = YES;
+    self.vpnEnableSwitch.on = NO;
+    [self showMessageViewWithInfo:nil];
+}
+
+- (void)setVPNStatusAsError:(NSString *)errorMessage {
+    [self.activityIndicator stopAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_WARNING;
+    self.statusLabel.text = NSLocalizedString(@"Connect failed", nil);
+    self.statusImageView.image = [UIImage imageNamed:@"ResourceConnectError"];
+    self.statusImageView.hidden = NO;
+    self.vpnEnableSwitch.on = NO;
+    [self showMessageViewWithInfo:errorMessage];
+}
+
+- (void)showMessageViewWithInfo:(NSString *)info {
+    if (info) {
+        self.messageLabel.text = info;
+        self.messageView.hidden = NO;
+    } else {
+        self.messageLabel.text = @"";
+        self.messageView.hidden = YES;
+    }
+}
+
+- (void)showEmptyResouceView {
+    self.emptyResourceView.hidden = NO;
+    self.resourceTableView.hidden = YES;
+    [self.view bringSubviewToFront:self.emptyResourceView];
+}
+
+- (void)showResourceTableView {
+    self.emptyResourceView.hidden = YES;
+    self.resourceTableView.hidden = NO;
+    [self.view bringSubviewToFront:self.resourceTableView];
+}
+
+#pragma mark - VPN Related
+- (BOOL)autoStartVPN {
+    BOOL isAutoStart = NO;
+    Gateway *gateway = [self getCurrentGateway];
+    
+    if (!gateway) {
+        isAutoStart = YES;
+        ANInfo(@"No gateway is selected, it is auto start vpn.");
+    } else {
+        if (!gateway.isSecureTunnelEnabled) {
+            ANInfo(@"Auto start VPN is not enabled.");
+            return NO;
+        }
+    }
+
+    return [self startVPN:isAutoStart];
+}
+
+- (BOOL)startVPN:(BOOL)isAutoStart {
+    //Gateway *gateway = [self getCurrentGateway];
+    //NSString *session = [AAAManager sharedInstance].sessionID;
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    
+#if TARGET_OS_IPHONE
+    //Reset connect fail reason.
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameResource];
+    [userDefaults removeObjectForKey:@"tunnel_result"];
+    [userDefaults removeObjectForKey:@"dns_list"];
+#endif
+    
+    [vpnWrapper startSSLVPN];
+    
+#if TARGET_OS_IPHONE
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleVPNTunnelError:)
+                                                 name:kArrayVPNTunelErrorMsgResource object:nil];
+#endif
+    
+    return YES;
+    
+//    if (isAutoStart) {
+//        [vpnWrapper startSSLVPN];
+//    }
+//
+//    return [vpnWrapper validateSessionWithHost:gateway.host
+//                                          port:gateway.port
+//                                       session:session
+//                                    completion:^(BOOL isSuccess, NSError *error) {
+//                                        if (isSuccess) {
+//                                            [vpnWrapper startSSLVPN];
+//                                        } else {
+//                                            NSString *message = NSLocalizedString(@"Session is invalid, please login again!", nil);
+//                                            PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+//                                                                                                          message:message
+//                                                                                                           action:^{
+//                                                                                                               [[NSNotificationCenter defaultCenter]
+//                                                                                                                postNotificationName:kAutoLogoutNotification
+//                                                                                                                object:nil];
+//                                                                                                           }];
+//                                            [self presentViewController:dialog animated:YES completion:nil];
+//                                        }
+//                                    }];
+}
+
+- (void)stopVPN {
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    [vpnWrapper stopSSLVPN];
+}
+
+- (void)stopVPNAndLogout:(BOOL)isSilent {
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{  // Stop timer rules fisrt.
+        [[RulesManager sharedInstance] stopAllRules];
+    });
+    
+    AAAManager *manager = [AAAManager sharedInstance];
+    [manager continueVPNThreadWithAccount:nil];
+    [self stopVPN];
+    
+    [self clearCookies];
+    
+    if (!isSilent) {
+        __weak typeof(self) weakSelf = self;
+        [self.view makeToastActivity:CSToastPositionCenter];
+        dispatch_async(dispatch_get_global_queue(0, 0), ^{
+            NSInteger ret = [[AAAManager sharedInstance] stopL3VPNDirectly];
+            if (ret != ERR_SUCCESS) {
+                ANError(@"Logout failed with error code: %zi.", ret);
+            }
+            
+            __strong typeof(weakSelf) strongSelf = weakSelf;
+            dispatch_async(dispatch_get_main_queue(), ^{
+                [strongSelf.view hideToastActivity];
+                [strongSelf dismissViewControllerAnimated:YES completion:nil];
+            });
+        });
+    }
+}
+
+- (void)logoutSilently {
+    [self stopVPNAndLogout:YES];
+    
+    [self.navigationController dismissViewControllerAnimated:NO completion:nil];  // Dismiss modal view if exists.
+    [self dismissViewControllerAnimated:YES completion:nil];
+}
+
+- (Gateway *)getCurrentGateway {
+    VPNAccount *account = [AAAManager sharedInstance].account;
+    GatewayManager *gm = [GatewayManager sharedInstance];
+    NSString *url = account.vsURL;
+    NSString *port = account.vsPort;
+    NSInteger index = [gm indexOfUrl:url andport:port];
+    
+    return [gm gatewayAtIndex:index];
+}
+
+#pragma mark - VPN Status Handler
+- (void)handleVPNStatus:(NSNotification *)notification {
+    ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+    
+    ANDebug(@"Array VPN tunnel status = %zi", tunnelStatus);
+    
+    [self updateUIWithVPNStatus:tunnelStatus];
+}
+
+- (void)updateUIWithVPNStatus:(ArrayVPNStatus)status {
+    switch (status) {
+        case ArrayVPNInavlid:
+        case ArrayVPNDisconnected:
+            [self setVPNStatusAsDisconnected];
+            break;
+        case ArrayVPNDisconnecting:
+            [self setVPNStatusAsDisconnecting];
+            break;
+        case ArrayVPNConnecting:
+        case ArrayVPNReasserting:
+            [self setVPNStatusAsConnecting];
+            break;
+        case ArrayVPNConnected:
+            [self setVPNSStatusAsConnected];
+            break;
+            
+        default:
+            break;
+    }
+}
+
+- (void)handleVPNTunnelError:(NSNotification *)notification {
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    NSString *errMessage = [vpnWrapper getErrorMsgWithCode];
+    if (errMessage && errMessage.length > 0) {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:errMessage];
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+#pragma mark - Number of Sections & Rows
+- (BOOL)isWebAppToShow {
+    PortalTabsConfiguration *portalConfiguration = [ConfigurationManager sharedInstance].portalTabs;
+    
+    return portalConfiguration.isWebAppConfigured && self.model.webApps.children.count > 0;
+}
+
+- (BOOL)isNativeAppToShow {
+    PortalTabsConfiguration *portalConfiguration = [ConfigurationManager sharedInstance].portalTabs;
+    
+    return portalConfiguration.isNativeAppConfigured && self.model.nativeApps.children.count > 0;
+}
+
+- (BOOL)isDesktopToShow {
+    PortalTabsConfiguration *portalConfiguration = [ConfigurationManager sharedInstance].portalTabs;
+    
+    return portalConfiguration.isDesktopConfigured && self.model.desktopApps.resourceItems.count > 0;
+}
+
+- (NSInteger)totalSections {
+    NSInteger totalSections = 0;
+    NSInteger webSection = [self isWebAppToShow] ? 1 : 0;
+    NSInteger nativeSection = [self isNativeAppToShow] ? 1 : 0;
+    NSInteger desktopSection = [self isDesktopToShow] ? 1 : 0;
+    
+    totalSections = webSection + nativeSection + desktopSection;
+    
+    return totalSections;
+}
+
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([segue.identifier isEqualToString:kSegueToSubResource]) {
+        SubResourceViewController *viewController = segue.destinationViewController;
+        [viewController setupModel:(NSArray *)sender];
+    }
+    if ([segue.identifier isEqualToString:kSegueToAccessModeSelect]) {
+        NSArray *cells = [self cellsForTableView:self.acsModeTableView];
+        if ([cells count] == 1) {
+            UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
+            AccessModeSelectViewController *controller = (AccessModeSelectViewController *)navController.topViewController;
+            controller.selectedAcsModeString = self.acsSelectedInfo;
+            controller.delegate = self;
+        }
+    }
+}
+
+#pragma mark - Get Child at Index
+- (NSArray *)didSelectWebAppAtIndexPath:(NSIndexPath *)indexPath {
+    NSInteger row = indexPath.row;
+    
+    if (row >= self.model.webApps.children.count) {
+        ANError(@"Index (%zi) is out range of web apps count.", row);
+        return nil;
+    }
+    
+    WebApp *app = [self.model.webApps.children objectAtIndex:row];
+    if (app.type == APP_TYPE_WEBAPP) {
+        ZTWKWebViewController *control = [[ZTWKWebViewController alloc] init];
+        control.webUrl = [app.url absoluteString];
+        [self.navigationController pushViewController:control animated:YES];
+
+        
+        return nil;
+    }
+    
+    return app.children;
+}
+
+- (NSArray *)didSelectNativeAppAtIndexPath:(NSIndexPath *)indexPath {
+    NSInteger row = indexPath.row;
+    
+    if (row >= self.model.nativeApps.children.count) {
+        ANError(@"Index (%zi) is out range of native apps count.", row);
+        return nil;
+    }
+    
+    NativeApp *app = [self.model.nativeApps.children objectAtIndex:row];
+    NSURL *url = [NSURL URLWithString:app.scheme];
+    if (url.scheme == nil) {
+        url = [NSURL URLWithString:[NSString stringWithFormat:@"%@://", app.scheme]];
+    }
+    
+    ANInfo(@"open app url=%@", url);
+    if (!OpenURL(url)) {
+        BOOL isAppStoreApp = (app.installUrl != nil);
+        if (!isAppStoreApp) {
+            NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Application %@ has not been installed, Would you like to search it on App Store?", nil), app.name];
+            PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:@""
+                                                                           message:message
+                                                                     confirmAction:^{
+                                                                         NSString *string = [NSString stringWithFormat:APPSTORE_SEARCH_STRING,
+                                                                                             [app.name stringByAddingPercentEncodingWithAllowedCharacters:
+                                                                                              NSCharacterSet.URLQueryAllowedCharacterSet]];
+                                                                         OpenURL([NSURL URLWithString:string]);
+                                                                     }
+                                                                      cancelAction:nil];
+            
+            [self presentViewController:dialog animated:YES completion:nil];
+        } else {
+            ANError(@"appstore client don't support this case any more.");
+        }
+    }
+    
+    return nil;
+}
+
+- (NSArray *)didSelectDesktopAtIndexPath:(NSIndexPath *)indexPath {
+    NSInteger row = indexPath.row;
+    
+    if (row >= self.model.desktopApps.resourceItems.count) {
+        ANError(@"Index (%zi) is out range of desktop apps count.", row);
+        return nil;
+    }
+    
+    FolderItem *item = [self.desktops objectAtIndex:row];
+    if ([item isKindOfClass:[GCustomItem class]] && [item.name isEqualToString:NSLocalizedString(@"Other", nil)]) {
+        [self performSegueWithIdentifier:kSegueToCustomDesktop sender:self];
+        return nil;
+    } else if ([item isKindOfClass:[HostItem class]]) {
+        [self didSelectHostItem:(HostItem *)item atIndexPath:indexPath];
+        return nil;
+    }
+    
+    return [self getSortedArray:[item.resourceItems allValues]];
+}
+
+#pragma mark - DesktopDirect
+- (void)didSelectHostItem:(HostItem *)hostItem atIndexPath:(NSIndexPath *)indexPath {
+    if (self.currentIndex
+        && self.currentIndex.row == indexPath.row
+        && hostItem.status < ResourceStatusReady) {
+        return;
+    }
+    
+    self.currentIndex = indexPath;
+    self.currentItem = hostItem;
+    
+    ResourceCell *cell = (ResourceCell *)[self.resourceTableView cellForRowAtIndexPath:indexPath];
+    
+    __weak typeof(self) weakSelf = self;
+    [self.kvoController observe:hostItem
+                        keyPath:@"status"
+                        options:NSKeyValueObservingOptionNew
+                          block:^(ResourcesViewController *observer, HostItem *host, NSDictionary *change) {
+                              NSInteger hostStatus = host.status;
+                              dispatch_async(dispatch_get_main_queue(), ^{
+                                  [cell updateUI:host];
+                                  if (observer.currentIndex.row != indexPath.row) {
+                                      return;
+                                  }
+                                  
+                                  if (observer.silence) {
+                                      return;
+                                  }
+                                  if (host.status == ResourceStatusReady) {
+                                      [observer.kvoController unobserve:host];
+                                      NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
+                                      AppManager *appManager = [AppManager sharedInstance];
+                                      BOOL cliEnabledNEC = NO;
+                                      NSString *enabledNEC = appManager.desktopSettings.settings[@"jp-rdp"];
+                                      if (enabledNEC && [enabledNEC isEqualToString:@"1"])
+                                          cliEnabledNEC = YES;
+                                      if (cliEnabledNEC || [userDefaults integerForKey:@"desktop_client_vendor"] == 1) {
+                                          [observer openRDClientNEC:host];
+                                      } else {
+                                          [observer openRDClient:host];
+                                      }
+                                      // Reset power state
+                                      host.powerState = HostPowerStateDown;
+                                      return;
+                                  } else if (hostStatus >= ResourceStatusFailed && hostStatus < ResourceStatusResolveHostNameFailed) {
+                                      ANError(@"Cannot connect to remote host, error code: %zi", hostStatus);
+                                      
+                                      if (hostStatus == ResourceStatusPowerDown) {
+                                          NSString *message = NSLocalizedString(@"It seems the remote host is turned off. Would you like to try and wake it up?", nil);
+                                          
+                                          PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Cannot connect to remote host", nil)
+                                                                                                         message:message
+                                                                                                   confirmAction:^{
+                                                                                                       NSInteger row = weakSelf.currentIndex.row;
+                                                                                                       HostItem *host = weakSelf.desktops[row];
+                                                                                                       [host wakeUp];
+                                                                                                   }
+                                                                                                    cancelAction:nil];
+                                          
+                                          [weakSelf presentViewController:dialog animated:YES completion:nil];
+                                          
+                                          return;
+                                      } else {
+                                          [observer.kvoController unobserve:host];
+                                      }
+                                  }
+                              });
+                          }];
+    
+    [hostItem prepare];
+}
+
+- (void)openRDClient:(HostItem *)hostItem {
+    NSURL *url = hostItem.url;
+    if (!url) {
+        return;
+    }
+    
+    if (!OpenURL(url)) {
+        NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Application %@ has not been installed, Would you like to search it on App Store?", nil), @"RD client"];
+        PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Cannot connect to remote host", nil)
+                                                                       message:message
+                                                                 confirmAction:^{
+                                                                     NSString *string = [NSString stringWithFormat:APPSTORE_SEARCH_STRING,
+                                                                                         [@"RD client" stringByAddingPercentEncodingWithAllowedCharacters:
+                                                                                          NSCharacterSet.URLQueryAllowedCharacterSet]];
+                                                                     
+                                                                     OpenURL([NSURL URLWithString:string]);
+                                                                 }
+                                                                  cancelAction:nil];
+        
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+- (void)openRDClientNEC:(HostItem *)hostItem {
+    NSURL *url = hostItem.urlVendorNEC;
+    if (!url) {
+        return;
+    }
+    
+    if (!OpenURL(url)) {
+        NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Application %@ has not been installed, Would you like to search it on App Store?", nil),@"RD"];
+        PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Cannot connect to remote host", nil)
+                                                                       message:message
+                                                                 confirmAction:^{
+                                                                     NSString *string = @"https://itunes.apple.com/jp/app/rd-v1.3/id771611106?mt=8";
+                                                                     OpenURL([NSURL URLWithString:string]);
+                                                                 }
+                                                                  cancelAction:nil];
+        
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+- (NSArray *)desktops {
+    if (!_desktops) {
+        _desktops = [self getSortedArray:[self.model.desktopApps.resourceItems allValues]];
+    }
+    
+    return _desktops;
+}
+
+- (NSArray *)getSortedArray:(NSArray *)array {
+    if (!array || array.count == 0) {
+        ANWarn(@"Empty array, should not be sorted.");
+        return nil;
+    }
+    
+    NSSortDescriptor *byClass = [NSSortDescriptor sortDescriptorWithKey:@"class" ascending:YES comparator:^NSComparisonResult(id obj1, id obj2) {
+        // Sort by class name
+        return [NSStringFromClass(obj1) compare:NSStringFromClass(obj2)];
+        
+    }];
+    
+    NSSortDescriptor *byName = [NSSortDescriptor sortDescriptorWithKey:@"name"
+                                                             ascending:YES
+                                                              selector:@selector(localizedStandardCompare:)];
+    
+    NSArray *sortDescriptors = [NSArray arrayWithObjects:byClass, byName, nil];
+    
+    return [array sortedArrayUsingDescriptors:sortDescriptors];
+}
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    if ([tableView isEqual:self.resourceTableView]) {
+        return [self totalSections];
+    } else if ([tableView isEqual:self.acsModeTableView]) {
+        return 1;
+    }
+    
+    return 0;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    if ([tableView isEqual:self.resourceTableView]) {
+        NSInteger totalSections = [self totalSections];
+        if (section > totalSections) {
+            ANError(@"Section (%zi) is larger than total sections (%zi).", section, totalSections);
+            
+            return 0;
+        }
+        
+        __weak typeof(self) weakSelf = self;
+        NSNumber *result = [self getCellInfoInSection:section
+                                         totalSection:totalSections
+                                               object:nil
+                                              action1:^id(id param) {
+                                                  __strong typeof(weakSelf) strongSelf = weakSelf;
+                                                  NSInteger rows = strongSelf.model.webApps.children.count;
+                                                  return [NSNumber numberWithInteger:rows];
+                                              }
+                                              action2:^id(id param) {
+                                                  __strong typeof(weakSelf) strongSelf = weakSelf;
+                                                  NSInteger rows = strongSelf.model.nativeApps.children.count;
+                                                  return [NSNumber numberWithInteger:rows];
+                                              }
+                                              action3:^id(id param) {
+                                                  __strong typeof(weakSelf) strongSelf = weakSelf;
+                                                  NSInteger rows = strongSelf.model.desktopApps.resourceItems.count;
+                                                  return [NSNumber numberWithInteger:rows];
+                                              }];
+        
+        return [result integerValue];
+    } else if ([tableView isEqual:self.acsModeTableView]) {
+        return 1;
+    }
+    
+    return 0;
+}
+
+- (UITableViewCell *)configureWebAppWithRow:(NSInteger)row {
+    ResourceCell *cell = [self.resourceTableView dequeueReusableCellWithIdentifier:kResourceCellID];
+    if (!cell) {
+        cell = [[ResourceCell alloc] init];
+    }
+    
+    WebApp *app = [self.model.webApps.children objectAtIndex:row];
+    UIImage *image = nil;
+    BOOL isFolder = app.type == APP_TYPE_FOLDER;
+    if (isFolder) {
+        image = [UIImage imageNamed:FOLDER_APP_IMAGE_NAME];
+    } else {
+        image = [UIImage imageNamed:WEB_APP_IMAGE_NAME];
+        UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self
+                                                                                                       action:@selector(cellLongPressed:)];
+        [cell addGestureRecognizer:longPressGesture];
+    }
+    [cell configureCellWithImage:image name:app.name isFolder:isFolder];
+    
+    return cell;
+}
+
+- (UITableViewCell *)configureNativeAppWithRow:(NSInteger)row {
+    NativeAppCell *cell = [self.resourceTableView dequeueReusableCellWithIdentifier:kNativeAppCellID];
+    if (!cell) {
+        cell = [[NativeAppCell alloc] init];
+    }
+    
+    NativeApp *app = [self.model.nativeApps.children objectAtIndex:row];
+    UIImage *image = nil;
+    if (app.customIcon) {
+        image = app.customIcon;
+    } else if (app.appIcon) {
+        image = app.appIcon;
+    } else {
+        image = [UIImage imageNamed:NATIVE_APP_IMAGE_NAME];
+    }
+    [cell configureCellWithImage:image name:app.name isFolder:NO];  // Native app doesn't support folder.
+    [cell setDescriptionContent:app.desc];
+    
+    return cell;
+}
+
+- (UITableViewCell *)configureDesktopAppWithRow:(NSInteger)row {
+    ResourceCell *cell = [self.resourceTableView dequeueReusableCellWithIdentifier:kResourceCellID];
+    if (!cell) {
+        cell = [[ResourceCell alloc] init];
+    }
+    
+    ResourceItem *item = [self.desktops objectAtIndex:row];
+    BOOL isFolder = [item isKindOfClass:[FolderItem class]];  // Only pub-app & self-defined desktop has folder.
+    BOOL isCustomDesktop = [item isKindOfClass:[GCustomItem class]];
+    if (isCustomDesktop) {
+        isFolder = YES;
+    }
+    UIImage *image = nil;
+    if (item.icon != nil) {
+        if ([item.description containsString:@"http.ico"]) {
+            image = [UIImage imageNamed:ZRT_HTTP_IMAGE_NAME];
+        } else if ([item.description containsString:@"HSValuate1.ico"]) {
+            image = [UIImage imageNamed:ZRT_HSVALUATE1_IMAGE_NAME];
+        } else if ([item.description containsString:@"HSValuate2.ico"]) {
+            image = [UIImage imageNamed:ZRT_HSVALUATE2_IMAGE_NAME];
+        } else if ([item.description containsString:@"fundclient1.ico"]) {
+            image = [UIImage imageNamed:ZRT_FUNDCLIENT1_IMAGE_NAME];
+        } else if ([item.description containsString:@"fundclient2.ico"]) {
+            image = [UIImage imageNamed:ZRT_FUNDCLIENT2_IMAGE_NAME];
+        } else {
+            image = item.icon;
+        }
+    } else {
+        image = (isFolder && !isCustomDesktop) ? [UIImage imageNamed:FOLDER_APP_IMAGE_NAME] : [UIImage imageNamed:DESKTOP_IMAGE_NAME];
+    }
+    [cell configureCellWithImage:image name:item.name isFolder:isFolder];
+    
+    return cell;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell *cell = nil;
+    if ([tableView isEqual:self.resourceTableView]) {
+        NSInteger row = indexPath.row;
+        NSInteger section = indexPath.section;
+        NSInteger totalSections = [self totalSections];
+        
+        __weak typeof(self) weakSelf = self;
+        cell = [self getCellInfoInSection:section
+                             totalSection:totalSections
+                                   object:[NSNumber numberWithInteger:row]
+                                  action1:^id(id param) {
+                                      __strong typeof(weakSelf) strongSelf = weakSelf;
+                                      NSInteger row = [(NSNumber *)param integerValue];
+                                      return [strongSelf configureWebAppWithRow:row];
+                                  }
+                                  action2:^id(id param) {
+                                      __strong typeof(weakSelf) strongSelf = weakSelf;
+                                      NSInteger row = [(NSNumber *)param integerValue];
+                                      return [strongSelf configureNativeAppWithRow:row];
+                                  }
+                                  action3:^id(id param) {
+                                      __strong typeof(weakSelf) strongSelf = weakSelf;
+                                      NSInteger row = [(NSNumber *)param integerValue];
+                                      return [strongSelf configureDesktopAppWithRow:row];
+                                  }];
+    } else if([tableView isEqual:self.acsModeTableView]) {
+        if ([self.acsDescList count] > 0) {
+            AccessModeCell *accessModeCell = [self.acsModeTableView dequeueReusableCellWithIdentifier:kAccessModeCellID];
+            if (!accessModeCell) {
+                accessModeCell = [[AccessModeCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kAccessModeCellID];
+            }
+            NSString *showAcsDesc = [self.acsDescList objectAtIndex:0];
+            if ([self.acsDescList count] > 1) {
+                showAcsDesc = [NSString stringWithFormat:@"%@...", showAcsDesc];
+            }
+            
+            [accessModeCell configureCellWithMessage:showAcsDesc isDescList:NO];
+            [accessModeCell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+            
+            return accessModeCell;
+        } else {
+            cell = [[UITableViewCell alloc] init];
+        }
+        
+    }
+    
+    return cell;
+}
+
+- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
+    NSString *title = @"";
+    if ([tableView isEqual:self.resourceTableView]) {
+        NSInteger totalSections = [self totalSections];
+
+        title = [self getCellInfoInSection:section
+                              totalSection:totalSections
+                                    object:nil
+                                   action1:^id(id param) {
+                                       return NSLocalizedString(@"Web App", nil);
+                                   }
+                                   action2:^id(id param) {
+                                       return NSLocalizedString(@"Native App", nil);
+                                   }
+                                   action3:^id(id param) {
+                                       return NSLocalizedString(@"Remote Desktop", nil);
+                                   }];
+    }
+
+    return title;
+}
+
+#pragma mark - Long press handler for WebApp
+- (void)cellLongPressed:(UIGestureRecognizer *)recognizer {
+    if (recognizer.state == UIGestureRecognizerStateBegan) {
+        CGPoint location = [recognizer locationInView:self.resourceTableView];
+        NSIndexPath *indexPath = [self.resourceTableView indexPathForRowAtPoint:location];
+        _longPressedIndex = indexPath.row;
+        ResourceCell *cell = [self.resourceTableView cellForRowAtIndexPath:indexPath];
+        
+        [self showMenuWithCell:cell];
+    }
+}
+
+- (void)showMenuWithCell:(ResourceCell *)cell {
+    [cell becomeFirstResponder];
+    
+    UIMenuController *controller = [UIMenuController sharedMenuController];
+    UIMenuItem *openItem = [[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Open in Safari", nil) action:@selector(openWebPage:)];
+    [controller setMenuItems:[NSArray arrayWithObjects:openItem, nil]];
+    [controller setTargetRect:cell.contentView.frame inView:cell.contentView];
+    [controller setMenuVisible:YES animated:YES];
+}
+
+- (void)openWebPage:(id)sender {
+    if (_longPressedIndex >= self.model.webApps.children.count) {
+        ANError(@"Index (%zi) is out range of web apps count.", _longPressedIndex);
+        return;
+    }
+    
+    WebApp *app = [self.model.webApps.children objectAtIndex:_longPressedIndex];
+    if (app.type == APP_TYPE_WEBAPP) {
+        [[UIApplication sharedApplication] openURL:app.url];
+    }
+}
+
+#pragma mark - TimerRuleDelegate
+- (void)shouldSignOut {
+    [self logoutSilently];
+}
+
+#pragma mark - UITableViewDelegate
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    if ([tableView isEqual:self.resourceTableView]) {
+        [self.resourceTableView deselectRowAtIndexPath:indexPath animated:YES];
+        
+        NSInteger totalSections = [self totalSections];
+        NSInteger section = indexPath.section;
+        NSArray *children = nil;
+        
+        __weak typeof(self) weakSelf = self;
+        children = [self getCellInfoInSection:section
+                                 totalSection:totalSections
+                                       object:indexPath
+                                      action1:^id(id param) {
+                                          __strong typeof(weakSelf) strongSelf = weakSelf;
+                                          return [strongSelf didSelectWebAppAtIndexPath:indexPath];
+                                      }
+                                      action2:^id(id param) {
+                                          __strong typeof(weakSelf) strongSelf = weakSelf;
+                                          return [strongSelf didSelectNativeAppAtIndexPath:indexPath];
+                                      }
+                                      action3:^id(id param) {
+                                          __strong typeof(weakSelf) strongSelf = weakSelf;
+                                          return [strongSelf didSelectDesktopAtIndexPath:indexPath];
+                                      }];
+        
+        if (children != nil) {
+            [self performSegueWithIdentifier:kSegueToSubResource sender:children];
+        }
+    } else if ([tableView isEqual:self.acsModeTableView]) {
+        [self.acsModeTableView deselectRowAtIndexPath:indexPath animated:YES];
+        if ([self.acsDescList count] > 0) {
+            [self performSegueWithIdentifier:kSegueToAccessModeSelect sender:self];
+        }
+    }
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    if ([tableView isEqual:self.resourceTableView]) {
+        return 39;
+    } 
+    
+    return 0;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
+    if ([tableView isEqual:self.resourceTableView]) {
+        static CGFloat kDefaultCellHeight = 44.0;
+        static CGFloat kNativeCellHeight = 66.0;
+        NSInteger section = indexPath.section;
+        NSInteger totalSections = [self totalSections];
+        
+        NSNumber *result = [self getCellInfoInSection:section
+                                         totalSection:totalSections
+                                               object:nil
+                                              action1:^id(id param) {
+                                                  return [NSNumber numberWithFloat:kDefaultCellHeight];
+                                              }
+                                              action2:^id(id param) {
+                                                  return [NSNumber numberWithFloat:kNativeCellHeight];
+                                              }
+                                              action3:^id(id param) {
+                                                  return [NSNumber numberWithFloat:kDefaultCellHeight];
+                                              }];
+        
+        return [result integerValue];
+    } else if ([tableView isEqual:self.acsModeTableView]) {
+        return 44;
+    }
+    
+    return 0;
+}
+
+#pragma mark - Helper
+typedef id (^Action)(id param);
+
+- (id)getCellInfoInSection:(NSInteger)section
+              totalSection:(NSInteger)totalSection
+                    object:(id)object
+                   action1:(Action)action1
+                   action2:(Action)action2
+                   action3:(Action)action3 {
+    id result = nil;
+    
+    switch (totalSection) {
+        case kResourceSectionOne: {
+            if ([self isWebAppToShow]) {
+                result = action1(object);
+            } else if ([self isNativeAppToShow]) {
+                result = action2(object);
+            } else if ([self isDesktopToShow]) {
+                result = action3(object);
+            }
+            break;
+        }
+        case kResourceSectionTwo:
+            if ([self isWebAppToShow]) {
+                if ([self isNativeAppToShow]) {
+                    if (section == kResourceSectionIndex0) {
+                        result = action1(object);
+                    } else if (section == kResourceSectionIndex1) {
+                        result = action2(object);
+                    }
+                } else if ([self isDesktopToShow]) {
+                    if ([self isDesktopToShow]) {
+                        if (section == kResourceSectionIndex0) {
+                            result = action1(object);
+                        } else if (section == kResourceSectionIndex1) {
+                            result = action3(object);
+                        }
+                    }
+                }
+            } else if ([self isNativeAppToShow]) {
+                if ([self isDesktopToShow]) {
+                    if (section == kResourceSectionIndex0) {
+                        result = action2(object);
+                    } else if (section == kResourceSectionIndex1) {
+                        result = action3(object);
+                    }
+                }
+            }
+            break;
+        case kResourceSectionThree:
+            if (section == kResourceSectionIndex0) {
+                result = action1(object);
+            } else if (section == kResourceSectionIndex1) {
+                result = action2(object);
+            } else if (section == kResourceSectionIndex2) {
+                result = action3(object);
+            }
+            break;
+            
+        default:
+            ANError(@"Invalid sections number of (%zi) received.", section);
+            break;
+    }
+    
+    return result;
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ResourcesViewController.m.MotionProEnterprise
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ResourcesViewController.m.MotionProEnterprise	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ResourcesViewController.m.MotionProEnterprise	(working copy)
@@ -0,0 +1,1319 @@
+//
+//  ResourcesViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/27.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "ANLogger.h"
+#import "AAAManager.h"
+#import "AppManager.h"
+#import "GCustomItem.h"
+#import "PubAppItem.h"
+#import "FBKVOController.h"
+#import "ArrayVPNWrapper.h"
+#import "ANPopupDialog.h"
+#import "GatewayManager.h"
+#import "CertificateManager.h"
+#import "ConfigurationManager.h"
+#import "RulesManager.h"
+#import "ResourceCell.h"
+#import "MJRefresh.h"
+#import "NativeAppCell.h"
+#import "AutoLoginHandler.h"
+#import "SubResourceViewController.h"
+#import "UIView+Toast.h"
+#import "ResourcesViewController.h"
+#import "AccessModeCell.h"
+#import "AccessModeSelectViewController.h"
+#import "ZTWKWebViewController.h"
+
+static NSString * const kSegueToSubResource = @"ResourceToSubResource";
+static NSString * const kSegueToCustomDesktop = @"ResourceToCustomDesktop";
+static NSString * const kSegueToAccessModeSelect = @"ResourceToAccessModeSelect";
+
+#if TARGET_OS_IPHONE
+NSString * const kAppGroupNameResource = @"group.net.arraynetworks.groupenterprise";
+NSString * const kArrayVPNTunelErrorMsgResource = @"net.arraynetworks.sslvpn.errormsg";
+#elif TARGET_OS_MAC
+NSString * const kAppGroupNameResource = @"5VZLZ3YQ9P.net.arraynetworks.MacTunnel";
+#endif
+
+typedef NS_ENUM(NSInteger, ResourceSectionNumber) {
+    kResourceSectionZero = 0,
+    kResourceSectionOne,
+    kResourceSectionTwo,
+    kResourceSectionThree
+};
+
+typedef NS_ENUM(NSInteger, ResourceSectionIndex) {
+    kResourceSectionIndex0 = 0,
+    kResourceSectionIndex1,
+    kResourceSectionIndex2
+};
+
+@interface ResourcesViewController () <TimerRuleDelegate, AcsModeSelectControllerDelegate> {
+    NSInteger _longPressedIndex;
+}
+
+@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator;
+@property (weak, nonatomic) IBOutlet UILabel *statusLabel;
+@property (weak, nonatomic) IBOutlet UISwitch *vpnEnableSwitch;
+@property (weak, nonatomic) IBOutlet UIImageView *statusImageView;
+
+@property (weak, nonatomic) IBOutlet UIView *messageView;
+@property (weak, nonatomic) IBOutlet UILabel *messageLabel;
+
+@property (weak, nonatomic) IBOutlet UIView *emptyResourceView;
+@property (weak, nonatomic) IBOutlet UIImageView *emptyResourceImageView;
+@property (weak, nonatomic) IBOutlet UILabel *emptyResourceLabel;
+
+@property (weak, nonatomic) IBOutlet UITableView *resourceTableView;
+
+@property (weak, nonatomic) IBOutlet UITableView *acsModeTableView;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *resourceViewTopConstraint;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *emptyViewTopConstraint;
+
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *messageViewTopConstraint;
+
+@property (strong, nonatomic) AppManager *model;
+@property (strong, nonatomic) NSArray *desktops;  // As a cache
+
+@property (strong, nonatomic) NSArray *acsDescList;
+@property (strong, nonatomic) NSArray *acsNameList;
+@property (strong, nonatomic) NSString *acsSelectedInfo;
+
+
+@property (strong, nonatomic) id browser;
+
+// For DesktopDirect
+@property (nonatomic, strong) NSIndexPath *currentIndex;
+@property (nonatomic, strong) ResourceItem *currentItem;
+@property (nonatomic, strong) FBKVOController *kvoController;
+@property (nonatomic, strong) UIControl *darkView;
+@property (nonatomic) BOOL silence;
+@property (nonatomic) BOOL needReconnect;
+
+@end
+
+@implementation ResourcesViewController
+
+@synthesize desktops = _desktops;
+
+- (void)dealloc {
+#if TARGET_OS_IPHONE
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:kArrayVPNTunelErrorMsgResource object:nil];
+#endif
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    self.model = [AppManager sharedInstance];
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(handleVPNStatus:)
+                                                 name:kArrayVPNStatusNotification
+                                               object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(handleAutoLogout:)
+                                                 name:kAutoLogoutNotification
+                                               object:nil];
+    
+    [self setVPNStatusAsDisconnected];
+    [self autoStartVPN];
+    [self doPostLoginCV];
+    
+    [self initKVOController];
+    
+    [self initTopView];
+    [self initAccessModeView];
+    [self initPullToRefresh];
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [super viewWillDisappear:animated];
+    
+    self.silence = YES;
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    
+    self.silence = NO;
+}
+
+- (void)viewDidAppear:(BOOL)animated {
+    [super viewDidAppear:animated];
+    
+    RulesManager *manager = [RulesManager sharedInstance];
+    if (manager.didEndSession) {
+        manager.didEndSession = NO;
+        
+        [self logoutSilently];
+    }
+}
+
+- (void)initAccessModeView {
+    BOOL bShowAcsModeView = NO;
+    
+    self.acsSelectedInfo = nil;
+    self.acsDescList = [AAAManager sharedInstance].acsModeDesc;
+    self.acsNameList = [AAAManager sharedInstance].acsModeName;
+    if (self.acsDescList != nil) {
+        bShowAcsModeView = YES;
+    }
+    
+    if (bShowAcsModeView) {
+        self.acsModeTableView.hidden = NO;
+        self.resourceViewTopConstraint.constant = 95;
+        self.emptyViewTopConstraint.constant = 100;
+        self.messageViewTopConstraint.constant = 100;
+        self.acsModeTableView.tableHeaderView = [[UIView alloc]initWithFrame:CGRectMake(0,0,0,0.01)];
+    } else {
+        self.acsModeTableView.hidden = YES;
+        self.resourceViewTopConstraint.constant = 45;
+        self.emptyViewTopConstraint.constant = 50;
+        self.messageViewTopConstraint.constant = 50;
+    }
+    
+    self.needReconnect = NO;
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (IBAction)exitButtonClicked:(id)sender {
+    __weak typeof(self) weakSelf = self;
+    PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+                                                                   message:NSLocalizedString(@"Would you like to sign out?", nil)
+                                                             confirmAction:^{
+                                                                 [weakSelf stopVPNAndLogout:NO];
+                                                             }
+                                                              cancelAction:nil];
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (IBAction)vpnEnableSwitched:(id)sender {
+    if (self.vpnEnableSwitch.on) {
+        BOOL ret = [self startVPN:NO];
+        if (!ret) {
+            [self setVPNStatusAsError:NSLocalizedString(@"Can't start VPN.", nil)];
+        }
+    } else {
+        [self stopVPN];
+    }
+}
+
+- (void)initTopView {
+    [self.acsModeTableView registerNib:[UINib nibWithNibName:@"AccessModeCell" bundle:nil] forCellReuseIdentifier:kAccessModeCellID];
+    if (self.model.isEmpty) {
+        [self showEmptyResouceView];
+    } else {
+        [self showResourceTableView];
+        [self.resourceTableView registerNib:[UINib nibWithNibName:@"ResourceCell" bundle:nil] forCellReuseIdentifier:kResourceCellID];
+        [self.resourceTableView registerNib:[UINib nibWithNibName:@"NativeAppCell" bundle:nil] forCellReuseIdentifier:kNativeAppCellID];
+    }
+}
+
+- (void)initPullToRefresh {
+    __weak typeof(self) weakSelf = self;
+    self.resourceTableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
+        __strong typeof(weakSelf) strongSelf = weakSelf;
+        [strongSelf endRefresh];
+        
+        Gateway *currentGateway = [self getCurrentGateway];
+        if (currentGateway) {
+            [[AppManager sharedInstance] fetchAppsFromServer:currentGateway.host
+                                                        port:currentGateway.port
+                                                  completion:^(BOOL isNeedUpdate) {
+                                                      [strongSelf.resourceTableView reloadData];
+                                                  }];
+        }
+    }];
+}
+
+- (void)endRefresh{
+    [self.resourceTableView.mj_header endRefreshing];
+}
+
+- (void)doPostLoginCV {
+    [[RulesManager sharedInstance] setDelegate:self];
+    
+    /**
+     * It may not be a reliable way to do post login Client Verification.
+     * Maybe we should listen to the VPN_CB_CV_USER message.
+     */
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{
+        RulesManager *manager = [RulesManager sharedInstance];
+        [manager cleanTimerRuleInteraction];
+        [manager kickoffTimerRules];
+    });
+    
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{
+        [[RulesManager sharedInstance].interactionHandler takeAction];
+    });
+}
+
+- (void)initKVOController {
+    self.kvoController = [FBKVOController controllerWithObserver:self];
+}
+
+#pragma mark - Access Mode
+
+- (NSArray *)cellsForTableView:(UITableView *)tableView
+{
+    NSInteger sections = tableView.numberOfSections;
+    NSMutableArray *cells = [[NSMutableArray alloc]  init];
+    for (int section = 0; section < sections; section++) {
+        NSInteger rows =  [tableView numberOfRowsInSection:section];
+        for (int row = 0; row < rows; row++) {
+            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
+            [cells addObject:[tableView cellForRowAtIndexPath:indexPath]];
+        }
+    }
+    return cells;
+}
+
+- (int)switchAccessMode:(NSString *)acsDesc {
+    int ret = ERROR_ACM_SUCCESS;
+    BOOL isMatchDesc = NO;
+    
+    if ([self.acsDescList count] == [self.acsNameList count]) {
+        for (NSUInteger i =0; i < [self.acsDescList count]; i++) {
+            if ([[self.acsDescList objectAtIndex:i] isEqualToString:acsDesc]) {
+                isMatchDesc = YES;
+                ret = array_vpn_access_mode_set([[self.acsNameList objectAtIndex:i] UTF8String], NULL, NULL, 0);
+                break;
+            }
+        }
+    }
+    
+    if (!isMatchDesc) {
+        ANError(@"switchAccessMode: get match access mode message failed, switch failed return error.");
+        ret = ERROR_ACM_UNDEFINE;
+    }
+    
+    return ret;
+}
+
+- (void)accessModeRestartVPN{
+    BOOL ret = [self startVPN:NO];
+    if (!ret) {
+        [self setVPNStatusAsError:NSLocalizedString(@"Can't start VPN.", nil)];
+    }
+    
+    NSArray *cells = [self cellsForTableView:self.acsModeTableView];
+    if ([cells count] == 1) {
+        AccessModeCell *cell = (AccessModeCell *)[cells objectAtIndex:0];
+        [cell showActiveView:NO];
+        [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+    }
+}
+
+- (void)didFinishSelect:(NSString *)selectAcsDesc {
+    NSArray *cells = [self cellsForTableView:self.acsModeTableView];
+    if ([cells count] == 1) {
+        AccessModeCell *cell = (AccessModeCell *)[cells objectAtIndex:0];
+        NSString *currentAcsDesc = [cell getCellText];
+        if ([selectAcsDesc length] > 0) {
+            if ([currentAcsDesc isEqualToString:selectAcsDesc]) {
+                ANInfo(@"didFinishSelect: user select same access mode ,do nothing.");
+            } else {
+                ANInfo(@"didFinishSelect: user select access mode[%@]", selectAcsDesc);
+                [cell setCellText:selectAcsDesc];
+                [cell showActiveView:YES];
+                [cell setCellImage:ACCESS_MODE_IMAGE_INACTIVE_NAME];
+                dispatch_async(dispatch_get_main_queue(), ^{
+                    int ret = [self switchAccessMode:selectAcsDesc];
+                    NSString *errorMessage = nil;
+                    switch (ret) {
+                        case ERROR_ACM_SUCCESS:
+                            ANInfo(@"didFinishSelect:switch access mode successfully.");
+                            [cell showActiveView:NO];
+                            [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+                            break;
+                        case ERROR_ACM_SUCCESS_RECONN:
+                            ANInfo(@"didFinishSelect:switch access mode successfully.");
+                            ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+                            if (tunnelStatus == ArrayVPNConnected) {
+                                ANInfo(@"didFinishSelect:vpn status is connected, need reconnect.");
+                                self.needReconnect = YES;
+                                [self stopVPN];
+                            } else {
+                                [cell showActiveView:NO];
+                                [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+                            }
+                            break;
+                        case ERROR_ACM_WITHOUT_SESSION:
+                            errorMessage = NSLocalizedString(@"Switching failure: invalid user session. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_NAME_INVALID:
+                            errorMessage = NSLocalizedString(@"Switching failure: illegal mode information. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_NAME_NONE:
+                            errorMessage = NSLocalizedString(@"Switching failure: mode information does not exist. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_INVALID_PARAMETER:
+                            errorMessage = NSLocalizedString(@"Switching failure: incorrect parameter. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_ACL_CHANGE_FAILED:
+                            errorMessage = NSLocalizedString(@"Switching failure: the server fails to switch. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_NETWORK:
+                            errorMessage = NSLocalizedString(@"Switching failure: network error. Please switch again or contact the administrator.", nil);
+                            break;
+                        case ERROR_ACM_UNDEFINE:
+                            errorMessage = NSLocalizedString(@"Switching failure: unknown error. Please switch again or contact the administrator.", nil);
+                            break;
+                        default:
+                            errorMessage = NSLocalizedString(@"Switching failure: unknown error. Please switch again or contact the administrator.", nil);
+                            break;
+                    }
+                    if (errorMessage && errorMessage.length > 0) {
+                        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error",nil) message:errorMessage];
+                        [self presentViewController:dialog animated:YES completion:nil];
+                        [cell showActiveView:NO];
+                        [cell setCellText:currentAcsDesc];
+                        [cell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+                    } else {
+                        for (NSString *info in self.acsDescList) {
+                            if ([selectAcsDesc isEqualToString:info]) {
+                                self.acsSelectedInfo = info;
+                            }
+                        }
+                    }
+                    ANInfo(@"didFinishSelect:switch access mode finished, select access mode=%@.", self.acsSelectedInfo);
+                });
+            }
+        }
+    }
+}
+
+#pragma mark - Auto Logout
+- (void)handleAutoLogout:(NSNotification *)notification {
+    [self logoutSilently];
+}
+
+- (void)clearCookies {  // ANsession should be cleared on logout. (for WebAuth)
+#define MP_SESSION_PREFIX   @"ANsession"
+#define MP_USERNAME_COOKIE  @"username"
+#define MP_ACCESS_NAME      @"acs_mode"
+#define MP_ACCESS_DESC      @"acs_desc"
+    
+    NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
+    NSArray *cookies = cookieJar.cookies;
+    for (NSHTTPCookie *cookie in cookies) {
+        if (cookie.name) {
+            if ([cookie.name isEqualToString:MP_USERNAME_COOKIE] ||[cookie.name containsString:MP_SESSION_PREFIX] || [cookie.name containsString:MP_ACCESS_NAME] || [cookie.name containsString:MP_ACCESS_DESC]) {
+                [cookieJar deleteCookie:cookie];
+            }
+        }
+    }
+}
+
+#pragma mark - VPN Status
+#define STATUS_LABEL_COLOR_NORMAL   UIColorFromRGBA(0x666666, 1.0)
+#define STATUS_LABEL_COLOR_WARNING  UIColorFromRGBA(0xff0000, 1.0)
+#define STATUS_LABEL_COLOR_GREEN    UIColorFromRGBA(0x42a009, 1.0)
+
+- (void)setVPNStatusAsConnecting {
+    self.activityIndicator.hidden = NO;
+    [self.activityIndicator startAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_NORMAL;
+    self.statusLabel.text = NSLocalizedString(@"Connecting...", nil);
+    self.statusImageView.hidden = YES;
+    self.vpnEnableSwitch.on = YES;
+    [self showMessageViewWithInfo:nil];
+}
+
+- (void)setVPNSStatusAsConnected {
+    [self.activityIndicator stopAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_GREEN;
+    self.statusLabel.text = NSLocalizedString(@"Connected", nil);
+    self.statusImageView.image = [UIImage imageNamed:@"ResourceConnectSuccess"];
+    self.statusImageView.hidden = NO;
+    self.vpnEnableSwitch.on = YES;
+    [self showMessageViewWithInfo:nil];
+}
+
+- (void)setVPNStatusAsDisconnected {
+    [self.activityIndicator stopAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_NORMAL;
+    self.statusLabel.text = NSLocalizedString(@"Disconnected", nil);
+    self.statusImageView.image = [UIImage imageNamed:@"ResourceConnectError"];
+    self.statusImageView.hidden = NO;
+    self.vpnEnableSwitch.on = NO;
+    [self showMessageViewWithInfo:nil];
+    if (self.needReconnect) {
+        ANInfo(@"access mode disconnect vpn finished, now need restart vpn.");
+        self.needReconnect = NO;
+        [self accessModeRestartVPN];
+    }
+}
+
+- (void)setVPNStatusAsDisconnecting {
+    [self.activityIndicator startAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_NORMAL;
+    self.statusLabel.text = NSLocalizedString(@"Disconnecting...", nil);
+    self.statusImageView.hidden = YES;
+    self.vpnEnableSwitch.on = NO;
+    [self showMessageViewWithInfo:nil];
+}
+
+- (void)setVPNStatusAsError:(NSString *)errorMessage {
+    [self.activityIndicator stopAnimating];
+    self.statusLabel.textColor = STATUS_LABEL_COLOR_WARNING;
+    self.statusLabel.text = NSLocalizedString(@"Connect failed", nil);
+    self.statusImageView.image = [UIImage imageNamed:@"ResourceConnectError"];
+    self.statusImageView.hidden = NO;
+    self.vpnEnableSwitch.on = NO;
+    [self showMessageViewWithInfo:errorMessage];
+}
+
+- (void)showMessageViewWithInfo:(NSString *)info {
+    if (info) {
+        self.messageLabel.text = info;
+        self.messageView.hidden = NO;
+    } else {
+        self.messageLabel.text = @"";
+        self.messageView.hidden = YES;
+    }
+}
+
+- (void)showEmptyResouceView {
+    self.emptyResourceView.hidden = NO;
+    self.resourceTableView.hidden = YES;
+    [self.view bringSubviewToFront:self.emptyResourceView];
+}
+
+- (void)showResourceTableView {
+    self.emptyResourceView.hidden = YES;
+    self.resourceTableView.hidden = NO;
+    [self.view bringSubviewToFront:self.resourceTableView];
+}
+
+#pragma mark - VPN Related
+- (BOOL)autoStartVPN {
+    BOOL isAutoStart = NO;
+    Gateway *gateway = [self getCurrentGateway];
+    
+    if (!gateway) {
+        isAutoStart = YES;
+        ANInfo(@"No gateway is selected, it is auto start vpn.");
+    } else {
+        if (!gateway.isSecureTunnelEnabled) {
+            ANInfo(@"Auto start VPN is not enabled.");
+            return NO;
+        }
+    }
+
+    return [self startVPN:isAutoStart];
+}
+
+- (BOOL)startVPN:(BOOL)isAutoStart {
+    //Gateway *gateway = [self getCurrentGateway];
+    //NSString *session = [AAAManager sharedInstance].sessionID;
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    
+#if TARGET_OS_IPHONE
+    //Reset connect fail reason.
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameResource];
+    [userDefaults removeObjectForKey:@"tunnel_result"];
+    [userDefaults removeObjectForKey:@"dns_list"];
+#endif
+    
+    [vpnWrapper startSSLVPN];
+    
+#if TARGET_OS_IPHONE
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleVPNTunnelError:)
+                                                 name:kArrayVPNTunelErrorMsgResource object:nil];
+#endif
+    
+    return YES;
+    
+//    if (isAutoStart) {
+//        [vpnWrapper startSSLVPN];
+//    }
+//
+//    return [vpnWrapper validateSessionWithHost:gateway.host
+//                                          port:gateway.port
+//                                       session:session
+//                                    completion:^(BOOL isSuccess, NSError *error) {
+//                                        if (isSuccess) {
+//                                            [vpnWrapper startSSLVPN];
+//                                        } else {
+//                                            NSString *message = NSLocalizedString(@"Session is invalid, please login again!", nil);
+//                                            PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+//                                                                                                          message:message
+//                                                                                                           action:^{
+//                                                                                                               [[NSNotificationCenter defaultCenter]
+//                                                                                                                postNotificationName:kAutoLogoutNotification
+//                                                                                                                object:nil];
+//                                                                                                           }];
+//                                            [self presentViewController:dialog animated:YES completion:nil];
+//                                        }
+//                                    }];
+}
+
+- (void)stopVPN {
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    [vpnWrapper stopSSLVPN];
+}
+
+- (void)stopVPNAndLogout:(BOOL)isSilent {
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{  // Stop timer rules fisrt.
+        [[RulesManager sharedInstance] stopAllRules];
+    });
+    
+    AAAManager *manager = [AAAManager sharedInstance];
+    [manager continueVPNThreadWithAccount:nil];
+    [self stopVPN];
+    
+    [self clearCookies];
+    
+    if (!isSilent) {
+        __weak typeof(self) weakSelf = self;
+        [self.view makeToastActivity:CSToastPositionCenter];
+        dispatch_async(dispatch_get_global_queue(0, 0), ^{
+            NSInteger ret = [[AAAManager sharedInstance] stopL3VPNDirectly];
+            if (ret != ERR_SUCCESS) {
+                ANError(@"Logout failed with error code: %zi.", ret);
+            }
+            
+            __strong typeof(weakSelf) strongSelf = weakSelf;
+            dispatch_async(dispatch_get_main_queue(), ^{
+                [strongSelf.view hideToastActivity];
+                [strongSelf dismissViewControllerAnimated:YES completion:nil];
+            });
+        });
+    }
+}
+
+- (void)logoutSilently {
+    [self stopVPNAndLogout:YES];
+    
+    [self.navigationController dismissViewControllerAnimated:NO completion:nil];  // Dismiss modal view if exists.
+    [self dismissViewControllerAnimated:YES completion:nil];
+}
+
+- (Gateway *)getCurrentGateway {
+    VPNAccount *account = [AAAManager sharedInstance].account;
+    GatewayManager *gm = [GatewayManager sharedInstance];
+    NSString *url = account.vsURL;
+    NSString *port = account.vsPort;
+    NSInteger index = [gm indexOfUrl:url andport:port];
+    
+    return [gm gatewayAtIndex:index];
+}
+
+#pragma mark - VPN Status Handler
+- (void)handleVPNStatus:(NSNotification *)notification {
+    ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+    
+    ANDebug(@"Array VPN tunnel status = %zi", tunnelStatus);
+    
+    [self updateUIWithVPNStatus:tunnelStatus];
+}
+
+- (void)updateUIWithVPNStatus:(ArrayVPNStatus)status {
+    switch (status) {
+        case ArrayVPNInavlid:
+        case ArrayVPNDisconnected:
+            [self setVPNStatusAsDisconnected];
+            break;
+        case ArrayVPNDisconnecting:
+            [self setVPNStatusAsDisconnecting];
+            break;
+        case ArrayVPNConnecting:
+        case ArrayVPNReasserting:
+            [self setVPNStatusAsConnecting];
+            break;
+        case ArrayVPNConnected:
+            [self setVPNSStatusAsConnected];
+            break;
+            
+        default:
+            break;
+    }
+}
+
+- (void)handleVPNTunnelError:(NSNotification *)notification {
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    NSString *errMessage = [vpnWrapper getErrorMsgWithCode];
+    if (errMessage && errMessage.length > 0) {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING",nil) message:errMessage];
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+#pragma mark - Number of Sections & Rows
+- (BOOL)isWebAppToShow {
+    PortalTabsConfiguration *portalConfiguration = [ConfigurationManager sharedInstance].portalTabs;
+    
+    return portalConfiguration.isWebAppConfigured && self.model.webApps.children.count > 0;
+}
+
+- (BOOL)isNativeAppToShow {
+    PortalTabsConfiguration *portalConfiguration = [ConfigurationManager sharedInstance].portalTabs;
+    
+    return portalConfiguration.isNativeAppConfigured && self.model.nativeApps.children.count > 0;
+}
+
+- (BOOL)isDesktopToShow {
+    PortalTabsConfiguration *portalConfiguration = [ConfigurationManager sharedInstance].portalTabs;
+    
+    return portalConfiguration.isDesktopConfigured && self.model.desktopApps.resourceItems.count > 0;
+}
+
+- (NSInteger)totalSections {
+    NSInteger totalSections = 0;
+    NSInteger webSection = [self isWebAppToShow] ? 1 : 0;
+    NSInteger nativeSection = [self isNativeAppToShow] ? 1 : 0;
+    NSInteger desktopSection = [self isDesktopToShow] ? 1 : 0;
+    
+    totalSections = webSection + nativeSection + desktopSection;
+    
+    return totalSections;
+}
+
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([segue.identifier isEqualToString:kSegueToSubResource]) {
+        SubResourceViewController *viewController = segue.destinationViewController;
+        [viewController setupModel:(NSArray *)sender];
+    }
+    if ([segue.identifier isEqualToString:kSegueToAccessModeSelect]) {
+        NSArray *cells = [self cellsForTableView:self.acsModeTableView];
+        if ([cells count] == 1) {
+            UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
+            AccessModeSelectViewController *controller = (AccessModeSelectViewController *)navController.topViewController;
+            controller.selectedAcsModeString = self.acsSelectedInfo;
+            controller.delegate = self;
+        }
+    }
+}
+
+#pragma mark - Get Child at Index
+- (NSArray *)didSelectWebAppAtIndexPath:(NSIndexPath *)indexPath {
+    NSInteger row = indexPath.row;
+    
+    if (row >= self.model.webApps.children.count) {
+        ANError(@"Index (%zi) is out range of web apps count.", row);
+        return nil;
+    }
+    
+    WebApp *app = [self.model.webApps.children objectAtIndex:row];
+    if (app.type == APP_TYPE_WEBAPP) {
+        ZTWKWebViewController *control = [[ZTWKWebViewController alloc] init];
+        control.webUrl = [app.url absoluteString];
+        [self.navigationController pushViewController:control animated:YES];
+
+        
+        return nil;
+    }
+    
+    return app.children;
+}
+
+- (NSArray *)didSelectNativeAppAtIndexPath:(NSIndexPath *)indexPath {
+    NSInteger row = indexPath.row;
+    
+    if (row >= self.model.nativeApps.children.count) {
+        ANError(@"Index (%zi) is out range of native apps count.", row);
+        return nil;
+    }
+    
+    NativeApp *app = [self.model.nativeApps.children objectAtIndex:row];
+    NSURL *url = [NSURL URLWithString:app.scheme];
+    if (url.scheme == nil) {
+        url = [NSURL URLWithString:[NSString stringWithFormat:@"%@://", app.scheme]];
+    }
+    
+    ANInfo(@"open app url=%@", url);
+    if (!OpenURL(url)) {
+        BOOL isAppStoreApp = (app.installUrl != nil);
+        if (!isAppStoreApp) {
+            NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Application %@ has not been installed, Would you like to search it on App Store?", nil), app.name];
+            PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:@""
+                                                                           message:message
+                                                                     confirmAction:^{
+                                                                         NSString *string = [NSString stringWithFormat:APPSTORE_SEARCH_STRING,
+                                                                                             [app.name stringByAddingPercentEncodingWithAllowedCharacters:
+                                                                                              NSCharacterSet.URLQueryAllowedCharacterSet]];
+                                                                         OpenURL([NSURL URLWithString:string]);
+                                                                     }
+                                                                      cancelAction:nil];
+            
+            [self presentViewController:dialog animated:YES completion:nil];
+        } else {
+            NSString *urlString = [NSString stringWithFormat:ITMS_SERVICE_PREFIX, app.installUrl];
+            ANInfo(@"Download app url=%@, scheme=%@", urlString, app.scheme);
+            if ([app.scheme containsString:@"voffice"]) {
+                urlString = @"http://app.arraynetworks.com.cn/voffice2";
+            }
+            if ([app.scheme containsString:@"zrOA"]) {
+                urlString = @"http://app.arraynetworks.com.cn/sufei";
+            }
+            if ([app.scheme containsString:@"zrlcsApp"]) {
+                urlString = @"http://app.arraynetworks.com.cn/staf";
+            }
+            OpenURL([NSURL URLWithString:urlString]);  // Install directly from AG.
+        }
+    }
+    
+    return nil;
+}
+
+- (NSArray *)didSelectDesktopAtIndexPath:(NSIndexPath *)indexPath {
+    NSInteger row = indexPath.row;
+    
+    if (row >= self.model.desktopApps.resourceItems.count) {
+        ANError(@"Index (%zi) is out range of desktop apps count.", row);
+        return nil;
+    }
+    
+    FolderItem *item = [self.desktops objectAtIndex:row];
+    if ([item isKindOfClass:[GCustomItem class]] && [item.name isEqualToString:NSLocalizedString(@"Other", nil)]) {
+        [self performSegueWithIdentifier:kSegueToCustomDesktop sender:self];
+        return nil;
+    } else if ([item isKindOfClass:[HostItem class]]) {
+        [self didSelectHostItem:(HostItem *)item atIndexPath:indexPath];
+        return nil;
+    }
+    
+    return [self getSortedArray:[item.resourceItems allValues]];
+}
+
+#pragma mark - DesktopDirect
+- (void)didSelectHostItem:(HostItem *)hostItem atIndexPath:(NSIndexPath *)indexPath {
+    if (self.currentIndex
+        && self.currentIndex.row == indexPath.row
+        && hostItem.status < ResourceStatusReady) {
+        return;
+    }
+    
+    self.currentIndex = indexPath;
+    self.currentItem = hostItem;
+    
+    ResourceCell *cell = (ResourceCell *)[self.resourceTableView cellForRowAtIndexPath:indexPath];
+    
+    __weak typeof(self) weakSelf = self;
+    [self.kvoController observe:hostItem
+                        keyPath:@"status"
+                        options:NSKeyValueObservingOptionNew
+                          block:^(ResourcesViewController *observer, HostItem *host, NSDictionary *change) {
+                              NSInteger hostStatus = host.status;
+                              dispatch_async(dispatch_get_main_queue(), ^{
+                                  [cell updateUI:host];
+                                  if (observer.currentIndex.row != indexPath.row) {
+                                      return;
+                                  }
+                                  
+                                  if (observer.silence) {
+                                      return;
+                                  }
+                                  if (host.status == ResourceStatusReady) {
+                                      [observer.kvoController unobserve:host];
+                                      NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
+                                      AppManager *appManager = [AppManager sharedInstance];
+                                      BOOL cliEnabledNEC = NO;
+                                      NSString *enabledNEC = appManager.desktopSettings.settings[@"jp-rdp"];
+                                      if (enabledNEC && [enabledNEC isEqualToString:@"1"])
+                                          cliEnabledNEC = YES;
+                                      if (cliEnabledNEC || [userDefaults integerForKey:@"desktop_client_vendor"] == 1) {
+                                          [observer openRDClientNEC:host];
+                                      } else {
+                                          [observer openRDClient:host];
+                                      }
+                                      // Reset power state
+                                      host.powerState = HostPowerStateDown;
+                                      return;
+                                  } else if (hostStatus >= ResourceStatusFailed && hostStatus < ResourceStatusResolveHostNameFailed) {
+                                      ANError(@"Cannot connect to remote host, error code: %zi", hostStatus);
+                                      
+                                      if (hostStatus == ResourceStatusPowerDown) {
+                                          NSString *message = NSLocalizedString(@"It seems the remote host is turned off. Would you like to try and wake it up?", nil);
+                                          
+                                          PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Cannot connect to remote host", nil)
+                                                                                                         message:message
+                                                                                                   confirmAction:^{
+                                                                                                       NSInteger row = weakSelf.currentIndex.row;
+                                                                                                       HostItem *host = weakSelf.desktops[row];
+                                                                                                       [host wakeUp];
+                                                                                                   }
+                                                                                                    cancelAction:nil];
+                                          
+                                          [weakSelf presentViewController:dialog animated:YES completion:nil];
+                                          
+                                          return;
+                                      } else {
+                                          [observer.kvoController unobserve:host];
+                                      }
+                                  }
+                              });
+                          }];
+    
+    [hostItem prepare];
+}
+
+- (void)openRDClient:(HostItem *)hostItem {
+    NSURL *url = hostItem.url;
+    if (!url) {
+        return;
+    }
+    
+    if (!OpenURL(url)) {
+        NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Application %@ has not been installed, Would you like to search it on App Store?", nil), @"RD client"];
+        PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Cannot connect to remote host", nil)
+                                                                       message:message
+                                                                 confirmAction:^{
+                                                                     NSString *string = [NSString stringWithFormat:APPSTORE_SEARCH_STRING,
+                                                                                         [@"RD client" stringByAddingPercentEncodingWithAllowedCharacters:
+                                                                                          NSCharacterSet.URLQueryAllowedCharacterSet]];
+                                                                     
+                                                                     OpenURL([NSURL URLWithString:string]);
+                                                                 }
+                                                                  cancelAction:nil];
+        
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+- (void)openRDClientNEC:(HostItem *)hostItem {
+    NSURL *url = hostItem.urlVendorNEC;
+    if (!url) {
+        return;
+    }
+    
+    if (!OpenURL(url)) {
+        NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Application %@ has not been installed, Would you like to search it on App Store?", nil),@"RD"];
+        PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Cannot connect to remote host", nil)
+                                                                       message:message
+                                                                 confirmAction:^{
+                                                                     NSString *string = @"https://itunes.apple.com/jp/app/rd-v1.3/id771611106?mt=8";
+                                                                     OpenURL([NSURL URLWithString:string]);
+                                                                 }
+                                                                  cancelAction:nil];
+        
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+- (NSArray *)desktops {
+    if (!_desktops) {
+        _desktops = [self getSortedArray:[self.model.desktopApps.resourceItems allValues]];
+    }
+    
+    return _desktops;
+}
+
+- (NSArray *)getSortedArray:(NSArray *)array {
+    if (!array || array.count == 0) {
+        ANWarn(@"Empty array, should not be sorted.");
+        return nil;
+    }
+    
+    NSSortDescriptor *byClass = [NSSortDescriptor sortDescriptorWithKey:@"class" ascending:YES comparator:^NSComparisonResult(id obj1, id obj2) {
+        // Sort by class name
+        return [NSStringFromClass(obj1) compare:NSStringFromClass(obj2)];
+        
+    }];
+    
+    NSSortDescriptor *byName = [NSSortDescriptor sortDescriptorWithKey:@"name"
+                                                             ascending:YES
+                                                              selector:@selector(localizedStandardCompare:)];
+    
+    NSArray *sortDescriptors = [NSArray arrayWithObjects:byClass, byName, nil];
+    
+    return [array sortedArrayUsingDescriptors:sortDescriptors];
+}
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    if ([tableView isEqual:self.resourceTableView]) {
+        return [self totalSections];
+    } else if ([tableView isEqual:self.acsModeTableView]) {
+        return 1;
+    }
+    
+    return 0;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    if ([tableView isEqual:self.resourceTableView]) {
+        NSInteger totalSections = [self totalSections];
+        if (section > totalSections) {
+            ANError(@"Section (%zi) is larger than total sections (%zi).", section, totalSections);
+            
+            return 0;
+        }
+        
+        __weak typeof(self) weakSelf = self;
+        NSNumber *result = [self getCellInfoInSection:section
+                                         totalSection:totalSections
+                                               object:nil
+                                              action1:^id(id param) {
+                                                  __strong typeof(weakSelf) strongSelf = weakSelf;
+                                                  NSInteger rows = strongSelf.model.webApps.children.count;
+                                                  return [NSNumber numberWithInteger:rows];
+                                              }
+                                              action2:^id(id param) {
+                                                  __strong typeof(weakSelf) strongSelf = weakSelf;
+                                                  NSInteger rows = strongSelf.model.nativeApps.children.count;
+                                                  return [NSNumber numberWithInteger:rows];
+                                              }
+                                              action3:^id(id param) {
+                                                  __strong typeof(weakSelf) strongSelf = weakSelf;
+                                                  NSInteger rows = strongSelf.model.desktopApps.resourceItems.count;
+                                                  return [NSNumber numberWithInteger:rows];
+                                              }];
+        
+        return [result integerValue];
+    } else if ([tableView isEqual:self.acsModeTableView]) {
+        return 1;
+    }
+    
+    return 0;
+}
+
+- (UITableViewCell *)configureWebAppWithRow:(NSInteger)row {
+    ResourceCell *cell = [self.resourceTableView dequeueReusableCellWithIdentifier:kResourceCellID];
+    if (!cell) {
+        cell = [[ResourceCell alloc] init];
+    }
+    
+    WebApp *app = [self.model.webApps.children objectAtIndex:row];
+    UIImage *image = nil;
+    BOOL isFolder = app.type == APP_TYPE_FOLDER;
+    if (isFolder) {
+        image = [UIImage imageNamed:FOLDER_APP_IMAGE_NAME];
+    } else {
+        image = [UIImage imageNamed:WEB_APP_IMAGE_NAME];
+        UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self
+                                                                                                       action:@selector(cellLongPressed:)];
+        [cell addGestureRecognizer:longPressGesture];
+    }
+    [cell configureCellWithImage:image name:app.name isFolder:isFolder];
+    
+    return cell;
+}
+
+- (UITableViewCell *)configureNativeAppWithRow:(NSInteger)row {
+    NativeAppCell *cell = [self.resourceTableView dequeueReusableCellWithIdentifier:kNativeAppCellID];
+    if (!cell) {
+        cell = [[NativeAppCell alloc] init];
+    }
+    
+    NativeApp *app = [self.model.nativeApps.children objectAtIndex:row];
+    UIImage *image = nil;
+    if (app.customIcon) {
+        image = app.customIcon;
+    } else if (app.appIcon) {
+        image = app.appIcon;
+    } else {
+        image = [UIImage imageNamed:NATIVE_APP_IMAGE_NAME];
+    }
+    [cell configureCellWithImage:image name:app.name isFolder:NO];  // Native app doesn't support folder.
+    [cell setDescriptionContent:app.desc];
+    
+    return cell;
+}
+
+- (UITableViewCell *)configureDesktopAppWithRow:(NSInteger)row {
+    ResourceCell *cell = [self.resourceTableView dequeueReusableCellWithIdentifier:kResourceCellID];
+    if (!cell) {
+        cell = [[ResourceCell alloc] init];
+    }
+    
+    ResourceItem *item = [self.desktops objectAtIndex:row];
+    BOOL isFolder = [item isKindOfClass:[FolderItem class]];  // Only pub-app & self-defined desktop has folder.
+    BOOL isCustomDesktop = [item isKindOfClass:[GCustomItem class]];
+    if (isCustomDesktop) {
+        isFolder = YES;
+    }
+    UIImage *image = nil;
+    if (item.icon != nil) {
+        if ([item.description containsString:@"http.ico"]) {
+            image = [UIImage imageNamed:ZRT_HTTP_IMAGE_NAME];
+        } else if ([item.description containsString:@"HSValuate1.ico"]) {
+            image = [UIImage imageNamed:ZRT_HSVALUATE1_IMAGE_NAME];
+        } else if ([item.description containsString:@"HSValuate2.ico"]) {
+            image = [UIImage imageNamed:ZRT_HSVALUATE2_IMAGE_NAME];
+        } else if ([item.description containsString:@"fundclient1.ico"]) {
+            image = [UIImage imageNamed:ZRT_FUNDCLIENT1_IMAGE_NAME];
+        } else if ([item.description containsString:@"fundclient2.ico"]) {
+            image = [UIImage imageNamed:ZRT_FUNDCLIENT2_IMAGE_NAME];
+        } else {
+            image = item.icon;
+        }
+    } else {
+        image = (isFolder && !isCustomDesktop) ? [UIImage imageNamed:FOLDER_APP_IMAGE_NAME] : [UIImage imageNamed:DESKTOP_IMAGE_NAME];
+    }
+    [cell configureCellWithImage:image name:item.name isFolder:isFolder];
+    
+    return cell;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell *cell = nil;
+    if ([tableView isEqual:self.resourceTableView]) {
+        NSInteger row = indexPath.row;
+        NSInteger section = indexPath.section;
+        NSInteger totalSections = [self totalSections];
+        
+        __weak typeof(self) weakSelf = self;
+        cell = [self getCellInfoInSection:section
+                             totalSection:totalSections
+                                   object:[NSNumber numberWithInteger:row]
+                                  action1:^id(id param) {
+                                      __strong typeof(weakSelf) strongSelf = weakSelf;
+                                      NSInteger row = [(NSNumber *)param integerValue];
+                                      return [strongSelf configureWebAppWithRow:row];
+                                  }
+                                  action2:^id(id param) {
+                                      __strong typeof(weakSelf) strongSelf = weakSelf;
+                                      NSInteger row = [(NSNumber *)param integerValue];
+                                      return [strongSelf configureNativeAppWithRow:row];
+                                  }
+                                  action3:^id(id param) {
+                                      __strong typeof(weakSelf) strongSelf = weakSelf;
+                                      NSInteger row = [(NSNumber *)param integerValue];
+                                      return [strongSelf configureDesktopAppWithRow:row];
+                                  }];
+    } else if([tableView isEqual:self.acsModeTableView]) {
+        if ([self.acsDescList count] > 0) {
+            AccessModeCell *accessModeCell = [self.acsModeTableView dequeueReusableCellWithIdentifier:kAccessModeCellID];
+            if (!accessModeCell) {
+                accessModeCell = [[AccessModeCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kAccessModeCellID];
+            }
+            NSString *showAcsDesc = [self.acsDescList objectAtIndex:0];
+            if ([self.acsDescList count] > 1) {
+                showAcsDesc = [NSString stringWithFormat:@"%@...", showAcsDesc];
+            }
+            
+            [accessModeCell configureCellWithMessage:showAcsDesc isDescList:NO];
+            [accessModeCell setCellImage:ACCESS_MODE_IMAGE_ACTIVE_NAME];
+            
+            return accessModeCell;
+        } else {
+            cell = [[UITableViewCell alloc] init];
+        }
+        
+    }
+    
+    return cell;
+}
+
+- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
+    NSString *title = @"";
+    if ([tableView isEqual:self.resourceTableView]) {
+        NSInteger totalSections = [self totalSections];
+
+        title = [self getCellInfoInSection:section
+                              totalSection:totalSections
+                                    object:nil
+                                   action1:^id(id param) {
+                                       return NSLocalizedString(@"Web App", nil);
+                                   }
+                                   action2:^id(id param) {
+                                       return NSLocalizedString(@"Native App", nil);
+                                   }
+                                   action3:^id(id param) {
+                                       return NSLocalizedString(@"Remote Desktop", nil);
+                                   }];
+    }
+
+    return title;
+}
+
+#pragma mark - Long press handler for WebApp
+- (void)cellLongPressed:(UIGestureRecognizer *)recognizer {
+    if (recognizer.state == UIGestureRecognizerStateBegan) {
+        CGPoint location = [recognizer locationInView:self.resourceTableView];
+        NSIndexPath *indexPath = [self.resourceTableView indexPathForRowAtPoint:location];
+        _longPressedIndex = indexPath.row;
+        ResourceCell *cell = [self.resourceTableView cellForRowAtIndexPath:indexPath];
+        
+        [self showMenuWithCell:cell];
+    }
+}
+
+- (void)showMenuWithCell:(ResourceCell *)cell {
+    [cell becomeFirstResponder];
+    
+    UIMenuController *controller = [UIMenuController sharedMenuController];
+    UIMenuItem *openItem = [[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Open in Safari", nil) action:@selector(openWebPage:)];
+    [controller setMenuItems:[NSArray arrayWithObjects:openItem, nil]];
+    [controller setTargetRect:cell.contentView.frame inView:cell.contentView];
+    [controller setMenuVisible:YES animated:YES];
+}
+
+- (void)openWebPage:(id)sender {
+    if (_longPressedIndex >= self.model.webApps.children.count) {
+        ANError(@"Index (%zi) is out range of web apps count.", _longPressedIndex);
+        return;
+    }
+    
+    WebApp *app = [self.model.webApps.children objectAtIndex:_longPressedIndex];
+    if (app.type == APP_TYPE_WEBAPP) {
+        [[UIApplication sharedApplication] openURL:app.url];
+    }
+}
+
+#pragma mark - TimerRuleDelegate
+- (void)shouldSignOut {
+    [self logoutSilently];
+}
+
+#pragma mark - UITableViewDelegate
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    if ([tableView isEqual:self.resourceTableView]) {
+        [self.resourceTableView deselectRowAtIndexPath:indexPath animated:YES];
+        
+        NSInteger totalSections = [self totalSections];
+        NSInteger section = indexPath.section;
+        NSArray *children = nil;
+        
+        __weak typeof(self) weakSelf = self;
+        children = [self getCellInfoInSection:section
+                                 totalSection:totalSections
+                                       object:indexPath
+                                      action1:^id(id param) {
+                                          __strong typeof(weakSelf) strongSelf = weakSelf;
+                                          return [strongSelf didSelectWebAppAtIndexPath:indexPath];
+                                      }
+                                      action2:^id(id param) {
+                                          __strong typeof(weakSelf) strongSelf = weakSelf;
+                                          return [strongSelf didSelectNativeAppAtIndexPath:indexPath];
+                                      }
+                                      action3:^id(id param) {
+                                          __strong typeof(weakSelf) strongSelf = weakSelf;
+                                          return [strongSelf didSelectDesktopAtIndexPath:indexPath];
+                                      }];
+        
+        if (children != nil) {
+            [self performSegueWithIdentifier:kSegueToSubResource sender:children];
+        }
+    } else if ([tableView isEqual:self.acsModeTableView]) {
+        [self.acsModeTableView deselectRowAtIndexPath:indexPath animated:YES];
+        if ([self.acsDescList count] > 0) {
+            [self performSegueWithIdentifier:kSegueToAccessModeSelect sender:self];
+        }
+    }
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    if ([tableView isEqual:self.resourceTableView]) {
+        return 39;
+    } 
+    
+    return 0;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
+    if ([tableView isEqual:self.resourceTableView]) {
+        static CGFloat kDefaultCellHeight = 44.0;
+        static CGFloat kNativeCellHeight = 66.0;
+        NSInteger section = indexPath.section;
+        NSInteger totalSections = [self totalSections];
+        
+        NSNumber *result = [self getCellInfoInSection:section
+                                         totalSection:totalSections
+                                               object:nil
+                                              action1:^id(id param) {
+                                                  return [NSNumber numberWithFloat:kDefaultCellHeight];
+                                              }
+                                              action2:^id(id param) {
+                                                  return [NSNumber numberWithFloat:kNativeCellHeight];
+                                              }
+                                              action3:^id(id param) {
+                                                  return [NSNumber numberWithFloat:kDefaultCellHeight];
+                                              }];
+        
+        return [result integerValue];
+    } else if ([tableView isEqual:self.acsModeTableView]) {
+        return 44;
+    }
+    
+    return 0;
+}
+
+#pragma mark - Helper
+typedef id (^Action)(id param);
+
+- (id)getCellInfoInSection:(NSInteger)section
+              totalSection:(NSInteger)totalSection
+                    object:(id)object
+                   action1:(Action)action1
+                   action2:(Action)action2
+                   action3:(Action)action3 {
+    id result = nil;
+    
+    switch (totalSection) {
+        case kResourceSectionOne: {
+            if ([self isWebAppToShow]) {
+                result = action1(object);
+            } else if ([self isNativeAppToShow]) {
+                result = action2(object);
+            } else if ([self isDesktopToShow]) {
+                result = action3(object);
+            }
+            break;
+        }
+        case kResourceSectionTwo:
+            if ([self isWebAppToShow]) {
+                if ([self isNativeAppToShow]) {
+                    if (section == kResourceSectionIndex0) {
+                        result = action1(object);
+                    } else if (section == kResourceSectionIndex1) {
+                        result = action2(object);
+                    }
+                } else if ([self isDesktopToShow]) {
+                    if ([self isDesktopToShow]) {
+                        if (section == kResourceSectionIndex0) {
+                            result = action1(object);
+                        } else if (section == kResourceSectionIndex1) {
+                            result = action3(object);
+                        }
+                    }
+                }
+            } else if ([self isNativeAppToShow]) {
+                if ([self isDesktopToShow]) {
+                    if (section == kResourceSectionIndex0) {
+                        result = action2(object);
+                    } else if (section == kResourceSectionIndex1) {
+                        result = action3(object);
+                    }
+                }
+            }
+            break;
+        case kResourceSectionThree:
+            if (section == kResourceSectionIndex0) {
+                result = action1(object);
+            } else if (section == kResourceSectionIndex1) {
+                result = action2(object);
+            } else if (section == kResourceSectionIndex2) {
+                result = action3(object);
+            }
+            break;
+            
+        default:
+            ANError(@"Invalid sections number of (%zi) received.", section);
+            break;
+    }
+    
+    return result;
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMSViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMSViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMSViewController.h	(working copy)
@@ -0,0 +1,13 @@
+//
+//  SMSViewController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/28.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface SMSViewController : UIViewController
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMSViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMSViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMSViewController.m	(working copy)
@@ -0,0 +1,223 @@
+//
+//  SMSViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/28.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "AAAManager.h"
+#import "ANPopupDialog.h"
+#import "UIViewController+Activity.h"
+#import "UIViewController+HideKeyboard.h"
+#import "SMSViewController.h"
+
+#define TOTAL_SECTIONS      1
+#define TOTAL_ROWS          1
+
+static NSString * const kValidateCodeCellID = @"ValidateCodeCellID";
+static NSInteger const kTextFieldTag = 1;
+static NSInteger const kButtonTag = 2;
+static NSInteger kValidateCodeCellSection = 0;
+static NSInteger kValidateCodeCellRow = 0;
+
+static NSInteger const defaultResendInterval = 30;
+static NSInteger const defaultResendMax = 2;
+static NSInteger resendCount = 0;
+
+@interface SMSViewController () <UITableViewDataSource, UITableViewDelegate>
+
+@property (weak, nonatomic) IBOutlet UIButton *loginButton;
+@property (weak, nonatomic) IBOutlet UITableView *tableView;
+
+@property (strong, nonatomic) UIButton *resendButton;
+
+@property (nonatomic) NSInteger resendInterval;
+@property (nonatomic, strong) NSTimer *timer;
+
+@end
+
+@implementation SMSViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    [self enableHideKeyboard];
+    [self initLoginButtonAppearance];
+}
+
+- (void)viewDidDisappear:(BOOL)animated {
+    [super viewDidDisappear:animated];
+    
+    resendCount = 0;
+    [self stopTimer];
+}
+
+- (void)viewDidAppear:(BOOL)animated {
+    [super viewDidAppear:animated];
+    
+    [self countdownFromSecond:defaultResendInterval-1];
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (IBAction)loginButtonClicked:(id)sender {
+    NSString *code = [self getValidateCodeTextField].text;
+    VPNAccount *account = [[VPNAccount alloc] init];
+    account.passWord = code;
+    
+    [[AAAManager sharedInstance] continueVPNThreadWithSMSAccount:account];
+    
+    [self stopTimer];
+    [self showLoginActivity:YES];
+}
+
+- (void)initResendButtonWithCell:(UITableViewCell *)cell {
+    if (!self.resendButton) {
+        self.resendButton = [cell viewWithTag:kButtonTag];
+        self.resendButton.layer.cornerRadius = 2.5;
+        self.resendButton.layer.borderWidth = 1.0;
+        self.resendButton.showsTouchWhenHighlighted = YES;
+        [self setResendButtonAsDisabledWithTitle:NSLocalizedString(@"Resend", nil)];
+        
+        [self.resendButton addTarget:self action:@selector(resendButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
+    }
+}
+
+- (void)resendButtonClicked:(id)sender {
+    AAAManager *manager = [AAAManager sharedInstance];
+    
+    if (++resendCount > defaultResendMax) {
+        NSString *message = NSLocalizedString(@"Your attempt to sign in failed, because you have resent verification code for too many times.", nil);
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@""
+                                                                      message:message];
+        [self presentViewController:dialog animated:YES completion:nil];
+        
+        [manager cancelLogin];
+        
+        return;
+    }
+    
+    [manager resendSMSVerificationCode];
+    
+    [self getValidateCodeTextField].text = nil;
+    [self countdownFromSecond:defaultResendInterval];
+}
+
+- (IBAction)cancelButtonClicked:(id)sender {
+    [self showLoginActivity:NO];
+    
+    [[AAAManager sharedInstance] cancelLoginTapped];
+}
+
+- (void)stopTimer {
+    [self.timer invalidate];
+    self.timer = nil;
+}
+
+- (void)countdownInterval:(NSTimer *)timer {
+    self.resendInterval = _resendInterval - 1;
+    if (_resendInterval == 0) {
+        [timer invalidate];
+        self.timer = nil;
+    }
+}
+
+- (void)countdownFromSecond:(NSInteger)number {
+    self.resendInterval = number;
+    
+    self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(countdownInterval:) userInfo:nil repeats:YES];
+}
+
+- (UITextField *)getValidateCodeTextField {
+    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:kValidateCodeCellRow inSection:kValidateCodeCellSection];
+    UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
+    
+    return (UITextField *)[cell viewWithTag:kTextFieldTag];
+}
+
+- (void)setResendInterval:(NSInteger)resendInterval {
+    NSString *buttonTitle = NSLocalizedString(@"Resend", @"Resend SMS Verification Code");
+    
+    _resendInterval = resendInterval;
+    
+    if (resendInterval == 0) {
+        [self setResendButtonAsNormalWithTitle:buttonTitle];
+    } else {
+        buttonTitle = [NSString stringWithFormat:@"%@(%zi)", buttonTitle, resendInterval];
+        [self setResendButtonAsDisabledWithTitle:buttonTitle];
+    }
+}
+
+- (void)setResendButtonAsNormalWithTitle:(NSString *)title {
+    self.resendButton.enabled = YES;
+    self.resendButton.layer.borderColor = MAIN_COLOR.CGColor;
+    [self.resendButton setTitle:title forState:UIControlStateNormal];
+    [self.resendButton setTitleColor:MAIN_COLOR forState:UIControlStateNormal];
+    [self.resendButton setTitleColor:UIColorFromRGBA(0x999999, 1.0) forState:UIControlStateHighlighted];
+}
+
+- (void)setResendButtonAsDisabledWithTitle:(NSString *)title {
+    self.resendButton.enabled = NO;
+    self.resendButton.layer.borderColor = UIColorFromRGBA(0x999999, 1.0).CGColor;
+    [self.resendButton setTitle:title forState:UIControlStateDisabled];
+    [self.resendButton setTitleColor:UIColorFromRGBA(0x999999, 1.0) forState:UIControlStateDisabled];
+}
+
+- (void)refreshView {
+    [self showLoginActivity:NO];
+    
+    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@""
+                                                                  message:NSLocalizedString(@"The verification code is wrong, please enter the right one", nil)];
+    [self presentViewController:dialog animated:YES completion:nil];
+    
+    [self getValidateCodeTextField].text = nil;
+    [self countdownFromSecond:defaultResendInterval];
+}
+
+- (void)initLoginButtonAppearance {
+    self.loginButton.layer.cornerRadius = 2.5;
+    self.loginButton.layer.shadowOffset = CGSizeMake(5.0, 5.0);
+    self.loginButton.layer.shadowColor = MAIN_COLOR.CGColor;
+    self.loginButton.layer.shadowOpacity = 0.25;
+}
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return TOTAL_SECTIONS;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return TOTAL_ROWS;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell *cell = nil;
+    NSInteger section = indexPath.section;
+    NSInteger row = indexPath.row;
+    if (section == kValidateCodeCellSection && row == kValidateCodeCellRow) {
+        cell = [self.tableView dequeueReusableCellWithIdentifier:kValidateCodeCellID];
+        if (cell) {
+            [self initResendButtonWithCell:cell];
+        }
+    } else {
+        cell = [[UITableViewCell alloc] init];
+    }
+    
+    return cell;
+}
+
+#pragma mark - UITableViewDelegate
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    return 15.0;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SMXLoginViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SMXLoginViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SMXLoginViewController.h	(working copy)
@@ -0,0 +1,28 @@
+//
+//  SMXLoginViewController.h
+//  MobileNow
+//
+//  Created by array on 1/15/14.
+//  Copyright (c) 2014 MobileNow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "SmxInfo.h"
+#import "AAAManager.h"
+
+@interface SmxLoginViewController : UIViewController <UITextFieldDelegate>
+@property (nonatomic, retain) SmxInfo* smxInfo;
+
+@property (strong, nonatomic) IBOutlet UILabel *matrixLabel;
+@property (strong, nonatomic) IBOutlet UITextField *passwdField;
+@property (weak, nonatomic) IBOutlet UIBarButtonItem *loginButton;
+
+- (IBAction)cancelLogin:(id)sender;
+- (IBAction)login:(id)sender;
+
+- (void)refreshView;
+- (NSString *)createMatrixText:(NSString *)matrixStr type:(int)type;
+- (VPNAccount *)accountWithPassword;
+- (void)refreshComponents;
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SMXLoginViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SMXLoginViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SMXLoginViewController.m	(working copy)
@@ -0,0 +1,158 @@
+//
+//  SMXLoginViewController.m
+//  MobileNow
+//
+//  Created by array on 1/15/14.
+//  Copyright (c) 2014 MobileNow. All rights reserved.
+//
+
+#import "ANLogger.h"
+#import "AAAManager.h"
+#import "ANPopupDialog.h"
+#import "UIViewController+Activity.h"
+#import "UIViewController+HideKeyboard.h"
+#import "SMXLoginViewController.h"
+
+@interface SmxLoginViewController ()
+@end
+
+@implementation SmxLoginViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+	// Do any additional setup after loading the view.
+    [self initSmxInfo];
+    [self refreshComponents];
+    [self enableHideKeyboard];
+    
+    AAAManager *manager = [AAAManager sharedInstance];
+    vpn_smx_info_t *smx_info = manager.smx_info;
+    if (smx_info == NULL || smx_info->action == SMX_ACTION_INPUT_PASS) {
+        self.title = NSLocalizedString(@"Password", @"");
+    } else if(smx_info->action == SMX_ACTION_INPUT_OLD_PASS) {
+        self.title = NSLocalizedString(@"Change Password", @"");
+        self.passwdField.placeholder = NSLocalizedString(@"Current Password", @"");
+        self.navigationItem.rightBarButtonItem.title = NSLocalizedString(@"Next", @"");
+    }
+}
+
+- (void)refreshComponents {
+    if (self.smxInfo == nil) {
+        return;
+    }
+    
+    NSString *matrixStr = [[NSString alloc] initWithString:[self.smxInfo generateMatrixStr]];
+    
+	if (matrixStr && [matrixStr length] == 16*self.smxInfo.boxcount) {
+        self.matrixLabel.text = [self createMatrixText:matrixStr type:(int)self.smxInfo.boxcount];
+	} else {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                      message:NSLocalizedString(@"An unexpected error occured.", nil)];
+        [self presentViewController:dialog animated:YES completion:nil];
+	}
+}
+
+- (void)initSmxInfo {
+    AAAManager *manager = [AAAManager sharedInstance];
+    vpn_smx_info_t *smx_info = manager.smx_info;
+    VPNAccount *account = manager.account;
+    
+    self.smxInfo = [[SmxInfo alloc] initWithVpnSmxInfo:smx_info user:account.userName];
+}
+
+- (void)updateSmxInfo {
+    AAAManager *manager = [AAAManager sharedInstance];
+    vpn_smx_info_t *smx_info = manager.smx_info;
+    
+    [self.smxInfo updateVpnSmxInfo:smx_info];
+}
+
+- (NSString *)createMatrixText:(NSString *)matrixStr type:(int)type {
+    if (type != 3 && type != 4) {
+        ANError(@"unknow Matrix type %d!", type);
+        return nil;
+    }
+    
+    NSMutableString *matrix = [[NSMutableString alloc] init];
+    NSRange range;
+    for (int j=0; j<4; j++) {
+        int start = j*4;
+        int end = start + type*16;
+        for (int i=start; i<end; i+=16) {
+            range.location = i;
+            range.length = 4;
+            
+            if (i/16 == type-1) {
+                [matrix appendFormat:@"%@\n", [matrixStr substringWithRange:range]];
+            } else {
+                [matrix appendFormat:@"%@ ", [matrixStr substringWithRange:range]];
+            }
+        }
+    }
+    return matrix;
+}
+
+- (BOOL)textFieldShouldReturn:(UITextField *)textField {
+    if ([textField returnKeyType] == UIReturnKeyDone) {
+        [textField resignFirstResponder];
+        [self login:nil];
+    }
+    
+    return YES;
+}
+
+- (IBAction)cancelLogin:(id)sender {
+    [[AAAManager sharedInstance] cancelLoginTapped];
+    [self showLoginActivity:NO];
+    [self.navigationController popToRootViewControllerAnimated:YES];
+}
+
+- (VPNAccount *)accountWithPassword
+{
+    NSString *passwd = self.passwdField.text;
+    if (passwd != nil && [passwd length] == 0) {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+                                                                      message:NSLocalizedString(@"Please input password!", @"")];
+        [self presentViewController:dialog animated:YES completion:nil];
+        
+        return nil;
+    }
+    
+    NSString *hashedPwdStr = [self.smxInfo generateHash:passwd];
+    
+    AAAManager *manager = [AAAManager sharedInstance];
+    VPNAccount *account;
+    if (manager.account == nil) {
+        account = [[VPNAccount alloc] init];
+    } else {
+        account = [manager.account copy];
+    }
+    
+    account.passWord = hashedPwdStr;
+    return account;
+}
+
+- (IBAction)login:(id)sender {
+    if ([self.passwdField isFirstResponder]) {
+        [self.passwdField resignFirstResponder];
+    }
+    
+    VPNAccount *account = [self accountWithPassword];
+    if (!account) return;
+    
+    [[AAAManager sharedInstance] continueVPNThreadWithAccount:account];
+    [self showLoginActivity:YES];
+    
+    return;
+}
+
+- (void)refreshView {
+    [self updateSmxInfo];
+    
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [self showLoginActivity:NO];
+        [self refreshComponents];
+    });
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SmxClientAPI.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SmxClientAPI.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SmxClientAPI.h	(working copy)
@@ -0,0 +1,54 @@
+//
+//  SmxClientAPI.h
+//  SmxClientAPI
+//
+//  Copyright(C) 2010 CSE Co.,Ltd.
+//  Version 1.0.0
+//
+
+
+#import <Foundation/Foundation.h>
+
+#define ARP_SMX_MAXNO           @"maxNo"
+#define ARP_SMX_CONF            @"conf"
+#define ARP_SMX_CHECK           @"check"
+#define ARP_SMX_RECPNO          @"RecpNo"
+#define ARP_SMX_NEXT            @"Next"
+#define ARP_SMX_POSPWD          @"PosPwd"
+#define ARP_SMX_AUTHCODE        @"authCode"
+#define ARP_SMX_RESULT          @"Result"
+#define ARP_SMX_ERRORMSG        @"ErrorMsg"
+#define SMX_COPYRIGHT_STRING    @"Copyright(C) 2013 CSE Co.,Ltd. All rights reserved."
+
+extern NSString *const SmxClientAPIErrorDomain;
+extern char const SmxClientAPIMatrixPatternSeparator;
+
+typedef enum _SmxClientAPIError {
+	SmxClientAPIErrorGenMatrixLoginId = 0x80000001,
+	SmxClientAPIErrorGenMatrixMxNo = 0x80000002,
+	SmxClientAPIErrorGenMatrixConf = 0x80000003,
+	SmxClientAPIErrorGenMatrixCheck = 0x80000004,
+	SmxClientAPIErrorGenMatrixFailed = 0x80000006,
+	
+	SmxClientAPIErrorGenChangeMatrixLoginId = 0x80000001,
+	SmxClientAPIErrorGenChangeMatrixMxNo = 0x80000002,
+	SmxClientAPIErrorGenChangeMatrixConf = 0x80000003,
+	SmxClientAPIErrorGenChangeMatrixCheck = 0x80000004,
+	SmxClientAPIErrorGenChangeMatrixFailed = 0x80000006,
+	SmxClientAPIErrorGenChangeMatrixCreate = 0x80000007,
+	
+	SmxClientAPIErrorGetHashPassword = 0x80000001,
+	SmxClientAPIErrorGetHashFailed = 0x80000003,
+	SmxClientAPIErrorGetHashChallengeCode = 0x80000004
+} SmxClientAPIError;
+
+@interface SmxClientAPI : NSObject {
+	@private
+	NSString *SmxClientChallengeCode_;
+}
+
+- (NSString *)genMatrix:(NSString *)loginId mxNo:(NSString *)mxNo conf:(NSInteger)conf check:(NSString *)check error:(NSError **)error;
+- (NSString *)genChangeMatrix:(NSString *)loginId mxNo:(NSString *)mxNo conf:(NSInteger)conf check:(NSString *)check error:(NSError **)error;
+- (NSString *)getHash:(NSString *)password error:(NSError **)error;
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SmxConfirmPasswordViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SmxConfirmPasswordViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SmxConfirmPasswordViewController.h	(working copy)
@@ -0,0 +1,16 @@
+//
+//  SmxConfirmPasswordViewController.h
+//  MobileNow
+//
+//  Created by array on 2/19/14.
+//  Copyright (c) 2014 MobileNow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "SMXLoginViewController.h"
+
+@interface SmxConfirmPasswordViewController : SmxLoginViewController
+
+@property (strong, nonatomic) IBOutlet UILabel *passwdConfirm;
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SmxConfirmPasswordViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SmxConfirmPasswordViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SmxConfirmPasswordViewController.m	(working copy)
@@ -0,0 +1,91 @@
+//
+//  SmxConfirmPasswordViewController.m
+//  MobileNow
+//
+//  Created by array on 2/19/14.
+//  Copyright (c) 2014 MobileNow. All rights reserved.
+//
+
+#import "AAAManager.h"
+#import "SmxConfirmPasswordViewController.h"
+
+@interface SmxConfirmPasswordViewController ()
+
+@end
+
+@implementation SmxConfirmPasswordViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+	// Do any additional setup after loading the view.
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+#define SMX_POS_PWD_KEY_F 'F'
+#define SMX_POS_PWD_KEY_P 'P'
+
+- (void)refreshComponents {
+    NSString *srt = [self.smxInfo pospass] ?: @"";
+    NSString *pospass = [[NSString alloc] initWithString:srt];
+    NSInteger type = self.smxInfo.boxcount;
+    
+    if (pospass.length < 2) {
+        self.passwdConfirm.text = @"";
+        self.matrixLabel.text = @"";
+        return;
+    }
+    
+    NSMutableString *matrixStr = [[NSMutableString alloc] initWithCapacity:16*type];
+    NSMutableString *confirmStr = [[NSMutableString alloc] initWithCapacity:5];
+
+    for (int i=0; i<16*type; i++) {
+        [matrixStr appendString:@"0"];
+    }
+    
+    NSInteger i = 0;
+    NSInteger matrixIndex = 1;
+    unichar c;
+    
+    while (i < pospass.length) {
+        c = [pospass characterAtIndex:i];
+        if (c == SMX_POS_PWD_KEY_F) {
+            [confirmStr appendString:[NSString stringWithFormat:@"%c", [pospass characterAtIndex:i+1]]];
+            i += 2;
+        } else if (c == SMX_POS_PWD_KEY_P) {
+            NSString *strIndex = [pospass substringWithRange:NSMakeRange(i+1, 2)];
+            NSInteger index = [strIndex integerValue];
+            NSString *value = [NSString stringWithFormat:@"%zi", matrixIndex];
+            [matrixStr replaceCharactersInRange:NSMakeRange(index, 1) withString:value];
+            matrixIndex++;
+            
+            [confirmStr appendString:@"*"];
+            i += 3;
+        }
+    };
+    
+    self.matrixLabel.text = [self createMatrixText:matrixStr type:(int)type];
+    self.passwdConfirm.text = confirmStr;
+}
+
+- (VPNAccount*)accountWithPassword {
+    AAAManager *manager = [AAAManager sharedInstance];
+    VPNAccount *account = manager.account;
+    if (account == nil) {
+        account = [[VPNAccount alloc] init];
+    }
+    
+    [manager continueVPNThreadWithAccount:account];
+    return account;
+}
+
+- (IBAction)login:(id)sender {
+    [super login:sender];
+    
+    [self.navigationController popToRootViewControllerAnimated:YES];
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SmxInfo.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SmxInfo.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SmxInfo.h	(working copy)
@@ -0,0 +1,26 @@
+//
+//  SmxInfo.h
+//  MobileNow
+//
+//  Created by Bryan Yuan on 11/3/13.
+//  Copyright (c) 2013 MobileNow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "arrayapi.h"
+#import "SmxClientAPI.h"
+
+@interface SmxInfo : NSObject
+
+@property (nonatomic, retain) SmxClientAPI *smx_;
+@property (nonatomic, assign) NSInteger boxcount;
+@property (nonatomic, retain) NSString *matrixres;
+@property (nonatomic, retain) NSString *pospass;
+
+- (NSString *)generateMatrixStr;
+- (NSString *)generateChangeMatrixStr;
+- (NSString *) generateHash:(NSString *)pwd;
+- (instancetype)initWithVpnSmxInfo:(vpn_smx_info_t *)smx_info user:(NSString *)username;
+- (void)updateVpnSmxInfo:(vpn_smx_info_t *)smx_info;
+- (void)updateUsername:(NSString *)username;
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SmxInfo.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SmxInfo.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SmxInfo.m	(working copy)
@@ -0,0 +1,108 @@
+//
+//  SmxInfo.m
+//  MobileNow
+//
+//  Created by Bryan Yuan on 11/3/13.
+//  Copyright (c) 2013 MobileNow. All rights reserved.
+//
+
+#import "SmxInfo.h"
+
+@interface SmxInfo () {
+}
+
+@property (nonatomic, retain) NSString *loginId_;
+
+@property (assign) vpn_smx_action_t action;
+@property (nonatomic, retain) NSString *charcheck;
+@property (nonatomic, retain) NSString *recpno;
+@property (nonatomic, retain) NSString *title;
+@property (nonatomic, retain) NSString *errmsg;
+
+@end
+
+@implementation SmxInfo
+
+@synthesize smx_;
+@synthesize loginId_;
+
+@synthesize boxcount;
+@synthesize charcheck;
+@synthesize recpno;
+@synthesize matrixres;
+@synthesize pospass;
+@synthesize title;
+@synthesize errmsg;
+
+- (instancetype)init {
+    self = [super init];
+    if(self)
+    {
+      	self.smx_ = [[SmxClientAPI alloc] init];
+    }
+    
+    return self;
+}
+- (instancetype)initWithVpnSmxInfo:(vpn_smx_info_t *)smx_info user:(NSString *)username {
+    self = [super init];
+    if (self) {
+      	self.smx_ = [[SmxClientAPI alloc] init];
+        
+        self->matrixres = [NSString stringWithUTF8String:smx_info->matrixres];
+        self->charcheck = [NSString stringWithUTF8String:smx_info->charcheck];
+        self->recpno = [NSString stringWithUTF8String:smx_info->recpno];
+        self->boxcount = [[NSString stringWithUTF8String:smx_info->boxcount] integerValue];
+        self->pospass = [NSString stringWithUTF8String:smx_info->pospass];
+        self->loginId_ = username;
+        self->errmsg = [NSString stringWithUTF8String:smx_info->errmsg];
+    }
+    
+    return self;
+}
+
+- (void)updateVpnSmxInfo:(vpn_smx_info_t *)smx_info {
+    self->matrixres = [NSString stringWithUTF8String:smx_info->matrixres];
+    self->charcheck = [NSString stringWithUTF8String:smx_info->charcheck];
+    self->recpno = [NSString stringWithUTF8String:smx_info->recpno];
+    self->boxcount = [[NSString stringWithUTF8String:smx_info->boxcount] integerValue];
+    self->errmsg = [NSString stringWithUTF8String:smx_info->errmsg];
+}
+
+- (void)updateUsername:(NSString *)username {
+    self->loginId_ = username;
+}
+
+- (NSString *)generateMatrixStr {
+    NSError *error = nil;
+    NSString *matrixStr = [self.smx_ genMatrix:self.loginId_ mxNo:self->matrixres conf:self->boxcount check:self->charcheck error:&error];
+    if(error) {
+        return nil;
+    }
+    NSLog(@"matrixStr: %@", matrixStr);
+    
+    return [[NSString alloc] initWithString:matrixStr];
+}
+
+- (NSString *)generateChangeMatrixStr {
+    NSError *error = nil;
+    
+    NSString *matrixStr = [smx_ genChangeMatrix:self.loginId_ mxNo:self->matrixres conf:self->boxcount check:self->charcheck error:&error];
+    if(error) {
+        return nil;
+    }
+    
+    return matrixStr;
+}
+
+- (NSString *)generateHash:(NSString *)pwd {
+    NSError *error = nil;
+    NSString *hashedMatrixStr = [self.smx_ getHash:pwd error:&error];
+    
+    if(error) {
+        return nil;
+    }
+    
+    return hashedMatrixStr;
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SmxNewPasswordViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SmxNewPasswordViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SmxNewPasswordViewController.h	(working copy)
@@ -0,0 +1,16 @@
+//
+//  SmxNewPasswordViewController.h
+//  MobileNow
+//
+//  Created by array on 2/19/14.
+//  Copyright (c) 2014 MobileNow. All rights reserved.
+//
+
+#import "SMXLoginViewController.h"
+
+@interface SmxNewPasswordViewController : SmxLoginViewController
+
+@property (strong, nonatomic) IBOutlet UILabel *matrixLabel2;
+@property (strong, nonatomic) IBOutlet UITextField *passwdField2;
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SmxNewPasswordViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SmxNewPasswordViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SMX/SmxNewPasswordViewController.m	(working copy)
@@ -0,0 +1,125 @@
+//
+//  SmxNewPasswordViewController.m
+//  MobileNow
+//
+//  Created by array on 2/19/14.
+//  Copyright (c) 2014 MobileNow. All rights reserved.
+//
+
+#import "AAAManager.h"
+#import "ANPopupDialog.h"
+#import "UIViewController+HideKeyboard.h"
+#import "SmxNewPasswordViewController.h"
+
+@interface SmxNewPasswordViewController ()
+
+@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
+
+@end
+
+@implementation SmxNewPasswordViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    
+    [self enableHideKeyboard];
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+}
+
+- (void)viewDidLayoutSubviews {
+    [super viewDidLayoutSubviews];
+    
+    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
+        //We need to add an scroll view for iPhone.
+        [self.scrollView setContentSize:CGSizeMake(320, 500)];
+    }
+}
+
+- (BOOL)textFieldShouldReturn:(UITextField *)textField {
+    if ([textField returnKeyType] == UIReturnKeyDone) {
+        [self login:nil];
+    } else if ([textField returnKeyType] == UIReturnKeyNext) {
+        [self.passwdField2 becomeFirstResponder];
+		return NO;
+    }
+    
+    return YES;
+}
+
+- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
+    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
+        if (textField == _passwdField2) {
+            [self.scrollView setContentOffset:CGPointMake(0, 106) animated:YES];
+        } else {
+            [self.scrollView setContentOffset:CGPointMake(0, 0) animated:YES];
+        }
+    }
+    return YES;
+}
+
+
+- (void)refreshComponents {
+    if (self.smxInfo == nil) {
+        return;
+    }
+    
+    self.passwdField.text = @"";
+    self.passwdField2.text = @"";
+    
+    NSString *matrixStr = [[NSString alloc] initWithString:[self.smxInfo generateChangeMatrixStr]];
+    NSRange range;
+    NSInteger type = self.smxInfo.boxcount;
+    
+	if (matrixStr && [matrixStr length] == 2*16*type+1) {
+        range.location = 0;
+        range.length = 16*self.smxInfo.boxcount;
+        self.matrixLabel.text = [self createMatrixText:[matrixStr substringWithRange:range] type:(int)type];
+        range.location += range.length+1;
+        self.matrixLabel2.text = [self createMatrixText:[matrixStr substringWithRange:range] type:(int)type];
+	} else {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                      message:NSLocalizedString(@"An unexpected error occured.", nil)];
+        [self presentViewController:dialog animated:YES completion:nil];
+	}
+    
+    [self.passwdField becomeFirstResponder];
+}
+
+- (VPNAccount *)accountWithPassword {
+    AAAManager *manager = [AAAManager sharedInstance];
+    VPNAccount *account;
+    if (manager.account == nil) {
+        account = [[VPNAccount alloc] init];
+    } else {
+        account = [manager.account copy];
+    }
+    
+    NSString *passwd1 = [self.passwdField.text stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@" "]];
+    NSString *passwd2 = [self.passwdField2.text stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@" "]];
+    
+    if ((passwd1 != nil && [passwd1 length] == 0) || (passwd2 != nil && [passwd2 length] == 0)) {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+                                                                      message:NSLocalizedString(@"Please input password!", nil)];
+        [self presentViewController:dialog animated:YES completion:nil];
+        
+        return nil;
+    }
+    
+    if ([passwd1 length] != [passwd2 length]) {
+        PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+                                                                      message:NSLocalizedString(@"Please check your password!", nil)];
+        [self presentViewController:dialog animated:YES completion:nil];
+        
+        return nil;
+    }
+    
+    account.passWord = passwd1;
+    account.passWord2 = passwd2;
+    
+    return account;
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SettingsViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SettingsViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SettingsViewController.h	(working copy)
@@ -0,0 +1,13 @@
+//
+//  SettingsViewController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/27.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface SettingsViewController : UITableViewController
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SettingsViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SettingsViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SettingsViewController.m	(working copy)
@@ -0,0 +1,567 @@
+//
+//  SettingsViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/27.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "ANLogger.h"
+#import "AAAManager.h"
+#import "ANPopupDialog.h"
+#import "InformationToSave.h"
+#import "ArrayVPNWrapper.h"
+#import "ActionSheetPicker.h"
+#import "ConfigurationManager.h"
+#import "RulesManager.h"
+#import "UIView+Toast.h"
+#import "SettingsViewController.h"
+#import "GatewayModel.h"
+#import "BioAuth.h"
+#import "SetupGestureViewController.h"
+#import "Global.h"
+#import "Singleton.h"
+
+static NSString * const kSegueToChangePassword = @"SettingsToChangePassword";
+static NSString * const kSegueToSMXLogin = @"SettingsToSMXLogin";
+static NSString * const kSegueToSMXNewPassword = @"SettingsToSMXNewPassword";
+static NSString * const kSegueToSMXConfirmPassword = @"SettingsToSMXConfirmPassword";
+static NSString * const kSegueToRemoteDesktop = @"SettingsToRemoteDesktop";
+
+#define VIEW_CONTROLLER_ID_SMX_LOGIN            @"SMXLoginViewControllerID"
+#define VIEW_CONTROLLER_ID_SMX_NEWPASS          @"SMXNewPasswordViewControllerID"
+#define VIEW_CONTROLLER_ID_CHANGE_PASSWORD      @"ChangePasswordViewControllerID"
+
+typedef NS_ENUM(NSInteger, SettingsTableSectionIndex) {
+    kSettingsTableSectionIndexInfo = 0,
+    kSettingsTableSectionIndexRemoteDesktop,
+    kSettingsTableSectionIndexDeviceID,
+    kSettingsTableSectionIndexFaceID,
+    kSettingsTableSectionIndexGestureID,
+    kSettingsTableSectionIndexLogout
+};
+
+static NSInteger const kChangePasswordRowIndex = 1;
+
+@interface SettingsViewController () <UITableViewDelegate>
+
+@property (weak, nonatomic) IBOutlet UILabel *usernameLabel;
+@property (weak, nonatomic) IBOutlet UILabel *deviceIDLabel;
+@property (weak, nonatomic) IBOutlet UITableViewCell *deviceIDCell;
+@property (weak, nonatomic) IBOutlet UITableViewCell *passwordCell;
+
+@property (weak, nonatomic) IBOutlet UILabel *faceIDLable;
+@property (weak, nonatomic) IBOutlet UISwitch *faceIDSwitch;
+@property (weak, nonatomic) IBOutlet UISwitch *gestureSwitch;
+
+@end
+
+@implementation SettingsViewController
+
+- (void)dealloc {
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleVPNNotification:) name:kVPNMessageNotification object:nil];
+    
+    [self setVerifySwitch];
+    [self setUsernameLabel];
+    [self setDeviceID];
+    [self enableOrDisableChangePassword];
+    
+    [self.faceIDSwitch addTarget:self action:@selector(mAuthSwitch:) forControlEvents:UIControlEventTouchUpInside];
+    [self.gestureSwitch addTarget:self action:@selector(mAuthSwitch:) forControlEvents:UIControlEventTouchUpInside];
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+
+-(void) setVerifySwitch
+{
+    NSString *strAuthType = [self judgeAuthType] == LCBiometricsTypeTouchID ? @"TouchID" : @"FaceID";
+    self.faceIDLable.text = NSLocalizedString(strAuthType, nil);
+    
+    Gateway *gw = [[[GatewayModel alloc] init] currentGatewayUpInside];
+    self.gestureSwitch.on = gw.isGestureEnabled;
+    self.faceIDSwitch.on = gw.isFaceOrTouchIDEnabled;
+    
+    if (![SecuritySetting hasGesture]){
+        
+        self.gestureSwitch.on = NO;
+        gw.isGestureEnabled = NO;
+    }
+    
+    BOOL isLocked = [Singleton sharedSingleton].isFaceIDOrTouchIDLocked;
+    if (isLocked){
+        
+        self.faceIDSwitch.on = NO;
+        gw.isFaceOrTouchIDEnabled = NO;
+    }
+    
+    if (![Singleton sharedSingleton].isSupportAuth){
+        
+        gw.isFaceOrTouchIDEnabled = NO;
+        gw.isGestureEnabled = NO;
+    }
+    [[GatewayManager sharedInstance] updateGateway:gw];
+}
+
+- (void)setUsernameLabel {
+    VPNAccount *account = [AAAManager sharedInstance].account;
+    if (account) {
+        self.usernameLabel.text = account.userName;
+    }
+}
+
+- (void)setDeviceID {
+    NSString *deviceID = [AAAManager sharedInstance].deviceID;
+    if (deviceID) {
+        self.deviceIDLabel.text = deviceID;
+    }
+}
+
+- (void)logout {
+    __weak typeof(self) weakSelf = self;
+    PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"WARNING", nil)
+                                                                   message:NSLocalizedString(@"Would you like to sign out?", nil)
+                                                             confirmAction:^{
+                                                                 [weakSelf stopVPNAndLogout];
+                                                             }
+                                                              cancelAction:nil];
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)stopVPN {
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    [vpnWrapper stopSSLVPN];
+}
+
+- (void)stopVPNAndLogout {
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{  // Stop timer rules fisrt.
+        [[RulesManager sharedInstance] stopAllRules];
+    });
+    
+    AAAManager *manager = [AAAManager sharedInstance];
+    [manager continueVPNThreadWithAccount:nil];
+    [self stopVPN];
+    
+    __weak typeof(self) weakSelf = self;
+    [self.view makeToastActivity:CSToastPositionCenter];
+    dispatch_async(dispatch_get_global_queue(0, 0), ^{
+        NSInteger ret = [[AAAManager sharedInstance] stopL3VPNDirectly];
+        if (ret != ERR_SUCCESS) {
+            ANError(@"Logout failed with error code: %zi.", ret);
+        }
+        
+        __strong typeof(weakSelf) strongSelf = weakSelf;
+        dispatch_async(dispatch_get_main_queue(), ^{
+            [strongSelf.view hideToastActivity];
+            [strongSelf dismissViewControllerAnimated:YES completion:nil];
+        });
+    });
+}
+
+// Copy menu for deviceID
+- (void)showCopyMenu {
+    [self.deviceIDLabel becomeFirstResponder];
+    
+    UIMenuController *controller = [UIMenuController sharedMenuController];
+    UIMenuItem *copyItem = [[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Copy", nil) action:@selector(customCopy:)];
+    [controller setMenuItems:[NSArray arrayWithObjects:copyItem, nil]];
+    [controller setTargetRect:self.deviceIDCell.contentView.frame inView:self.deviceIDCell.contentView];
+    [controller setMenuVisible:YES animated:YES];
+}
+
+- (void)customCopy:(id)sender {
+    UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
+    pasteboard.string = self.deviceIDLabel.text;
+    ANDebug(@"Pasted string: %@", pasteboard.string);
+}
+
+// Remote Desktop Setting
+- (void)showRemoteDesktopSettings {
+    [self performSegueWithIdentifier:kSegueToRemoteDesktop sender:nil];
+}
+
+// Change password related
+- (void)enableOrDisableChangePassword {
+        BOOL isChangePasswordEnabled = [self isChangePasswordEnabled];
+        self.passwordCell.userInteractionEnabled = isChangePasswordEnabled;
+        self.passwordCell.contentView.alpha = isChangePasswordEnabled ? 1.0 : 0.5;
+}
+
+- (BOOL)isChangePasswordEnabled {
+    return ([self isLocalDBChangePasswordEnabled] ||
+            [self isLDAPChangePasswordEnabled] ||
+            [[AAAManager sharedInstance] isCurrentMethodSMXAuth]);
+}
+
+- (BOOL)isLocalDBChangePasswordEnabled {
+    return ([ConfigurationManager sharedInstance].changePassword.isLocalDBEnabled &&
+            [[AAAManager sharedInstance] isAuthTypeInLoginMethod:AUTH_LOCALDB]);
+}
+
+- (BOOL)isLDAPChangePasswordEnabled {
+    return ([ConfigurationManager sharedInstance].changePassword.isLDAPEnabled &&
+            [[AAAManager sharedInstance] isAuthTypeInLoginMethod:AUTH_LDAP]);
+}
+
+#define CHANGE_PASSWORD_MULTI_METHODS           -2
+#define CHANGE_PASSWORD_NOT_SUPPORT             -1
+#define CHANGE_PASSWORD_SUCCESS                 0
+#define CHANGE_PASSWORD_SMX_SESSION_EXPIRED     3
+
+- (NSInteger)initiateChangePassword {
+    auth_type_t authType = AUTH_LOCALDB;
+    char *server = NULL;
+    AAAManager *manager = [AAAManager sharedInstance];
+    aaa_auth_info_t *autoInfo = manager.autoInfoBack;
+    
+    if (autoInfo != NULL && autoInfo->method_num == 1) {
+        auth_method_t auth_method = autoInfo->methods[0];
+        
+        InformationToSave *infor =  [InformationToSave sharedInstance];
+        NSString *loginMethod = infor.lastLoginAccount.loginMethod;
+        NSString *authMethodName = [[NSString alloc] initWithCString:auth_method.name encoding:NSUTF8StringEncoding];
+        if ([authMethodName isEqualToString:loginMethod] || [loginMethod isEqualToString:@"DD_Register"]) {
+            authType = auth_method.type;
+            server = auth_method.server;
+            if (auth_method.multi_step_num > 0) {
+                ANInfo(@"Multi-step authentication site, user has to switch server to change password.");
+                return CHANGE_PASSWORD_MULTI_METHODS;
+            }
+        } else if (auth_method.multi_step_num > 0) {
+            auth_multi_method_t multi_method = auth_method.multi_steps[auth_method.multi_step_num-1];
+            authType = multi_method.type;
+            server = multi_method.server;
+        } else {
+            authType = auth_method.type;
+            server = auth_method.server;
+        }
+    } else if (autoInfo != NULL && autoInfo->method_num > 1) {
+        InformationToSave *infor =  [InformationToSave sharedInstance];
+        NSString *loginMethod = infor.lastLoginAccount.loginMethod;
+        for (int i =0; i < autoInfo->method_num; i++) {
+            auth_method_t auth_method = autoInfo->methods[i];
+            NSString *authMethodName = [[NSString alloc] initWithCString:auth_method.name encoding:NSUTF8StringEncoding];
+            if ([authMethodName isEqualToString:loginMethod]) {
+                if (auth_method.multi_step_num > 0) {
+                    ANInfo(@"Multi-step authentication site, user has to switch server to change password.");
+                    return CHANGE_PASSWORD_MULTI_METHODS;
+                }
+                authType = auth_method.type;
+                server = auth_method.server;
+                break;
+            }
+        }
+    } else {
+        return CHANGE_PASSWORD_NOT_SUPPORT;
+    }
+    
+    if (authType != AUTH_LOCALDB &&
+        authType != AUTH_LDAP &&
+        authType != AUTH_SMX) {
+        return CHANGE_PASSWORD_NOT_SUPPORT;
+    }
+    
+    return array_vpn_change_password(authType, server);
+}
+
+- (void)showAAAMethodsPickerWithMethodNames:(NSArray *)methodNames {
+    if (methodNames == nil || [methodNames count] == 0) {
+        ANError(@"Multi-step method names array is empty, can not show picker.");
+        return;
+    }
+    
+    [ActionSheetStringPicker showPickerWithTitle:NSLocalizedString(@"Authentication List", nil)
+                                            rows:methodNames
+                                initialSelection:0
+                                       doneBlock:^(ActionSheetStringPicker *picker, NSInteger selectedIndex, id selectedValue) {
+                                           NSString *selectedServerName = (NSString *)selectedValue;
+                                           ANInfo(@"Server name of %@ is selected, change password will be continue.", selectedServerName);
+                                           dispatch_async(dispatch_get_global_queue(0, 0), ^{
+                                               NSInteger ret = [[AAAManager sharedInstance] changePasswordWithAAAServerName:selectedServerName];
+                                               if (ret == 0) {
+                                                   dispatch_async(dispatch_get_main_queue(), ^{
+                                                       [self promptMessage:NSLocalizedString(@"Password has been updated", nil)];
+                                                   });
+                                               }
+                                           });
+                                       }
+                                     cancelBlock:nil
+                                          origin:self.passwordCell.contentView];  // Use "contentView" to compitable with iPad.
+}
+
+- (void)promptMessage:(NSString *)message {
+    PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:@"" message:message];
+    
+    [self presentViewController:dialog animated:YES completion:nil];
+}
+
+- (void)handleVPNNotification:(NSNotification *)notification {
+    VPNMessage *msg = notification.object;
+    BOOL showAlert = YES;
+    switch (msg.code) {
+        case VPN_CB_CHANGPASSWORD: {
+            if ([self.navigationController.topViewController.restorationIdentifier isEqualToString:VIEW_CONTROLLER_ID_CHANGE_PASSWORD]) {
+                [self refreshTopView];
+            } else {
+                [self performSegueWithIdentifier:kSegueToChangePassword sender:self];
+            }
+            break;
+        }
+        case VPN_CB_SMX:{
+            NSString *errorMsg = nil;
+            AAAManager *manager = [AAAManager sharedInstance];
+            vpn_smx_info_t *smx_info = manager.smx_info;
+            if (smx_info != NULL) {
+                ANInfo(@"smx_info->action: %d", smx_info->action);
+                switch (smx_info->action) {
+                    case SMX_ACTION_INPUT_PASS:
+                    case SMX_ACTION_INPUT_OLD_PASS: {
+                        UIViewController *topViewController = self.navigationController.topViewController;
+                        if ([topViewController.restorationIdentifier isEqualToString:VIEW_CONTROLLER_ID_SMX_LOGIN]) {
+                            //If the top controller is login controller, do nothing but send the status to it.
+                            [self refreshTopView];
+                            showAlert = YES;
+                        } else {
+                            showAlert = NO;
+                            [self performSegueWithIdentifier:kSegueToSMXLogin sender:nil];
+                        }
+                        break;
+                    }
+                    case SMX_ACTION_INPUT_NEW_PASS: {
+                        UIViewController *topViewController = self.navigationController.topViewController;
+                        if ([topViewController.restorationIdentifier isEqualToString:VIEW_CONTROLLER_ID_SMX_NEWPASS]) {
+                            //If the top controller is new password controller, do nothing but send the status to it.
+                            [self refreshTopView];
+                            showAlert = YES;
+                        } else {
+                            showAlert = NO;
+                            [self performSegueWithIdentifier:kSegueToSMXNewPassword sender:nil];
+                        }
+                        break;
+                    }
+                    case SMX_ACTION_PASS_CONFIRM:
+                        showAlert = NO;
+                        [self performSegueWithIdentifier:kSegueToSMXConfirmPassword sender:nil];
+                        break;
+                        
+                    default:
+                        break;
+                }
+                
+                if (showAlert) {
+                    errorMsg = [NSString stringWithUTF8String:smx_info->errmsg];
+                    if (![errorMsg isEqual:@"OK"] && ![errorMsg isEqual:@"正常"]) {
+                        [self promptMessage:errorMsg];
+                    }
+                }
+            }
+            break;
+        }
+            
+        default:
+            break;
+    }
+}
+
+- (void)refreshTopView {
+    UIViewController *topViewController = self.navigationController.topViewController;
+    SEL handler = NSSelectorFromString(@"refreshView");
+    if ([topViewController respondsToSelector:handler]) {
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+        [topViewController performSelector:handler];
+    }
+}
+
+#pragma mark - UITableViewDelegate
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
+    
+    NSInteger section = indexPath.section;
+    NSInteger row = indexPath.row;
+    if (section == kSettingsTableSectionIndexInfo && row == kChangePasswordRowIndex) {
+        dispatch_async(dispatch_get_global_queue(0, 0), ^{
+            NSInteger ret = [self initiateChangePassword];
+            if (ret == CHANGE_PASSWORD_SUCCESS) {
+                dispatch_async(dispatch_get_main_queue(), ^{
+                    [self promptMessage:NSLocalizedString(@"Password has been updated", nil)];
+                });
+            } else if (ret == CHANGE_PASSWORD_NOT_SUPPORT) {
+                dispatch_async(dispatch_get_main_queue(), ^{
+                    [self promptMessage:NSLocalizedString(@"The authentication method is not supported to change password!", nil)];
+                });
+            } else if (ret == CHANGE_PASSWORD_MULTI_METHODS) {
+                // Multi-step authentication.
+                BOOL localdbChangePasswordEnabled = [self isLocalDBChangePasswordEnabled];
+                BOOL ldapChangePasswordEnabled = [self isLDAPChangePasswordEnabled];
+                NSArray *methodNames = [[AAAManager sharedInstance] multiStepMethodNamesWithLocalDB:localdbChangePasswordEnabled
+                                                                                               ladp:ldapChangePasswordEnabled];
+                dispatch_async(dispatch_get_main_queue(), ^{
+                    [self showAAAMethodsPickerWithMethodNames:methodNames];
+                });
+            } else if (ret == CHANGE_PASSWORD_SMX_SESSION_EXPIRED) {
+                dispatch_async(dispatch_get_main_queue(), ^{
+                    [self promptMessage:NSLocalizedString(@"SMX session expired!", nil)];
+                });
+            }
+        });
+    } else if (section == kSettingsTableSectionIndexDeviceID) {
+        [self showCopyMenu];
+    } else if (section == kSettingsTableSectionIndexRemoteDesktop) {
+        [self showRemoteDesktopSettings];
+    } else if (indexPath.section == kSettingsTableSectionIndexLogout) {
+        [self logout];
+    }
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    CGFloat height = 0;
+    
+    switch (section) {
+        case kSettingsTableSectionIndexInfo:
+        case kSettingsTableSectionIndexDeviceID:
+        case kSettingsTableSectionIndexRemoteDesktop:
+        case kSettingsTableSectionIndexFaceID:
+        case kSettingsTableSectionIndexGestureID:
+            height = 15;
+            break;
+        case kSettingsTableSectionIndexLogout:
+            height = 35;
+            break;
+            
+        default:
+            break;
+    }
+    
+    return height;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
+    
+    if (section == 0){
+        
+        return 2;
+    }else if ((section == 3 || section == 4) && ![Singleton sharedSingleton].isSupportAuth){
+        
+        return 0;
+    }
+    
+    return 1;
+}
+
+-(void) mAuthSwitch: (UISwitch *) sender
+{
+    Gateway *gw = [[[GatewayModel alloc] init] currentGatewayUpInside];
+
+    if (sender == self.faceIDSwitch){
+       
+        gw.isFaceOrTouchIDEnabled = sender.on;
+        if ([self judgeAuthType] == LCBiometricsTypeTouchID){
+            
+            [self modifyTouchIDAuthSetting:sender];
+        }else{
+            
+            [self modifyFaceIDAuthSetting:sender];
+        }
+       
+    }else if (sender == self.gestureSwitch){
+        
+        if (sender.on == YES){
+                    
+            [self.gestureSwitch setOn:NO animated:YES];
+
+            SetupGestureViewController *control = [[SetupGestureViewController alloc] init];
+            control.resultBlock = ^{
+                
+                [self.gestureSwitch setOn:YES animated:YES];
+                gw.isGestureEnabled = YES;
+                [[GatewayManager sharedInstance] updateGateway:gw];
+            };
+            control.modalPresentationStyle = UIModalPresentationFullScreen;
+            [self presentViewController:control animated:YES completion:nil];
+        }else{
+            
+            [SecuritySetting clearGesture];
+        }
+        gw.isGestureEnabled = self.gestureSwitch.on;
+    }
+    [[GatewayManager sharedInstance] updateGateway:gw];
+}
+
+-(LCBiometricsType) judgeAuthType
+{
+    return [SecuritySetting isSupportBiometricsAuth];
+}
+
+- (void)modifyFaceIDAuthSetting:(UISwitch *) sender{
+    
+    Gateway *gw = [[[GatewayModel alloc] init] currentGatewayUpInside];
+    if (sender.on) {
+        __weak typeof(self) weakSelf = self;
+        [BioAuth startBiometricsAuthType:LCBiometricsTypeFaceID
+                              WithAction:BioAuthOpen
+                              completion:^(BOOL isSuccess, NSString *errorMsg){
+            if(isSuccess){
+            } else{
+                
+                if (ISNULLSTR(errorMsg) || [errorMsg isEqualToString:@""]){
+                    errorMsg = NSLocalizedString(@"Open failed", nil);
+                }
+
+                gw.isFaceOrTouchIDEnabled = NO;
+                [self.faceIDSwitch setOn:NO animated:YES]; //开启失败，switch状态设置为NO
+                [[GatewayManager sharedInstance] updateGateway:gw];
+
+                NSString *message = NSLocalizedString(errorMsg, nil);
+                PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                              message:message];
+                [weakSelf presentViewController:dialog animated:YES completion:nil];
+            }
+        }];
+    }else{
+    }
+}
+
+- (void)modifyTouchIDAuthSetting:(UISwitch *) sender{
+    
+    Gateway *gw = [[[GatewayModel alloc] init] currentGatewayUpInside];
+    if (sender.on) {
+        __weak typeof(self) weakSelf = self;
+        [BioAuth startBiometricsAuthType:LCBiometricsTypeTouchID
+                              WithAction:BioAuthOpen
+                              completion:^(BOOL isSuccess, NSString *errorMsg){
+            if(isSuccess){
+            }
+            else{
+                
+                if (ISNULLSTR(errorMsg) || [errorMsg isEqualToString:@""]){
+                    errorMsg = NSLocalizedString(@"Open failed", nil);
+                }
+                
+                gw.isFaceOrTouchIDEnabled = NO;
+                [self.faceIDSwitch setOn:NO animated:YES]; //开启失败，switch状态设置为NO
+                [[GatewayManager sharedInstance] updateGateway:gw];
+                
+                NSString *message = NSLocalizedString(errorMsg, nil);
+                PopupDialog *dialog = [ANPopupDialog singleButtonPopupDialogWithTitle:NSLocalizedString(@"Error", nil)
+                                                                              message:message];
+                [weakSelf presentViewController:dialog animated:YES completion:nil];
+            }
+        }];
+    } else{
+    }
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/StatusViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/StatusViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/StatusViewController.h	(working copy)
@@ -0,0 +1,13 @@
+//
+//  StatusViewController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/27.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface StatusViewController : UITableViewController
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/StatusViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/StatusViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/StatusViewController.m	(working copy)
@@ -0,0 +1,504 @@
+//
+//  StatusViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/27.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+#include <arpa/inet.h>
+#import "ANLogger.h"
+#import "arrayapi.h"
+#import "vpnplugin.h"
+#import "ArrayVPNManager.h"
+#import "ArrayVPNWrapper.h"
+#import "ANPopupDialog.h"
+#import "AAAManager.h"
+#import "GatewayManager.h"
+#import "StatusViewController.h"
+#import "DNSSettingCell.h"
+#import "UIViewController+HideKeyboard.h"
+
+BOOL isValidDNSServer(const char *dnsServer);
+
+BOOL isValidDNSServer(const char *dnsServer)
+{
+    if (!dnsServer) {
+        return NO;
+    }
+    
+    struct sockaddr_in sa;
+    int result = inet_pton(AF_INET, dnsServer, &(sa.sin_addr));
+    return result != 0;
+}
+
+#define SECTIONS_IN_STATUS_VIEW             2
+#define ROWS_IN_SECTION_CONNECTION_INFO     6
+#define ROWS_IN_SECIONT_STATISTICS          2
+
+typedef NS_ENUM(NSInteger, StatusSectionIndex) {
+    kStatusSectionConnectionInfo = 0,
+    kStatusSectionDNS,
+    kStatusSectionStatistics,
+    kStatusSectionTotal
+};
+
+#define TIMER_PERIOD                1
+#define REFRESH_VPN_STATUS_PERIOD   3
+
+NSString * const kAppGroupNameStatus = @"group.net.arraynetworks.MotionProPlus";
+
+
+@interface StatusViewController () <DNSSettingCellDelegate> {
+    NSTimer *_timer;
+    NSInteger _tick;
+}
+
+@property (weak, nonatomic) IBOutlet UILabel *stateLabel;
+@property (weak, nonatomic) IBOutlet UILabel *serverLabel;
+@property (weak, nonatomic) IBOutlet UILabel *ipAddressLabel;
+@property (weak, nonatomic) IBOutlet UILabel *timeLabel;
+@property (weak, nonatomic) IBOutlet UILabel *mtuLabel;
+@property (weak, nonatomic) IBOutlet UILabel *modeLabel;
+@property (weak, nonatomic) IBOutlet UILabel *dataSentLabel;
+@property (weak, nonatomic) IBOutlet UILabel *dataReceivedLabel;
+@property (strong, nonatomic) NSMutableArray *dnsList;
+@property (nonatomic) BOOL needReconnect;
+
+@end
+
+@implementation StatusViewController
+
+- (void)dealloc {
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    [self enableHideKeyboard];
+    
+    [self.tableView registerNib:[UINib nibWithNibName:@"DNSSettingCell" bundle:nil] forCellReuseIdentifier:kDNSSettingCellID];
+    self.needReconnect = NO;
+    
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameStatus];
+    NSMutableArray *newDNSList = [userDefaults valueForKey:@"dns_list"];
+    ANInfo(@"viewDidLoad:get new dns list[%@]", newDNSList);
+    if (newDNSList.count > 0) {
+        [userDefaults removeObjectForKey:@"dns_list"];
+        _dnsList = newDNSList;
+        ANInfo(@"viewDidLoad:get dns list= %@", _dnsList);
+    }
+    
+    if (![self clearVPNInfoIfNotConnected]) {
+        [self fetchVPNTunnelStatsInfo];
+    }
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(handleVPNStatus:)
+                                                 name:kArrayVPNStatusNotification
+                                               object:nil];
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [self setVPNStatus];
+    if (![self clearVPNInfoIfNotConnected]) {
+        [self setMTU];
+        [self refreshVPNStatusWithPeriod:TIMER_PERIOD];
+    }
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [self stopFetchInfo];
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+#pragma mark - All Status Information
+- (void)setVPNStatus {
+    NSString *statusString = @"";
+    ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+    
+    switch (tunnelStatus) {
+        case ArrayVPNInavlid:
+        case ArrayVPNDisconnecting:
+        case ArrayVPNDisconnected:
+            statusString = NSLocalizedString(@"Disconnected", nil);
+            break;
+        case ArrayVPNConnecting:
+        case ArrayVPNReasserting:
+            statusString = NSLocalizedString(@"Connecting...", nil);
+            break;
+        case ArrayVPNConnected:
+            statusString = NSLocalizedString(@"Connected", nil);
+            break;
+        default:
+            ANError(@"Invalid VPN tunnel status \(%zi).", tunnelStatus);
+            break;
+    }
+    
+    self.stateLabel.text = statusString;
+}
+
+// VPN Status Handler
+- (void)handleVPNStatus:(NSNotification *)notification {
+    ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+    
+    ANInfo(@"Array VPN tunnel status = %zi", tunnelStatus);
+    
+    if (tunnelStatus != ArrayVPNConnected) {
+        [self clearVPNInfo];
+        [self stopFetchInfo];
+        if (self.needReconnect && tunnelStatus == ArrayVPNDisconnected) {
+            ANInfo(@"custom dns server config, now need restart vpn.");
+            self.needReconnect = NO;
+            [self startVPN:NO];
+        }
+    } else {
+        if (_timer == nil) {
+            [self refreshVPNStatusWithPeriod:TIMER_PERIOD];
+        }
+        ANInfo(@"Array VPN tunnel status is connected");
+        if (tunnelStatus == ArrayVPNConnected) {
+            NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameStatus];
+            for (int i = 0; i < 3; i++) {
+                NSMutableArray *newDNSList = [userDefaults valueForKey:@"dns_list"];
+                ANInfo(@"get new dns list[%@], i =%d", newDNSList, i);
+                if (newDNSList.count > 0) {
+                    //[userDefaults removeObjectForKey:@"dns_list"];
+                    _dnsList = newDNSList;
+                    ANInfo(@"status connected:get dns list= %@", _dnsList);
+                    [self.tableView reloadData];
+                    break;
+                } else {
+                    sleep(1);
+                }
+            }
+        }
+    }
+}
+
+- (BOOL)startVPN:(BOOL)isAutoStart {
+    //Gateway *gateway = [self getCurrentGateway];
+    //NSString *session = [AAAManager sharedInstance].sessionID;
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    
+    //Reset connect fail reason.
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameStatus];
+    [userDefaults removeObjectForKey:@"tunnel_result"];
+    [userDefaults removeObjectForKey:@"dns_list"];
+    
+    [vpnWrapper startSSLVPN];
+    
+    return YES;
+}
+
+- (void)stopVPN {
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    [vpnWrapper stopSSLVPN];
+}
+
+// Clear all statistics information if vpn is not connected.
+- (BOOL)clearVPNInfoIfNotConnected {
+    ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+    if (tunnelStatus != ArrayVPNConnected) {
+        [self clearVPNInfo];
+        
+        return YES;
+    }
+    
+    return NO;
+}
+
+- (void)clearVPNInfo {
+    self.serverLabel.text = @"";
+    self.ipAddressLabel.text = @"";
+    self.timeLabel.text = @"";
+    self.mtuLabel.text = @"";
+    self.modeLabel.text = @"";
+    self.dataSentLabel.text = @"";
+    self.dataReceivedLabel.text = @"";
+}
+
+// From local progress.
+- (void)setConnectedTime {
+    NSDate *connectedDate = [ArrayVPNManager sharedInstance].tunnelManager.connection.connectedDate;
+    NSString *timeString = [self formatDate:connectedDate];
+    
+    self.timeLabel.text = timeString;
+}
+
+// MTU is hard-coded, default value is 1400.
+- (void)setMTU {
+    self.mtuLabel.text = [NSString stringWithFormat:@"%d", VPN_PLUGIN_DEFAULT_MTU];
+}
+
+// From VPN extension.
+- (void)refreshVPNStatusWithPeriod:(NSTimeInterval)period {
+    _timer = [NSTimer timerWithTimeInterval:period
+                                     target:self
+                                   selector:@selector(timerHandler)
+                                   userInfo:nil
+                                    repeats:YES];
+    
+    [[NSRunLoop currentRunLoop]addTimer:_timer forMode:NSDefaultRunLoopMode];
+    [_timer fire];
+}
+
+- (void)timerHandler {
+    if (++_tick == REFRESH_VPN_STATUS_PERIOD) {
+        _tick = 0;
+        
+        [self fetchVPNTunnelStatsInfo];
+    }
+    
+    [self setConnectedTime];
+    [self setMTU];
+}
+
+- (void)fetchVPNTunnelStatsInfo {
+    NSError *error = nil;
+    
+    NETunnelProviderManager *manager = [[ArrayVPNManager sharedInstance] tunnelManager];
+    NETunnelProviderSession *session = (NETunnelProviderSession *)manager.connection;
+    
+    NSDictionary *IPCRequestDict = @{(__bridge NSString *)kIPCType:(__bridge NSString *)kIPCStatsRequest};
+    NSData *IPCRequest = [NSJSONSerialization dataWithJSONObject:IPCRequestDict
+                                                         options:NSJSONWritingPrettyPrinted
+                                                           error:nil];
+    
+    __weak typeof(self) weakSelf = self;
+    [session sendProviderMessage:IPCRequest
+                     returnError:&error
+                 responseHandler:^(NSData * _Nullable responseData) {
+                     if (responseData) {
+                         ANDebug(@"IPC response received.");
+                         
+                         NSError *error = nil;
+                         NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:responseData
+                                                                              options:NSJSONReadingMutableContainers
+                                                                                error:&error];
+                         if (!dict) {
+                             ANError(@"Parse IPC response failed with error: %@.", error);
+                             return;
+                         }
+                         NSDictionary *IPCData = [dict objectForKey:(__bridge NSString *)kIPCResponseData];
+                         if (responseData != nil) {
+                             [weakSelf updateDisplayedVPNStatsWithDict:IPCData];
+                         } else {
+                             ANError(@"IPC data is not found in response.");
+                         }
+                     } else {
+                         ANError(@"IPC response is nil.");
+                     }
+                 }];
+    if (error) {
+        ANError(@"Send IPC failed with error: %@.", error.localizedDescription);
+    }
+}
+
+- (void)updateDisplayedVPNStatsWithDict:(NSDictionary *)dict {
+    NSNumber *clientIP = [dict objectForKey:(__bridge NSString *)kIPCStatsClientIP];
+    NSString *serverHost = [dict objectForKey:(__bridge NSString *)kIPCStatsServerHost];
+    NSNumber *sentBytes = [dict objectForKey:(__bridge NSString *)kIPCStatsSentBytes];
+    NSNumber *receivedBytes = [dict objectForKey:(__bridge NSString *)kIPCStatsReceviedBytes];
+    NSNumber *isFullTunnel = [dict objectForKey:(__bridge NSString *)kIPCStatsIsFullTunnel];
+    
+    NSString *sentToShow = [self formatBytes:[sentBytes stringValue]];
+    NSString *recvToShow = [self formatBytes:[receivedBytes stringValue]];
+    
+    self.ipAddressLabel.text = [self formatIP:clientIP];
+    self.serverLabel.text = serverHost;
+    self.modeLabel.text = [isFullTunnel boolValue] ? NSLocalizedString(@"Full Tunnel", nil) : NSLocalizedString(@"Split Tunnel", nil);
+    
+    if (sentToShow) {
+        self.dataSentLabel.text = sentToShow;
+    }
+    if (recvToShow) {
+        self.dataReceivedLabel.text = recvToShow;
+    }
+}
+
+- (void)stopFetchInfo {
+    [_timer invalidate];
+    _timer = nil;
+}
+
+#pragma mark - Helpers
+- (NSString *)formatIP:(NSNumber *)IP {
+    if (!IP) {
+        return @"0.0.0.0";
+    }
+    
+    uint32_t ip = [IP unsignedIntValue];
+    
+    return [NSString stringWithFormat:@"%d.%d.%d.%d", IPSTR(ip)];
+}
+
+- (NSString *)formatBytes:(NSString *)bytes {
+    
+#define K_BYTES     1024
+#define M_BYTES     (1024 * 1024)
+    
+    if (!bytes) {
+        return nil;
+    }
+    
+    uint64_t uBytes = (uint64_t)[bytes integerValue];
+    if (uBytes > M_BYTES) {
+        return [NSString stringWithFormat:@"%.1f MB", (double)uBytes/M_BYTES];
+    } else if (uBytes > K_BYTES) {
+        return [NSString stringWithFormat:@"%.1f KB", (double)uBytes/K_BYTES];
+    }
+    
+    return [NSString stringWithFormat:@"%@ B", bytes];
+}
+
+- (NSString *)formatDate:(NSDate *)date {
+    if (!date) {
+        return NSLocalizedString(@"Unconnected", nil);
+    }
+    
+    NSTimeInterval now = [[NSDate date] timeIntervalSince1970];
+    NSTimeInterval connectedDateInterval = [date timeIntervalSince1970];
+    NSUInteger seconds = (NSUInteger)round(now - connectedDateInterval);
+    NSString *dateString = [NSString stringWithFormat:@"%02zi:%02zi:%02zi",
+                            seconds / 3600, (seconds / 60) % 60, seconds % 60];
+    
+    return [NSString stringWithFormat:@"%@", dateString];
+}
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return kStatusSectionTotal;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    if (section == kStatusSectionConnectionInfo) {
+        return 6;
+    } else if (section == kStatusSectionStatistics) {
+        return 2;
+    } else if (section == kStatusSectionDNS){
+        if (_dnsList.count < 16) {
+            return _dnsList.count + 1;
+        } else {
+            return 16;
+        }
+    }
+    return 0;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell *cell = nil;
+    
+    if (indexPath.section == kStatusSectionDNS) {
+        DNSSettingCell *dnsSettingCell = [tableView dequeueReusableCellWithIdentifier:kDNSSettingCellID];
+        dnsSettingCell.delegate = self;
+        if (!dnsSettingCell) {
+            dnsSettingCell = [[DNSSettingCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kDNSSettingCellID];;
+        }
+        
+        NSInteger row = indexPath.row;
+        if (_dnsList.count < 16) {
+            if (row == 0) {
+                [dnsSettingCell configureCellWithMessage:@"" isAddCell:YES];
+            } else {
+                [dnsSettingCell configureCellWithMessage:[_dnsList objectAtIndex:row - 1] isAddCell:NO];
+            }
+        } else {
+            [dnsSettingCell configureCellWithMessage:[_dnsList objectAtIndex:row] isAddCell:NO];
+        }
+        
+        return dnsSettingCell;
+    } else {
+        cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
+    }
+    return cell;
+}
+
+
+#pragma mark - UITableViewDelegate
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    return 35;
+}
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+#pragma mark - DNSSettingCellDelegate
+- (void)DNSSettingButtonDidClickedWithCell:(UITableViewCell *)cell isAdd:(BOOL)bAdd {
+    DNSSettingCell* dnsCell = (DNSSettingCell *)(cell);
+    NSMutableArray *tmpArray = [NSMutableArray arrayWithArray:_dnsList];
+    NSString *errMessage = @"", *titleMessage = @"";
+    if (bAdd) {
+        NSArray *newDnsArray = [dnsCell.addDnsTextField.text componentsSeparatedByString:@";"];
+        BOOL bValidDNSServer = YES;
+        if ([newDnsArray count] > 0) {
+            for (NSString *signalDNS in newDnsArray) {
+                if (!isValidDNSServer([signalDNS UTF8String])) {
+                    bValidDNSServer = NO;
+                }
+            }
+        } else {
+            bValidDNSServer = NO;
+        }
+        
+        if (bValidDNSServer) {
+            [tmpArray addObjectsFromArray:newDnsArray];
+        } else {
+            errMessage = NSLocalizedString(@"The format of the DNS server is invalid.", nil);
+            titleMessage = NSLocalizedString(@"Error", nil);
+        }
+    } else {
+        [tmpArray removeObject:dnsCell.descText.text];
+        if([tmpArray count] <= 0) {
+            errMessage = NSLocalizedString(@"Make sure at least one DNS server exists in the system.", nil);
+            titleMessage = NSLocalizedString(@"Information", nil);
+        }
+    }
+    
+    if ([errMessage length] > 0) {
+        PopupDialog *popup = [ANPopupDialog singleButtonPopupDialogWithTitle:titleMessage message:errMessage];
+        [self presentViewController:popup animated:YES completion:nil];
+        return;
+    }
+    _dnsList = tmpArray;
+    ANInfo(@"new dns list=%@", _dnsList);
+    [self.tableView reloadData];
+    
+    NSString *dnsListString = [_dnsList componentsJoinedByString:@";"];
+    Gateway *currentGateway = [self getCurrentGateway];
+    currentGateway.customDnsList = dnsListString;
+    ANInfo(@"save current gateway custom dns list=%@", currentGateway.customDnsList);
+    GatewayManager *gatewayManager = [GatewayManager sharedInstance];
+    [gatewayManager updateGateway:currentGateway];
+    self.needReconnect = YES;
+    [self stopVPN];
+}
+
+- (Gateway *)getCurrentGateway {
+    AAAManager *manager = [AAAManager sharedInstance];
+    VPNAccount *account = manager.account;
+    GatewayManager *gm = [GatewayManager sharedInstance];
+    NSString *url = account.vsURL;
+    NSString *port = account.vsPort;
+    if ([url length] <= 0) {
+        NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameStatus];
+        NSString *oauthUrl = [userDefaults valueForKey:KEY_OAUTH_URL];
+        if (oauthUrl.length > 0) {
+            ANInfo(@"getCurrentGateway: Get oauth url[%@].", oauthUrl);
+            NSRange range = [oauthUrl rangeOfString:@"https://"];
+            oauthUrl = [oauthUrl substringFromIndex:range.location + range.length];
+            range = [oauthUrl rangeOfString:@"/prx/000/"];
+            url = [oauthUrl substringToIndex:range.location];
+            ANInfo(@"getCurrentGateway: Get url[%@].", url);
+        }
+    }
+    NSInteger index = [gm indexOfUrl:url andport:port];
+    
+    return [gm gatewayAtIndex:index];
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/StatusViewController.m.InfosecEnterprise
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/StatusViewController.m.InfosecEnterprise	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/StatusViewController.m.InfosecEnterprise	(working copy)
@@ -0,0 +1,509 @@
+//
+//  StatusViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/27.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+#include <arpa/inet.h>
+#import "ANLogger.h"
+#import "arrayapi.h"
+#import "vpnplugin.h"
+#import "ArrayVPNManager.h"
+#import "ArrayVPNWrapper.h"
+#import "ANPopupDialog.h"
+#import "AAAManager.h"
+#import "GatewayManager.h"
+#import "StatusViewController.h"
+#import "DNSSettingCell.h"
+#import "UIViewController+HideKeyboard.h"
+
+BOOL isValidDNSServer(const char *dnsServer);
+
+BOOL isValidDNSServer(const char *dnsServer)
+{
+    if (!dnsServer) {
+        return NO;
+    }
+    
+    struct sockaddr_in sa;
+    int result = inet_pton(AF_INET, dnsServer, &(sa.sin_addr));
+    return result != 0;
+}
+
+#define SECTIONS_IN_STATUS_VIEW             2
+#define ROWS_IN_SECTION_CONNECTION_INFO     6
+#define ROWS_IN_SECIONT_STATISTICS          2
+
+typedef NS_ENUM(NSInteger, StatusSectionIndex) {
+    kStatusSectionConnectionInfo = 0,
+    kStatusSectionDNS,
+    kStatusSectionStatistics,
+    kStatusSectionTotal
+};
+
+#define TIMER_PERIOD                1
+#define REFRESH_VPN_STATUS_PERIOD   3
+
+#if TARGET_OS_IPHONE
+NSString * const kAppGroupNameStatus = @"group.net.infosec.groupenterprise";
+#elif TARGET_OS_MAC
+NSString * const kAppGroupNameStatus = @"5VZLZ3YQ9P.net.arraynetworks.MacTunnel";
+#endif
+
+@interface StatusViewController () <DNSSettingCellDelegate> {
+    NSTimer *_timer;
+    NSInteger _tick;
+}
+
+@property (weak, nonatomic) IBOutlet UILabel *stateLabel;
+@property (weak, nonatomic) IBOutlet UILabel *serverLabel;
+@property (weak, nonatomic) IBOutlet UILabel *ipAddressLabel;
+@property (weak, nonatomic) IBOutlet UILabel *timeLabel;
+@property (weak, nonatomic) IBOutlet UILabel *mtuLabel;
+@property (weak, nonatomic) IBOutlet UILabel *modeLabel;
+@property (weak, nonatomic) IBOutlet UILabel *dataSentLabel;
+@property (weak, nonatomic) IBOutlet UILabel *dataReceivedLabel;
+@property (strong, nonatomic) NSMutableArray *dnsList;
+@property (nonatomic) BOOL needReconnect;
+
+@end
+
+@implementation StatusViewController
+
+- (void)dealloc {
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    [self enableHideKeyboard];
+    
+    [self.tableView registerNib:[UINib nibWithNibName:@"DNSSettingCell" bundle:nil] forCellReuseIdentifier:kDNSSettingCellID];
+    self.needReconnect = NO;
+    
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameStatus];
+    NSMutableArray *newDNSList = [userDefaults valueForKey:@"dns_list"];
+    ANInfo(@"viewDidLoad:get new dns list[%@]", newDNSList);
+    if (newDNSList.count > 0) {
+        [userDefaults removeObjectForKey:@"dns_list"];
+        _dnsList = newDNSList;
+        ANInfo(@"viewDidLoad:get dns list= %@", _dnsList);
+    }
+    
+    if (![self clearVPNInfoIfNotConnected]) {
+        [self fetchVPNTunnelStatsInfo];
+    }
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(handleVPNStatus:)
+                                                 name:kArrayVPNStatusNotification
+                                               object:nil];
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [self setVPNStatus];
+    if (![self clearVPNInfoIfNotConnected]) {
+        [self setMTU];
+        [self refreshVPNStatusWithPeriod:TIMER_PERIOD];
+    }
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [self stopFetchInfo];
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+#pragma mark - All Status Information
+- (void)setVPNStatus {
+    NSString *statusString = @"";
+    ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+    
+    switch (tunnelStatus) {
+        case ArrayVPNInavlid:
+        case ArrayVPNDisconnecting:
+        case ArrayVPNDisconnected:
+            statusString = NSLocalizedString(@"Disconnected", nil);
+            break;
+        case ArrayVPNConnecting:
+        case ArrayVPNReasserting:
+            statusString = NSLocalizedString(@"Connecting...", nil);
+            break;
+        case ArrayVPNConnected:
+            statusString = NSLocalizedString(@"Connected", nil);
+            break;
+        default:
+            ANError(@"Invalid VPN tunnel status \(%zi).", tunnelStatus);
+            break;
+    }
+    
+    self.stateLabel.text = statusString;
+}
+
+// VPN Status Handler
+- (void)handleVPNStatus:(NSNotification *)notification {
+    ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+    
+    ANInfo(@"Array VPN tunnel status = %zi", tunnelStatus);
+    
+    if (tunnelStatus != ArrayVPNConnected) {
+        [self clearVPNInfo];
+        [self stopFetchInfo];
+        if (self.needReconnect && tunnelStatus == ArrayVPNDisconnected) {
+            ANInfo(@"custom dns server config, now need restart vpn.");
+            self.needReconnect = NO;
+            [self startVPN:NO];
+        }
+    } else {
+        if (_timer == nil) {
+            [self refreshVPNStatusWithPeriod:TIMER_PERIOD];
+        }
+        ANInfo(@"Array VPN tunnel status is connected");
+        if (tunnelStatus == ArrayVPNConnected) {
+            NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameStatus];
+            for (int i = 0; i < 3; i++) {
+                NSMutableArray *newDNSList = [userDefaults valueForKey:@"dns_list"];
+                ANInfo(@"get new dns list[%@], i =%d", newDNSList, i);
+                if (newDNSList.count > 0) {
+                    //[userDefaults removeObjectForKey:@"dns_list"];
+                    _dnsList = newDNSList;
+                    ANInfo(@"status connected:get dns list= %@", _dnsList);
+                    [self.tableView reloadData];
+                    break;
+                } else {
+                    sleep(1);
+                }
+            }
+        }
+    }
+}
+
+- (BOOL)startVPN:(BOOL)isAutoStart {
+    //Gateway *gateway = [self getCurrentGateway];
+    //NSString *session = [AAAManager sharedInstance].sessionID;
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    
+#if TARGET_OS_IPHONE
+    //Reset connect fail reason.
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameStatus];
+    [userDefaults removeObjectForKey:@"tunnel_result"];
+    [userDefaults removeObjectForKey:@"dns_list"];
+#endif
+    
+    [vpnWrapper startSSLVPN];
+    
+    return YES;
+}
+
+- (void)stopVPN {
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    [vpnWrapper stopSSLVPN];
+}
+
+// Clear all statistics information if vpn is not connected.
+- (BOOL)clearVPNInfoIfNotConnected {
+    ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+    if (tunnelStatus != ArrayVPNConnected) {
+        [self clearVPNInfo];
+        
+        return YES;
+    }
+    
+    return NO;
+}
+
+- (void)clearVPNInfo {
+    self.serverLabel.text = @"";
+    self.ipAddressLabel.text = @"";
+    self.timeLabel.text = @"";
+    self.mtuLabel.text = @"";
+    self.modeLabel.text = @"";
+    self.dataSentLabel.text = @"";
+    self.dataReceivedLabel.text = @"";
+}
+
+// From local progress.
+- (void)setConnectedTime {
+    NSDate *connectedDate = [ArrayVPNManager sharedInstance].tunnelManager.connection.connectedDate;
+    NSString *timeString = [self formatDate:connectedDate];
+    
+    self.timeLabel.text = timeString;
+}
+
+// MTU is hard-coded, default value is 1400.
+- (void)setMTU {
+    self.mtuLabel.text = [NSString stringWithFormat:@"%d", VPN_PLUGIN_DEFAULT_MTU];
+}
+
+// From VPN extension.
+- (void)refreshVPNStatusWithPeriod:(NSTimeInterval)period {
+    _timer = [NSTimer timerWithTimeInterval:period
+                                     target:self
+                                   selector:@selector(timerHandler)
+                                   userInfo:nil
+                                    repeats:YES];
+    
+    [[NSRunLoop currentRunLoop]addTimer:_timer forMode:NSDefaultRunLoopMode];
+    [_timer fire];
+}
+
+- (void)timerHandler {
+    if (++_tick == REFRESH_VPN_STATUS_PERIOD) {
+        _tick = 0;
+        
+        [self fetchVPNTunnelStatsInfo];
+    }
+    
+    [self setConnectedTime];
+    [self setMTU];
+}
+
+- (void)fetchVPNTunnelStatsInfo {
+    NSError *error = nil;
+    
+    NETunnelProviderManager *manager = [[ArrayVPNManager sharedInstance] tunnelManager];
+    NETunnelProviderSession *session = (NETunnelProviderSession *)manager.connection;
+    
+    NSDictionary *IPCRequestDict = @{(__bridge NSString *)kIPCType:(__bridge NSString *)kIPCStatsRequest};
+    NSData *IPCRequest = [NSJSONSerialization dataWithJSONObject:IPCRequestDict
+                                                         options:NSJSONWritingPrettyPrinted
+                                                           error:nil];
+    
+    __weak typeof(self) weakSelf = self;
+    [session sendProviderMessage:IPCRequest
+                     returnError:&error
+                 responseHandler:^(NSData * _Nullable responseData) {
+                     if (responseData) {
+                         ANDebug(@"IPC response received.");
+                         
+                         NSError *error = nil;
+                         NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:responseData
+                                                                              options:NSJSONReadingMutableContainers
+                                                                                error:&error];
+                         if (!dict) {
+                             ANError(@"Parse IPC response failed with error: %@.", error);
+                             return;
+                         }
+                         NSDictionary *IPCData = [dict objectForKey:(__bridge NSString *)kIPCResponseData];
+                         if (responseData != nil) {
+                             [weakSelf updateDisplayedVPNStatsWithDict:IPCData];
+                         } else {
+                             ANError(@"IPC data is not found in response.");
+                         }
+                     } else {
+                         ANError(@"IPC response is nil.");
+                     }
+                 }];
+    if (error) {
+        ANError(@"Send IPC failed with error: %@.", error.localizedDescription);
+    }
+}
+
+- (void)updateDisplayedVPNStatsWithDict:(NSDictionary *)dict {
+    NSNumber *clientIP = [dict objectForKey:(__bridge NSString *)kIPCStatsClientIP];
+    NSString *serverHost = [dict objectForKey:(__bridge NSString *)kIPCStatsServerHost];
+    NSNumber *sentBytes = [dict objectForKey:(__bridge NSString *)kIPCStatsSentBytes];
+    NSNumber *receivedBytes = [dict objectForKey:(__bridge NSString *)kIPCStatsReceviedBytes];
+    NSNumber *isFullTunnel = [dict objectForKey:(__bridge NSString *)kIPCStatsIsFullTunnel];
+    
+    NSString *sentToShow = [self formatBytes:[sentBytes stringValue]];
+    NSString *recvToShow = [self formatBytes:[receivedBytes stringValue]];
+    
+    self.ipAddressLabel.text = [self formatIP:clientIP];
+    self.serverLabel.text = serverHost;
+    self.modeLabel.text = [isFullTunnel boolValue] ? NSLocalizedString(@"Full Tunnel", nil) : NSLocalizedString(@"Split Tunnel", nil);
+    
+    if (sentToShow) {
+        self.dataSentLabel.text = sentToShow;
+    }
+    if (recvToShow) {
+        self.dataReceivedLabel.text = recvToShow;
+    }
+}
+
+- (void)stopFetchInfo {
+    [_timer invalidate];
+    _timer = nil;
+}
+
+#pragma mark - Helpers
+- (NSString *)formatIP:(NSNumber *)IP {
+    if (!IP) {
+        return @"0.0.0.0";
+    }
+    
+    uint32_t ip = [IP unsignedIntValue];
+    
+    return [NSString stringWithFormat:@"%d.%d.%d.%d", IPSTR(ip)];
+}
+
+- (NSString *)formatBytes:(NSString *)bytes {
+    
+#define K_BYTES     1024
+#define M_BYTES     (1024 * 1024)
+    
+    if (!bytes) {
+        return nil;
+    }
+    
+    uint64_t uBytes = (uint64_t)[bytes integerValue];
+    if (uBytes > M_BYTES) {
+        return [NSString stringWithFormat:@"%.1f MB", (double)uBytes/M_BYTES];
+    } else if (uBytes > K_BYTES) {
+        return [NSString stringWithFormat:@"%.1f KB", (double)uBytes/K_BYTES];
+    }
+    
+    return [NSString stringWithFormat:@"%@ B", bytes];
+}
+
+- (NSString *)formatDate:(NSDate *)date {
+    if (!date) {
+        return NSLocalizedString(@"Unconnected", nil);
+    }
+    
+    NSTimeInterval now = [[NSDate date] timeIntervalSince1970];
+    NSTimeInterval connectedDateInterval = [date timeIntervalSince1970];
+    NSUInteger seconds = (NSUInteger)round(now - connectedDateInterval);
+    NSString *dateString = [NSString stringWithFormat:@"%02zi:%02zi:%02zi",
+                            seconds / 3600, (seconds / 60) % 60, seconds % 60];
+    
+    return [NSString stringWithFormat:@"%@", dateString];
+}
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return kStatusSectionTotal;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    if (section == kStatusSectionConnectionInfo) {
+        return 6;
+    } else if (section == kStatusSectionStatistics) {
+        return 2;
+    } else if (section == kStatusSectionDNS){
+        if (_dnsList.count < 16) {
+            return _dnsList.count + 1;
+        } else {
+            return 16;
+        }
+    }
+    return 0;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell *cell = nil;
+    
+    if (indexPath.section == kStatusSectionDNS) {
+        DNSSettingCell *dnsSettingCell = [tableView dequeueReusableCellWithIdentifier:kDNSSettingCellID];
+        dnsSettingCell.delegate = self;
+        if (!dnsSettingCell) {
+            dnsSettingCell = [[DNSSettingCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kDNSSettingCellID];;
+        }
+        
+        NSInteger row = indexPath.row;
+        if (_dnsList.count < 16) {
+            if (row == 0) {
+                [dnsSettingCell configureCellWithMessage:@"" isAddCell:YES];
+            } else {
+                [dnsSettingCell configureCellWithMessage:[_dnsList objectAtIndex:row - 1] isAddCell:NO];
+            }
+        } else {
+            [dnsSettingCell configureCellWithMessage:[_dnsList objectAtIndex:row] isAddCell:NO];
+        }
+        
+        return dnsSettingCell;
+    } else {
+        cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
+    }
+    return cell;
+}
+
+
+#pragma mark - UITableViewDelegate
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    return 35;
+}
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+#pragma mark - DNSSettingCellDelegate
+- (void)DNSSettingButtonDidClickedWithCell:(UITableViewCell *)cell isAdd:(BOOL)bAdd {
+    DNSSettingCell* dnsCell = (DNSSettingCell *)(cell);
+    NSMutableArray *tmpArray = [NSMutableArray arrayWithArray:_dnsList];
+    NSString *errMessage = @"", *titleMessage = @"";
+    if (bAdd) {
+        NSArray *newDnsArray = [dnsCell.addDnsTextField.text componentsSeparatedByString:@";"];
+        BOOL bValidDNSServer = YES;
+        if ([newDnsArray count] > 0) {
+            for (NSString *signalDNS in newDnsArray) {
+                if (!isValidDNSServer([signalDNS UTF8String])) {
+                    bValidDNSServer = NO;
+                }
+            }
+        } else {
+            bValidDNSServer = NO;
+        }
+        
+        if (bValidDNSServer) {
+            [tmpArray addObjectsFromArray:newDnsArray];
+        } else {
+            errMessage = NSLocalizedString(@"The format of the DNS server is invalid.", nil);
+            titleMessage = NSLocalizedString(@"Error", nil);
+        }
+    } else {
+        [tmpArray removeObject:dnsCell.descText.text];
+        if([tmpArray count] <= 0) {
+            errMessage = NSLocalizedString(@"Make sure at least one DNS server exists in the system.", nil);
+            titleMessage = NSLocalizedString(@"Information", nil);
+        }
+    }
+    
+    if ([errMessage length] > 0) {
+        PopupDialog *popup = [ANPopupDialog singleButtonPopupDialogWithTitle:titleMessage message:errMessage];
+        [self presentViewController:popup animated:YES completion:nil];
+        return;
+    }
+    _dnsList = tmpArray;
+    ANInfo(@"new dns list=%@", _dnsList);
+    [self.tableView reloadData];
+    
+    NSString *dnsListString = [_dnsList componentsJoinedByString:@";"];
+    Gateway *currentGateway = [self getCurrentGateway];
+    currentGateway.customDnsList = dnsListString;
+    ANInfo(@"save current gateway custom dns list=%@", currentGateway.customDnsList);
+    GatewayManager *gatewayManager = [GatewayManager sharedInstance];
+    [gatewayManager updateGateway:currentGateway];
+    self.needReconnect = YES;
+    [self stopVPN];
+}
+
+- (Gateway *)getCurrentGateway {
+    AAAManager *manager = [AAAManager sharedInstance];
+    VPNAccount *account = manager.account;
+    GatewayManager *gm = [GatewayManager sharedInstance];
+    NSString *url = account.vsURL;
+    NSString *port = account.vsPort;
+    if ([url length] <= 0) {
+        NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameStatus];
+        NSString *oauthUrl = [userDefaults valueForKey:KEY_OAUTH_URL];
+        if (oauthUrl.length > 0) {
+            ANInfo(@"getCurrentGateway: Get oauth url[%@].", oauthUrl);
+            NSRange range = [oauthUrl rangeOfString:@"https://"];
+            oauthUrl = [oauthUrl substringFromIndex:range.location + range.length];
+            range = [oauthUrl rangeOfString:@"/prx/000/"];
+            url = [oauthUrl substringToIndex:range.location];
+            ANInfo(@"getCurrentGateway: Get url[%@].", url);
+        }
+    }
+    NSInteger index = [gm indexOfUrl:url andport:port];
+    
+    return [gm gatewayAtIndex:index];
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/StatusViewController.m.InfosecStore
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/StatusViewController.m.InfosecStore	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/StatusViewController.m.InfosecStore	(working copy)
@@ -0,0 +1,509 @@
+//
+//  StatusViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/27.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+#include <arpa/inet.h>
+#import "ANLogger.h"
+#import "arrayapi.h"
+#import "vpnplugin.h"
+#import "ArrayVPNManager.h"
+#import "ArrayVPNWrapper.h"
+#import "ANPopupDialog.h"
+#import "AAAManager.h"
+#import "GatewayManager.h"
+#import "StatusViewController.h"
+#import "DNSSettingCell.h"
+#import "UIViewController+HideKeyboard.h"
+
+BOOL isValidDNSServer(const char *dnsServer);
+
+BOOL isValidDNSServer(const char *dnsServer)
+{
+    if (!dnsServer) {
+        return NO;
+    }
+    
+    struct sockaddr_in sa;
+    int result = inet_pton(AF_INET, dnsServer, &(sa.sin_addr));
+    return result != 0;
+}
+
+#define SECTIONS_IN_STATUS_VIEW             2
+#define ROWS_IN_SECTION_CONNECTION_INFO     6
+#define ROWS_IN_SECIONT_STATISTICS          2
+
+typedef NS_ENUM(NSInteger, StatusSectionIndex) {
+    kStatusSectionConnectionInfo = 0,
+    kStatusSectionDNS,
+    kStatusSectionStatistics,
+    kStatusSectionTotal
+};
+
+#define TIMER_PERIOD                1
+#define REFRESH_VPN_STATUS_PERIOD   3
+
+#if TARGET_OS_IPHONE
+NSString * const kAppGroupNameStatus = @"group.net.infosec.MotionPro";
+#elif TARGET_OS_MAC
+NSString * const kAppGroupNameStatus = @"5VZLZ3YQ9P.net.arraynetworks.MacTunnel";
+#endif
+
+@interface StatusViewController () <DNSSettingCellDelegate> {
+    NSTimer *_timer;
+    NSInteger _tick;
+}
+
+@property (weak, nonatomic) IBOutlet UILabel *stateLabel;
+@property (weak, nonatomic) IBOutlet UILabel *serverLabel;
+@property (weak, nonatomic) IBOutlet UILabel *ipAddressLabel;
+@property (weak, nonatomic) IBOutlet UILabel *timeLabel;
+@property (weak, nonatomic) IBOutlet UILabel *mtuLabel;
+@property (weak, nonatomic) IBOutlet UILabel *modeLabel;
+@property (weak, nonatomic) IBOutlet UILabel *dataSentLabel;
+@property (weak, nonatomic) IBOutlet UILabel *dataReceivedLabel;
+@property (strong, nonatomic) NSMutableArray *dnsList;
+@property (nonatomic) BOOL needReconnect;
+
+@end
+
+@implementation StatusViewController
+
+- (void)dealloc {
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    [self enableHideKeyboard];
+    
+    [self.tableView registerNib:[UINib nibWithNibName:@"DNSSettingCell" bundle:nil] forCellReuseIdentifier:kDNSSettingCellID];
+    self.needReconnect = NO;
+    
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameStatus];
+    NSMutableArray *newDNSList = [userDefaults valueForKey:@"dns_list"];
+    ANInfo(@"viewDidLoad:get new dns list[%@]", newDNSList);
+    if (newDNSList.count > 0) {
+        [userDefaults removeObjectForKey:@"dns_list"];
+        _dnsList = newDNSList;
+        ANInfo(@"viewDidLoad:get dns list= %@", _dnsList);
+    }
+    
+    if (![self clearVPNInfoIfNotConnected]) {
+        [self fetchVPNTunnelStatsInfo];
+    }
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(handleVPNStatus:)
+                                                 name:kArrayVPNStatusNotification
+                                               object:nil];
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [self setVPNStatus];
+    if (![self clearVPNInfoIfNotConnected]) {
+        [self setMTU];
+        [self refreshVPNStatusWithPeriod:TIMER_PERIOD];
+    }
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [self stopFetchInfo];
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+#pragma mark - All Status Information
+- (void)setVPNStatus {
+    NSString *statusString = @"";
+    ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+    
+    switch (tunnelStatus) {
+        case ArrayVPNInavlid:
+        case ArrayVPNDisconnecting:
+        case ArrayVPNDisconnected:
+            statusString = NSLocalizedString(@"Disconnected", nil);
+            break;
+        case ArrayVPNConnecting:
+        case ArrayVPNReasserting:
+            statusString = NSLocalizedString(@"Connecting...", nil);
+            break;
+        case ArrayVPNConnected:
+            statusString = NSLocalizedString(@"Connected", nil);
+            break;
+        default:
+            ANError(@"Invalid VPN tunnel status \(%zi).", tunnelStatus);
+            break;
+    }
+    
+    self.stateLabel.text = statusString;
+}
+
+// VPN Status Handler
+- (void)handleVPNStatus:(NSNotification *)notification {
+    ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+    
+    ANInfo(@"Array VPN tunnel status = %zi", tunnelStatus);
+    
+    if (tunnelStatus != ArrayVPNConnected) {
+        [self clearVPNInfo];
+        [self stopFetchInfo];
+        if (self.needReconnect && tunnelStatus == ArrayVPNDisconnected) {
+            ANInfo(@"custom dns server config, now need restart vpn.");
+            self.needReconnect = NO;
+            [self startVPN:NO];
+        }
+    } else {
+        if (_timer == nil) {
+            [self refreshVPNStatusWithPeriod:TIMER_PERIOD];
+        }
+        ANInfo(@"Array VPN tunnel status is connected");
+        if (tunnelStatus == ArrayVPNConnected) {
+            NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameStatus];
+            for (int i = 0; i < 3; i++) {
+                NSMutableArray *newDNSList = [userDefaults valueForKey:@"dns_list"];
+                ANInfo(@"get new dns list[%@], i =%d", newDNSList, i);
+                if (newDNSList.count > 0) {
+                    //[userDefaults removeObjectForKey:@"dns_list"];
+                    _dnsList = newDNSList;
+                    ANInfo(@"status connected:get dns list= %@", _dnsList);
+                    [self.tableView reloadData];
+                    break;
+                } else {
+                    sleep(1);
+                }
+            }
+        }
+    }
+}
+
+- (BOOL)startVPN:(BOOL)isAutoStart {
+    //Gateway *gateway = [self getCurrentGateway];
+    //NSString *session = [AAAManager sharedInstance].sessionID;
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    
+#if TARGET_OS_IPHONE
+    //Reset connect fail reason.
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameStatus];
+    [userDefaults removeObjectForKey:@"tunnel_result"];
+    [userDefaults removeObjectForKey:@"dns_list"];
+#endif
+    
+    [vpnWrapper startSSLVPN];
+    
+    return YES;
+}
+
+- (void)stopVPN {
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    [vpnWrapper stopSSLVPN];
+}
+
+// Clear all statistics information if vpn is not connected.
+- (BOOL)clearVPNInfoIfNotConnected {
+    ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+    if (tunnelStatus != ArrayVPNConnected) {
+        [self clearVPNInfo];
+        
+        return YES;
+    }
+    
+    return NO;
+}
+
+- (void)clearVPNInfo {
+    self.serverLabel.text = @"";
+    self.ipAddressLabel.text = @"";
+    self.timeLabel.text = @"";
+    self.mtuLabel.text = @"";
+    self.modeLabel.text = @"";
+    self.dataSentLabel.text = @"";
+    self.dataReceivedLabel.text = @"";
+}
+
+// From local progress.
+- (void)setConnectedTime {
+    NSDate *connectedDate = [ArrayVPNManager sharedInstance].tunnelManager.connection.connectedDate;
+    NSString *timeString = [self formatDate:connectedDate];
+    
+    self.timeLabel.text = timeString;
+}
+
+// MTU is hard-coded, default value is 1400.
+- (void)setMTU {
+    self.mtuLabel.text = [NSString stringWithFormat:@"%d", VPN_PLUGIN_DEFAULT_MTU];
+}
+
+// From VPN extension.
+- (void)refreshVPNStatusWithPeriod:(NSTimeInterval)period {
+    _timer = [NSTimer timerWithTimeInterval:period
+                                     target:self
+                                   selector:@selector(timerHandler)
+                                   userInfo:nil
+                                    repeats:YES];
+    
+    [[NSRunLoop currentRunLoop]addTimer:_timer forMode:NSDefaultRunLoopMode];
+    [_timer fire];
+}
+
+- (void)timerHandler {
+    if (++_tick == REFRESH_VPN_STATUS_PERIOD) {
+        _tick = 0;
+        
+        [self fetchVPNTunnelStatsInfo];
+    }
+    
+    [self setConnectedTime];
+    [self setMTU];
+}
+
+- (void)fetchVPNTunnelStatsInfo {
+    NSError *error = nil;
+    
+    NETunnelProviderManager *manager = [[ArrayVPNManager sharedInstance] tunnelManager];
+    NETunnelProviderSession *session = (NETunnelProviderSession *)manager.connection;
+    
+    NSDictionary *IPCRequestDict = @{(__bridge NSString *)kIPCType:(__bridge NSString *)kIPCStatsRequest};
+    NSData *IPCRequest = [NSJSONSerialization dataWithJSONObject:IPCRequestDict
+                                                         options:NSJSONWritingPrettyPrinted
+                                                           error:nil];
+    
+    __weak typeof(self) weakSelf = self;
+    [session sendProviderMessage:IPCRequest
+                     returnError:&error
+                 responseHandler:^(NSData * _Nullable responseData) {
+                     if (responseData) {
+                         ANDebug(@"IPC response received.");
+                         
+                         NSError *error = nil;
+                         NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:responseData
+                                                                              options:NSJSONReadingMutableContainers
+                                                                                error:&error];
+                         if (!dict) {
+                             ANError(@"Parse IPC response failed with error: %@.", error);
+                             return;
+                         }
+                         NSDictionary *IPCData = [dict objectForKey:(__bridge NSString *)kIPCResponseData];
+                         if (responseData != nil) {
+                             [weakSelf updateDisplayedVPNStatsWithDict:IPCData];
+                         } else {
+                             ANError(@"IPC data is not found in response.");
+                         }
+                     } else {
+                         ANError(@"IPC response is nil.");
+                     }
+                 }];
+    if (error) {
+        ANError(@"Send IPC failed with error: %@.", error.localizedDescription);
+    }
+}
+
+- (void)updateDisplayedVPNStatsWithDict:(NSDictionary *)dict {
+    NSNumber *clientIP = [dict objectForKey:(__bridge NSString *)kIPCStatsClientIP];
+    NSString *serverHost = [dict objectForKey:(__bridge NSString *)kIPCStatsServerHost];
+    NSNumber *sentBytes = [dict objectForKey:(__bridge NSString *)kIPCStatsSentBytes];
+    NSNumber *receivedBytes = [dict objectForKey:(__bridge NSString *)kIPCStatsReceviedBytes];
+    NSNumber *isFullTunnel = [dict objectForKey:(__bridge NSString *)kIPCStatsIsFullTunnel];
+    
+    NSString *sentToShow = [self formatBytes:[sentBytes stringValue]];
+    NSString *recvToShow = [self formatBytes:[receivedBytes stringValue]];
+    
+    self.ipAddressLabel.text = [self formatIP:clientIP];
+    self.serverLabel.text = serverHost;
+    self.modeLabel.text = [isFullTunnel boolValue] ? NSLocalizedString(@"Full Tunnel", nil) : NSLocalizedString(@"Split Tunnel", nil);
+    
+    if (sentToShow) {
+        self.dataSentLabel.text = sentToShow;
+    }
+    if (recvToShow) {
+        self.dataReceivedLabel.text = recvToShow;
+    }
+}
+
+- (void)stopFetchInfo {
+    [_timer invalidate];
+    _timer = nil;
+}
+
+#pragma mark - Helpers
+- (NSString *)formatIP:(NSNumber *)IP {
+    if (!IP) {
+        return @"0.0.0.0";
+    }
+    
+    uint32_t ip = [IP unsignedIntValue];
+    
+    return [NSString stringWithFormat:@"%d.%d.%d.%d", IPSTR(ip)];
+}
+
+- (NSString *)formatBytes:(NSString *)bytes {
+    
+#define K_BYTES     1024
+#define M_BYTES     (1024 * 1024)
+    
+    if (!bytes) {
+        return nil;
+    }
+    
+    uint64_t uBytes = (uint64_t)[bytes integerValue];
+    if (uBytes > M_BYTES) {
+        return [NSString stringWithFormat:@"%.1f MB", (double)uBytes/M_BYTES];
+    } else if (uBytes > K_BYTES) {
+        return [NSString stringWithFormat:@"%.1f KB", (double)uBytes/K_BYTES];
+    }
+    
+    return [NSString stringWithFormat:@"%@ B", bytes];
+}
+
+- (NSString *)formatDate:(NSDate *)date {
+    if (!date) {
+        return NSLocalizedString(@"Unconnected", nil);
+    }
+    
+    NSTimeInterval now = [[NSDate date] timeIntervalSince1970];
+    NSTimeInterval connectedDateInterval = [date timeIntervalSince1970];
+    NSUInteger seconds = (NSUInteger)round(now - connectedDateInterval);
+    NSString *dateString = [NSString stringWithFormat:@"%02zi:%02zi:%02zi",
+                            seconds / 3600, (seconds / 60) % 60, seconds % 60];
+    
+    return [NSString stringWithFormat:@"%@", dateString];
+}
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return kStatusSectionTotal;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    if (section == kStatusSectionConnectionInfo) {
+        return 6;
+    } else if (section == kStatusSectionStatistics) {
+        return 2;
+    } else if (section == kStatusSectionDNS){
+        if (_dnsList.count < 16) {
+            return _dnsList.count + 1;
+        } else {
+            return 16;
+        }
+    }
+    return 0;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell *cell = nil;
+    
+    if (indexPath.section == kStatusSectionDNS) {
+        DNSSettingCell *dnsSettingCell = [tableView dequeueReusableCellWithIdentifier:kDNSSettingCellID];
+        dnsSettingCell.delegate = self;
+        if (!dnsSettingCell) {
+            dnsSettingCell = [[DNSSettingCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kDNSSettingCellID];;
+        }
+        
+        NSInteger row = indexPath.row;
+        if (_dnsList.count < 16) {
+            if (row == 0) {
+                [dnsSettingCell configureCellWithMessage:@"" isAddCell:YES];
+            } else {
+                [dnsSettingCell configureCellWithMessage:[_dnsList objectAtIndex:row - 1] isAddCell:NO];
+            }
+        } else {
+            [dnsSettingCell configureCellWithMessage:[_dnsList objectAtIndex:row] isAddCell:NO];
+        }
+        
+        return dnsSettingCell;
+    } else {
+        cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
+    }
+    return cell;
+}
+
+
+#pragma mark - UITableViewDelegate
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    return 35;
+}
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+#pragma mark - DNSSettingCellDelegate
+- (void)DNSSettingButtonDidClickedWithCell:(UITableViewCell *)cell isAdd:(BOOL)bAdd {
+    DNSSettingCell* dnsCell = (DNSSettingCell *)(cell);
+    NSMutableArray *tmpArray = [NSMutableArray arrayWithArray:_dnsList];
+    NSString *errMessage = @"", *titleMessage = @"";
+    if (bAdd) {
+        NSArray *newDnsArray = [dnsCell.addDnsTextField.text componentsSeparatedByString:@";"];
+        BOOL bValidDNSServer = YES;
+        if ([newDnsArray count] > 0) {
+            for (NSString *signalDNS in newDnsArray) {
+                if (!isValidDNSServer([signalDNS UTF8String])) {
+                    bValidDNSServer = NO;
+                }
+            }
+        } else {
+            bValidDNSServer = NO;
+        }
+        
+        if (bValidDNSServer) {
+            [tmpArray addObjectsFromArray:newDnsArray];
+        } else {
+            errMessage = NSLocalizedString(@"The format of the DNS server is invalid.", nil);
+            titleMessage = NSLocalizedString(@"Error", nil);
+        }
+    } else {
+        [tmpArray removeObject:dnsCell.descText.text];
+        if([tmpArray count] <= 0) {
+            errMessage = NSLocalizedString(@"Make sure at least one DNS server exists in the system.", nil);
+            titleMessage = NSLocalizedString(@"Information", nil);
+        }
+    }
+    
+    if ([errMessage length] > 0) {
+        PopupDialog *popup = [ANPopupDialog singleButtonPopupDialogWithTitle:titleMessage message:errMessage];
+        [self presentViewController:popup animated:YES completion:nil];
+        return;
+    }
+    _dnsList = tmpArray;
+    ANInfo(@"new dns list=%@", _dnsList);
+    [self.tableView reloadData];
+    
+    NSString *dnsListString = [_dnsList componentsJoinedByString:@";"];
+    Gateway *currentGateway = [self getCurrentGateway];
+    currentGateway.customDnsList = dnsListString;
+    ANInfo(@"save current gateway custom dns list=%@", currentGateway.customDnsList);
+    GatewayManager *gatewayManager = [GatewayManager sharedInstance];
+    [gatewayManager updateGateway:currentGateway];
+    self.needReconnect = YES;
+    [self stopVPN];
+}
+
+- (Gateway *)getCurrentGateway {
+    AAAManager *manager = [AAAManager sharedInstance];
+    VPNAccount *account = manager.account;
+    GatewayManager *gm = [GatewayManager sharedInstance];
+    NSString *url = account.vsURL;
+    NSString *port = account.vsPort;
+    if ([url length] <= 0) {
+        NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameStatus];
+        NSString *oauthUrl = [userDefaults valueForKey:KEY_OAUTH_URL];
+        if (oauthUrl.length > 0) {
+            ANInfo(@"getCurrentGateway: Get oauth url[%@].", oauthUrl);
+            NSRange range = [oauthUrl rangeOfString:@"https://"];
+            oauthUrl = [oauthUrl substringFromIndex:range.location + range.length];
+            range = [oauthUrl rangeOfString:@"/prx/000/"];
+            url = [oauthUrl substringToIndex:range.location];
+            ANInfo(@"getCurrentGateway: Get url[%@].", url);
+        }
+    }
+    NSInteger index = [gm indexOfUrl:url andport:port];
+    
+    return [gm gatewayAtIndex:index];
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/StatusViewController.m.MotionPro
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/StatusViewController.m.MotionPro	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/StatusViewController.m.MotionPro	(working copy)
@@ -0,0 +1,509 @@
+//
+//  StatusViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/27.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+#include <arpa/inet.h>
+#import "ANLogger.h"
+#import "arrayapi.h"
+#import "vpnplugin.h"
+#import "ArrayVPNManager.h"
+#import "ArrayVPNWrapper.h"
+#import "ANPopupDialog.h"
+#import "AAAManager.h"
+#import "GatewayManager.h"
+#import "StatusViewController.h"
+#import "DNSSettingCell.h"
+#import "UIViewController+HideKeyboard.h"
+
+BOOL isValidDNSServer(const char *dnsServer);
+
+BOOL isValidDNSServer(const char *dnsServer)
+{
+    if (!dnsServer) {
+        return NO;
+    }
+    
+    struct sockaddr_in sa;
+    int result = inet_pton(AF_INET, dnsServer, &(sa.sin_addr));
+    return result != 0;
+}
+
+#define SECTIONS_IN_STATUS_VIEW             2
+#define ROWS_IN_SECTION_CONNECTION_INFO     6
+#define ROWS_IN_SECIONT_STATISTICS          2
+
+typedef NS_ENUM(NSInteger, StatusSectionIndex) {
+    kStatusSectionConnectionInfo = 0,
+    kStatusSectionDNS,
+    kStatusSectionStatistics,
+    kStatusSectionTotal
+};
+
+#define TIMER_PERIOD                1
+#define REFRESH_VPN_STATUS_PERIOD   3
+
+#if TARGET_OS_IPHONE
+NSString * const kAppGroupNameStatus = @"group.net.arraynetworks.MotionPro";
+#elif TARGET_OS_MAC
+NSString * const kAppGroupNameStatus = @"5VZLZ3YQ9P.net.arraynetworks.MacTunnel";
+#endif
+
+@interface StatusViewController () <DNSSettingCellDelegate> {
+    NSTimer *_timer;
+    NSInteger _tick;
+}
+
+@property (weak, nonatomic) IBOutlet UILabel *stateLabel;
+@property (weak, nonatomic) IBOutlet UILabel *serverLabel;
+@property (weak, nonatomic) IBOutlet UILabel *ipAddressLabel;
+@property (weak, nonatomic) IBOutlet UILabel *timeLabel;
+@property (weak, nonatomic) IBOutlet UILabel *mtuLabel;
+@property (weak, nonatomic) IBOutlet UILabel *modeLabel;
+@property (weak, nonatomic) IBOutlet UILabel *dataSentLabel;
+@property (weak, nonatomic) IBOutlet UILabel *dataReceivedLabel;
+@property (strong, nonatomic) NSMutableArray *dnsList;
+@property (nonatomic) BOOL needReconnect;
+
+@end
+
+@implementation StatusViewController
+
+- (void)dealloc {
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    [self enableHideKeyboard];
+    
+    [self.tableView registerNib:[UINib nibWithNibName:@"DNSSettingCell" bundle:nil] forCellReuseIdentifier:kDNSSettingCellID];
+    self.needReconnect = NO;
+    
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameStatus];
+    NSMutableArray *newDNSList = [userDefaults valueForKey:@"dns_list"];
+    ANInfo(@"viewDidLoad:get new dns list[%@]", newDNSList);
+    if (newDNSList.count > 0) {
+        [userDefaults removeObjectForKey:@"dns_list"];
+        _dnsList = newDNSList;
+        ANInfo(@"viewDidLoad:get dns list= %@", _dnsList);
+    }
+    
+    if (![self clearVPNInfoIfNotConnected]) {
+        [self fetchVPNTunnelStatsInfo];
+    }
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(handleVPNStatus:)
+                                                 name:kArrayVPNStatusNotification
+                                               object:nil];
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [self setVPNStatus];
+    if (![self clearVPNInfoIfNotConnected]) {
+        [self setMTU];
+        [self refreshVPNStatusWithPeriod:TIMER_PERIOD];
+    }
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [self stopFetchInfo];
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+#pragma mark - All Status Information
+- (void)setVPNStatus {
+    NSString *statusString = @"";
+    ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+    
+    switch (tunnelStatus) {
+        case ArrayVPNInavlid:
+        case ArrayVPNDisconnecting:
+        case ArrayVPNDisconnected:
+            statusString = NSLocalizedString(@"Disconnected", nil);
+            break;
+        case ArrayVPNConnecting:
+        case ArrayVPNReasserting:
+            statusString = NSLocalizedString(@"Connecting...", nil);
+            break;
+        case ArrayVPNConnected:
+            statusString = NSLocalizedString(@"Connected", nil);
+            break;
+        default:
+            ANError(@"Invalid VPN tunnel status \(%zi).", tunnelStatus);
+            break;
+    }
+    
+    self.stateLabel.text = statusString;
+}
+
+// VPN Status Handler
+- (void)handleVPNStatus:(NSNotification *)notification {
+    ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+    
+    ANInfo(@"Array VPN tunnel status = %zi", tunnelStatus);
+    
+    if (tunnelStatus != ArrayVPNConnected) {
+        [self clearVPNInfo];
+        [self stopFetchInfo];
+        if (self.needReconnect && tunnelStatus == ArrayVPNDisconnected) {
+            ANInfo(@"custom dns server config, now need restart vpn.");
+            self.needReconnect = NO;
+            [self startVPN:NO];
+        }
+    } else {
+        if (_timer == nil) {
+            [self refreshVPNStatusWithPeriod:TIMER_PERIOD];
+        }
+        ANInfo(@"Array VPN tunnel status is connected");
+        if (tunnelStatus == ArrayVPNConnected) {
+            NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameStatus];
+            for (int i = 0; i < 3; i++) {
+                NSMutableArray *newDNSList = [userDefaults valueForKey:@"dns_list"];
+                ANInfo(@"get new dns list[%@], i =%d", newDNSList, i);
+                if (newDNSList.count > 0) {
+                    //[userDefaults removeObjectForKey:@"dns_list"];
+                    _dnsList = newDNSList;
+                    ANInfo(@"status connected:get dns list= %@", _dnsList);
+                    [self.tableView reloadData];
+                    break;
+                } else {
+                    sleep(1);
+                }
+            }
+        }
+    }
+}
+
+- (BOOL)startVPN:(BOOL)isAutoStart {
+    //Gateway *gateway = [self getCurrentGateway];
+    //NSString *session = [AAAManager sharedInstance].sessionID;
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    
+#if TARGET_OS_IPHONE
+    //Reset connect fail reason.
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameStatus];
+    [userDefaults removeObjectForKey:@"tunnel_result"];
+    [userDefaults removeObjectForKey:@"dns_list"];
+#endif
+    
+    [vpnWrapper startSSLVPN];
+    
+    return YES;
+}
+
+- (void)stopVPN {
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    [vpnWrapper stopSSLVPN];
+}
+
+// Clear all statistics information if vpn is not connected.
+- (BOOL)clearVPNInfoIfNotConnected {
+    ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+    if (tunnelStatus != ArrayVPNConnected) {
+        [self clearVPNInfo];
+        
+        return YES;
+    }
+    
+    return NO;
+}
+
+- (void)clearVPNInfo {
+    self.serverLabel.text = @"";
+    self.ipAddressLabel.text = @"";
+    self.timeLabel.text = @"";
+    self.mtuLabel.text = @"";
+    self.modeLabel.text = @"";
+    self.dataSentLabel.text = @"";
+    self.dataReceivedLabel.text = @"";
+}
+
+// From local progress.
+- (void)setConnectedTime {
+    NSDate *connectedDate = [ArrayVPNManager sharedInstance].tunnelManager.connection.connectedDate;
+    NSString *timeString = [self formatDate:connectedDate];
+    
+    self.timeLabel.text = timeString;
+}
+
+// MTU is hard-coded, default value is 1400.
+- (void)setMTU {
+    self.mtuLabel.text = [NSString stringWithFormat:@"%d", VPN_PLUGIN_DEFAULT_MTU];
+}
+
+// From VPN extension.
+- (void)refreshVPNStatusWithPeriod:(NSTimeInterval)period {
+    _timer = [NSTimer timerWithTimeInterval:period
+                                     target:self
+                                   selector:@selector(timerHandler)
+                                   userInfo:nil
+                                    repeats:YES];
+    
+    [[NSRunLoop currentRunLoop]addTimer:_timer forMode:NSDefaultRunLoopMode];
+    [_timer fire];
+}
+
+- (void)timerHandler {
+    if (++_tick == REFRESH_VPN_STATUS_PERIOD) {
+        _tick = 0;
+        
+        [self fetchVPNTunnelStatsInfo];
+    }
+    
+    [self setConnectedTime];
+    [self setMTU];
+}
+
+- (void)fetchVPNTunnelStatsInfo {
+    NSError *error = nil;
+    
+    NETunnelProviderManager *manager = [[ArrayVPNManager sharedInstance] tunnelManager];
+    NETunnelProviderSession *session = (NETunnelProviderSession *)manager.connection;
+    
+    NSDictionary *IPCRequestDict = @{(__bridge NSString *)kIPCType:(__bridge NSString *)kIPCStatsRequest};
+    NSData *IPCRequest = [NSJSONSerialization dataWithJSONObject:IPCRequestDict
+                                                         options:NSJSONWritingPrettyPrinted
+                                                           error:nil];
+    
+    __weak typeof(self) weakSelf = self;
+    [session sendProviderMessage:IPCRequest
+                     returnError:&error
+                 responseHandler:^(NSData * _Nullable responseData) {
+                     if (responseData) {
+                         ANDebug(@"IPC response received.");
+                         
+                         NSError *error = nil;
+                         NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:responseData
+                                                                              options:NSJSONReadingMutableContainers
+                                                                                error:&error];
+                         if (!dict) {
+                             ANError(@"Parse IPC response failed with error: %@.", error);
+                             return;
+                         }
+                         NSDictionary *IPCData = [dict objectForKey:(__bridge NSString *)kIPCResponseData];
+                         if (responseData != nil) {
+                             [weakSelf updateDisplayedVPNStatsWithDict:IPCData];
+                         } else {
+                             ANError(@"IPC data is not found in response.");
+                         }
+                     } else {
+                         ANError(@"IPC response is nil.");
+                     }
+                 }];
+    if (error) {
+        ANError(@"Send IPC failed with error: %@.", error.localizedDescription);
+    }
+}
+
+- (void)updateDisplayedVPNStatsWithDict:(NSDictionary *)dict {
+    NSNumber *clientIP = [dict objectForKey:(__bridge NSString *)kIPCStatsClientIP];
+    NSString *serverHost = [dict objectForKey:(__bridge NSString *)kIPCStatsServerHost];
+    NSNumber *sentBytes = [dict objectForKey:(__bridge NSString *)kIPCStatsSentBytes];
+    NSNumber *receivedBytes = [dict objectForKey:(__bridge NSString *)kIPCStatsReceviedBytes];
+    NSNumber *isFullTunnel = [dict objectForKey:(__bridge NSString *)kIPCStatsIsFullTunnel];
+    
+    NSString *sentToShow = [self formatBytes:[sentBytes stringValue]];
+    NSString *recvToShow = [self formatBytes:[receivedBytes stringValue]];
+    
+    self.ipAddressLabel.text = [self formatIP:clientIP];
+    self.serverLabel.text = serverHost;
+    self.modeLabel.text = [isFullTunnel boolValue] ? NSLocalizedString(@"Full Tunnel", nil) : NSLocalizedString(@"Split Tunnel", nil);
+    
+    if (sentToShow) {
+        self.dataSentLabel.text = sentToShow;
+    }
+    if (recvToShow) {
+        self.dataReceivedLabel.text = recvToShow;
+    }
+}
+
+- (void)stopFetchInfo {
+    [_timer invalidate];
+    _timer = nil;
+}
+
+#pragma mark - Helpers
+- (NSString *)formatIP:(NSNumber *)IP {
+    if (!IP) {
+        return @"0.0.0.0";
+    }
+    
+    uint32_t ip = [IP unsignedIntValue];
+    
+    return [NSString stringWithFormat:@"%d.%d.%d.%d", IPSTR(ip)];
+}
+
+- (NSString *)formatBytes:(NSString *)bytes {
+    
+#define K_BYTES     1024
+#define M_BYTES     (1024 * 1024)
+    
+    if (!bytes) {
+        return nil;
+    }
+    
+    uint64_t uBytes = (uint64_t)[bytes integerValue];
+    if (uBytes > M_BYTES) {
+        return [NSString stringWithFormat:@"%.1f MB", (double)uBytes/M_BYTES];
+    } else if (uBytes > K_BYTES) {
+        return [NSString stringWithFormat:@"%.1f KB", (double)uBytes/K_BYTES];
+    }
+    
+    return [NSString stringWithFormat:@"%@ B", bytes];
+}
+
+- (NSString *)formatDate:(NSDate *)date {
+    if (!date) {
+        return NSLocalizedString(@"Unconnected", nil);
+    }
+    
+    NSTimeInterval now = [[NSDate date] timeIntervalSince1970];
+    NSTimeInterval connectedDateInterval = [date timeIntervalSince1970];
+    NSUInteger seconds = (NSUInteger)round(now - connectedDateInterval);
+    NSString *dateString = [NSString stringWithFormat:@"%02zi:%02zi:%02zi",
+                            seconds / 3600, (seconds / 60) % 60, seconds % 60];
+    
+    return [NSString stringWithFormat:@"%@", dateString];
+}
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return kStatusSectionTotal;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    if (section == kStatusSectionConnectionInfo) {
+        return 6;
+    } else if (section == kStatusSectionStatistics) {
+        return 2;
+    } else if (section == kStatusSectionDNS){
+        if (_dnsList.count < 16) {
+            return _dnsList.count + 1;
+        } else {
+            return 16;
+        }
+    }
+    return 0;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell *cell = nil;
+    
+    if (indexPath.section == kStatusSectionDNS) {
+        DNSSettingCell *dnsSettingCell = [tableView dequeueReusableCellWithIdentifier:kDNSSettingCellID];
+        dnsSettingCell.delegate = self;
+        if (!dnsSettingCell) {
+            dnsSettingCell = [[DNSSettingCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kDNSSettingCellID];;
+        }
+        
+        NSInteger row = indexPath.row;
+        if (_dnsList.count < 16) {
+            if (row == 0) {
+                [dnsSettingCell configureCellWithMessage:@"" isAddCell:YES];
+            } else {
+                [dnsSettingCell configureCellWithMessage:[_dnsList objectAtIndex:row - 1] isAddCell:NO];
+            }
+        } else {
+            [dnsSettingCell configureCellWithMessage:[_dnsList objectAtIndex:row] isAddCell:NO];
+        }
+        
+        return dnsSettingCell;
+    } else {
+        cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
+    }
+    return cell;
+}
+
+
+#pragma mark - UITableViewDelegate
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    return 35;
+}
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+#pragma mark - DNSSettingCellDelegate
+- (void)DNSSettingButtonDidClickedWithCell:(UITableViewCell *)cell isAdd:(BOOL)bAdd {
+    DNSSettingCell* dnsCell = (DNSSettingCell *)(cell);
+    NSMutableArray *tmpArray = [NSMutableArray arrayWithArray:_dnsList];
+    NSString *errMessage = @"", *titleMessage = @"";
+    if (bAdd) {
+        NSArray *newDnsArray = [dnsCell.addDnsTextField.text componentsSeparatedByString:@";"];
+        BOOL bValidDNSServer = YES;
+        if ([newDnsArray count] > 0) {
+            for (NSString *signalDNS in newDnsArray) {
+                if (!isValidDNSServer([signalDNS UTF8String])) {
+                    bValidDNSServer = NO;
+                }
+            }
+        } else {
+            bValidDNSServer = NO;
+        }
+        
+        if (bValidDNSServer) {
+            [tmpArray addObjectsFromArray:newDnsArray];
+        } else {
+            errMessage = NSLocalizedString(@"The format of the DNS server is invalid.", nil);
+            titleMessage = NSLocalizedString(@"Error", nil);
+        }
+    } else {
+        [tmpArray removeObject:dnsCell.descText.text];
+        if([tmpArray count] <= 0) {
+            errMessage = NSLocalizedString(@"Make sure at least one DNS server exists in the system.", nil);
+            titleMessage = NSLocalizedString(@"Information", nil);
+        }
+    }
+    
+    if ([errMessage length] > 0) {
+        PopupDialog *popup = [ANPopupDialog singleButtonPopupDialogWithTitle:titleMessage message:errMessage];
+        [self presentViewController:popup animated:YES completion:nil];
+        return;
+    }
+    _dnsList = tmpArray;
+    ANInfo(@"new dns list=%@", _dnsList);
+    [self.tableView reloadData];
+    
+    NSString *dnsListString = [_dnsList componentsJoinedByString:@";"];
+    Gateway *currentGateway = [self getCurrentGateway];
+    currentGateway.customDnsList = dnsListString;
+    ANInfo(@"save current gateway custom dns list=%@", currentGateway.customDnsList);
+    GatewayManager *gatewayManager = [GatewayManager sharedInstance];
+    [gatewayManager updateGateway:currentGateway];
+    self.needReconnect = YES;
+    [self stopVPN];
+}
+
+- (Gateway *)getCurrentGateway {
+    AAAManager *manager = [AAAManager sharedInstance];
+    VPNAccount *account = manager.account;
+    GatewayManager *gm = [GatewayManager sharedInstance];
+    NSString *url = account.vsURL;
+    NSString *port = account.vsPort;
+    if ([url length] <= 0) {
+        NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameStatus];
+        NSString *oauthUrl = [userDefaults valueForKey:KEY_OAUTH_URL];
+        if (oauthUrl.length > 0) {
+            ANInfo(@"getCurrentGateway: Get oauth url[%@].", oauthUrl);
+            NSRange range = [oauthUrl rangeOfString:@"https://"];
+            oauthUrl = [oauthUrl substringFromIndex:range.location + range.length];
+            range = [oauthUrl rangeOfString:@"/prx/000/"];
+            url = [oauthUrl substringToIndex:range.location];
+            ANInfo(@"getCurrentGateway: Get url[%@].", url);
+        }
+    }
+    NSInteger index = [gm indexOfUrl:url andport:port];
+    
+    return [gm gatewayAtIndex:index];
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/StatusViewController.m.MotionProEnterprise
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/StatusViewController.m.MotionProEnterprise	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/StatusViewController.m.MotionProEnterprise	(working copy)
@@ -0,0 +1,509 @@
+//
+//  StatusViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/27.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+#include <arpa/inet.h>
+#import "ANLogger.h"
+#import "arrayapi.h"
+#import "vpnplugin.h"
+#import "ArrayVPNManager.h"
+#import "ArrayVPNWrapper.h"
+#import "ANPopupDialog.h"
+#import "AAAManager.h"
+#import "GatewayManager.h"
+#import "StatusViewController.h"
+#import "DNSSettingCell.h"
+#import "UIViewController+HideKeyboard.h"
+
+BOOL isValidDNSServer(const char *dnsServer);
+
+BOOL isValidDNSServer(const char *dnsServer)
+{
+    if (!dnsServer) {
+        return NO;
+    }
+    
+    struct sockaddr_in sa;
+    int result = inet_pton(AF_INET, dnsServer, &(sa.sin_addr));
+    return result != 0;
+}
+
+#define SECTIONS_IN_STATUS_VIEW             2
+#define ROWS_IN_SECTION_CONNECTION_INFO     6
+#define ROWS_IN_SECIONT_STATISTICS          2
+
+typedef NS_ENUM(NSInteger, StatusSectionIndex) {
+    kStatusSectionConnectionInfo = 0,
+    kStatusSectionDNS,
+    kStatusSectionStatistics,
+    kStatusSectionTotal
+};
+
+#define TIMER_PERIOD                1
+#define REFRESH_VPN_STATUS_PERIOD   3
+
+#if TARGET_OS_IPHONE
+NSString * const kAppGroupNameStatus = @"group.net.arraynetworks.groupenterprise";
+#elif TARGET_OS_MAC
+NSString * const kAppGroupNameStatus = @"5VZLZ3YQ9P.net.arraynetworks.MacTunnel";
+#endif
+
+@interface StatusViewController () <DNSSettingCellDelegate> {
+    NSTimer *_timer;
+    NSInteger _tick;
+}
+
+@property (weak, nonatomic) IBOutlet UILabel *stateLabel;
+@property (weak, nonatomic) IBOutlet UILabel *serverLabel;
+@property (weak, nonatomic) IBOutlet UILabel *ipAddressLabel;
+@property (weak, nonatomic) IBOutlet UILabel *timeLabel;
+@property (weak, nonatomic) IBOutlet UILabel *mtuLabel;
+@property (weak, nonatomic) IBOutlet UILabel *modeLabel;
+@property (weak, nonatomic) IBOutlet UILabel *dataSentLabel;
+@property (weak, nonatomic) IBOutlet UILabel *dataReceivedLabel;
+@property (strong, nonatomic) NSMutableArray *dnsList;
+@property (nonatomic) BOOL needReconnect;
+
+@end
+
+@implementation StatusViewController
+
+- (void)dealloc {
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    [self enableHideKeyboard];
+    
+    [self.tableView registerNib:[UINib nibWithNibName:@"DNSSettingCell" bundle:nil] forCellReuseIdentifier:kDNSSettingCellID];
+    self.needReconnect = NO;
+    
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameStatus];
+    NSMutableArray *newDNSList = [userDefaults valueForKey:@"dns_list"];
+    ANInfo(@"viewDidLoad:get new dns list[%@]", newDNSList);
+    if (newDNSList.count > 0) {
+        [userDefaults removeObjectForKey:@"dns_list"];
+        _dnsList = newDNSList;
+        ANInfo(@"viewDidLoad:get dns list= %@", _dnsList);
+    }
+    
+    if (![self clearVPNInfoIfNotConnected]) {
+        [self fetchVPNTunnelStatsInfo];
+    }
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(handleVPNStatus:)
+                                                 name:kArrayVPNStatusNotification
+                                               object:nil];
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [self setVPNStatus];
+    if (![self clearVPNInfoIfNotConnected]) {
+        [self setMTU];
+        [self refreshVPNStatusWithPeriod:TIMER_PERIOD];
+    }
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [self stopFetchInfo];
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+#pragma mark - All Status Information
+- (void)setVPNStatus {
+    NSString *statusString = @"";
+    ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+    
+    switch (tunnelStatus) {
+        case ArrayVPNInavlid:
+        case ArrayVPNDisconnecting:
+        case ArrayVPNDisconnected:
+            statusString = NSLocalizedString(@"Disconnected", nil);
+            break;
+        case ArrayVPNConnecting:
+        case ArrayVPNReasserting:
+            statusString = NSLocalizedString(@"Connecting...", nil);
+            break;
+        case ArrayVPNConnected:
+            statusString = NSLocalizedString(@"Connected", nil);
+            break;
+        default:
+            ANError(@"Invalid VPN tunnel status \(%zi).", tunnelStatus);
+            break;
+    }
+    
+    self.stateLabel.text = statusString;
+}
+
+// VPN Status Handler
+- (void)handleVPNStatus:(NSNotification *)notification {
+    ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+    
+    ANInfo(@"Array VPN tunnel status = %zi", tunnelStatus);
+    
+    if (tunnelStatus != ArrayVPNConnected) {
+        [self clearVPNInfo];
+        [self stopFetchInfo];
+        if (self.needReconnect && tunnelStatus == ArrayVPNDisconnected) {
+            ANInfo(@"custom dns server config, now need restart vpn.");
+            self.needReconnect = NO;
+            [self startVPN:NO];
+        }
+    } else {
+        if (_timer == nil) {
+            [self refreshVPNStatusWithPeriod:TIMER_PERIOD];
+        }
+        ANInfo(@"Array VPN tunnel status is connected");
+        if (tunnelStatus == ArrayVPNConnected) {
+            NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameStatus];
+            for (int i = 0; i < 3; i++) {
+                NSMutableArray *newDNSList = [userDefaults valueForKey:@"dns_list"];
+                ANInfo(@"get new dns list[%@], i =%d", newDNSList, i);
+                if (newDNSList.count > 0) {
+                    //[userDefaults removeObjectForKey:@"dns_list"];
+                    _dnsList = newDNSList;
+                    ANInfo(@"status connected:get dns list= %@", _dnsList);
+                    [self.tableView reloadData];
+                    break;
+                } else {
+                    sleep(1);
+                }
+            }
+        }
+    }
+}
+
+- (BOOL)startVPN:(BOOL)isAutoStart {
+    //Gateway *gateway = [self getCurrentGateway];
+    //NSString *session = [AAAManager sharedInstance].sessionID;
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    
+#if TARGET_OS_IPHONE
+    //Reset connect fail reason.
+    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameStatus];
+    [userDefaults removeObjectForKey:@"tunnel_result"];
+    [userDefaults removeObjectForKey:@"dns_list"];
+#endif
+    
+    [vpnWrapper startSSLVPN];
+    
+    return YES;
+}
+
+- (void)stopVPN {
+    ArrayVPNWrapper *vpnWrapper = [ArrayVPNWrapper sharedInstance];
+    [vpnWrapper stopSSLVPN];
+}
+
+// Clear all statistics information if vpn is not connected.
+- (BOOL)clearVPNInfoIfNotConnected {
+    ArrayVPNStatus tunnelStatus = [ArrayVPNManager sharedInstance].vpnStatus;
+    if (tunnelStatus != ArrayVPNConnected) {
+        [self clearVPNInfo];
+        
+        return YES;
+    }
+    
+    return NO;
+}
+
+- (void)clearVPNInfo {
+    self.serverLabel.text = @"";
+    self.ipAddressLabel.text = @"";
+    self.timeLabel.text = @"";
+    self.mtuLabel.text = @"";
+    self.modeLabel.text = @"";
+    self.dataSentLabel.text = @"";
+    self.dataReceivedLabel.text = @"";
+}
+
+// From local progress.
+- (void)setConnectedTime {
+    NSDate *connectedDate = [ArrayVPNManager sharedInstance].tunnelManager.connection.connectedDate;
+    NSString *timeString = [self formatDate:connectedDate];
+    
+    self.timeLabel.text = timeString;
+}
+
+// MTU is hard-coded, default value is 1400.
+- (void)setMTU {
+    self.mtuLabel.text = [NSString stringWithFormat:@"%d", VPN_PLUGIN_DEFAULT_MTU];
+}
+
+// From VPN extension.
+- (void)refreshVPNStatusWithPeriod:(NSTimeInterval)period {
+    _timer = [NSTimer timerWithTimeInterval:period
+                                     target:self
+                                   selector:@selector(timerHandler)
+                                   userInfo:nil
+                                    repeats:YES];
+    
+    [[NSRunLoop currentRunLoop]addTimer:_timer forMode:NSDefaultRunLoopMode];
+    [_timer fire];
+}
+
+- (void)timerHandler {
+    if (++_tick == REFRESH_VPN_STATUS_PERIOD) {
+        _tick = 0;
+        
+        [self fetchVPNTunnelStatsInfo];
+    }
+    
+    [self setConnectedTime];
+    [self setMTU];
+}
+
+- (void)fetchVPNTunnelStatsInfo {
+    NSError *error = nil;
+    
+    NETunnelProviderManager *manager = [[ArrayVPNManager sharedInstance] tunnelManager];
+    NETunnelProviderSession *session = (NETunnelProviderSession *)manager.connection;
+    
+    NSDictionary *IPCRequestDict = @{(__bridge NSString *)kIPCType:(__bridge NSString *)kIPCStatsRequest};
+    NSData *IPCRequest = [NSJSONSerialization dataWithJSONObject:IPCRequestDict
+                                                         options:NSJSONWritingPrettyPrinted
+                                                           error:nil];
+    
+    __weak typeof(self) weakSelf = self;
+    [session sendProviderMessage:IPCRequest
+                     returnError:&error
+                 responseHandler:^(NSData * _Nullable responseData) {
+                     if (responseData) {
+                         ANDebug(@"IPC response received.");
+                         
+                         NSError *error = nil;
+                         NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:responseData
+                                                                              options:NSJSONReadingMutableContainers
+                                                                                error:&error];
+                         if (!dict) {
+                             ANError(@"Parse IPC response failed with error: %@.", error);
+                             return;
+                         }
+                         NSDictionary *IPCData = [dict objectForKey:(__bridge NSString *)kIPCResponseData];
+                         if (responseData != nil) {
+                             [weakSelf updateDisplayedVPNStatsWithDict:IPCData];
+                         } else {
+                             ANError(@"IPC data is not found in response.");
+                         }
+                     } else {
+                         ANError(@"IPC response is nil.");
+                     }
+                 }];
+    if (error) {
+        ANError(@"Send IPC failed with error: %@.", error.localizedDescription);
+    }
+}
+
+- (void)updateDisplayedVPNStatsWithDict:(NSDictionary *)dict {
+    NSNumber *clientIP = [dict objectForKey:(__bridge NSString *)kIPCStatsClientIP];
+    NSString *serverHost = [dict objectForKey:(__bridge NSString *)kIPCStatsServerHost];
+    NSNumber *sentBytes = [dict objectForKey:(__bridge NSString *)kIPCStatsSentBytes];
+    NSNumber *receivedBytes = [dict objectForKey:(__bridge NSString *)kIPCStatsReceviedBytes];
+    NSNumber *isFullTunnel = [dict objectForKey:(__bridge NSString *)kIPCStatsIsFullTunnel];
+    
+    NSString *sentToShow = [self formatBytes:[sentBytes stringValue]];
+    NSString *recvToShow = [self formatBytes:[receivedBytes stringValue]];
+    
+    self.ipAddressLabel.text = [self formatIP:clientIP];
+    self.serverLabel.text = serverHost;
+    self.modeLabel.text = [isFullTunnel boolValue] ? NSLocalizedString(@"Full Tunnel", nil) : NSLocalizedString(@"Split Tunnel", nil);
+    
+    if (sentToShow) {
+        self.dataSentLabel.text = sentToShow;
+    }
+    if (recvToShow) {
+        self.dataReceivedLabel.text = recvToShow;
+    }
+}
+
+- (void)stopFetchInfo {
+    [_timer invalidate];
+    _timer = nil;
+}
+
+#pragma mark - Helpers
+- (NSString *)formatIP:(NSNumber *)IP {
+    if (!IP) {
+        return @"0.0.0.0";
+    }
+    
+    uint32_t ip = [IP unsignedIntValue];
+    
+    return [NSString stringWithFormat:@"%d.%d.%d.%d", IPSTR(ip)];
+}
+
+- (NSString *)formatBytes:(NSString *)bytes {
+    
+#define K_BYTES     1024
+#define M_BYTES     (1024 * 1024)
+    
+    if (!bytes) {
+        return nil;
+    }
+    
+    uint64_t uBytes = (uint64_t)[bytes integerValue];
+    if (uBytes > M_BYTES) {
+        return [NSString stringWithFormat:@"%.1f MB", (double)uBytes/M_BYTES];
+    } else if (uBytes > K_BYTES) {
+        return [NSString stringWithFormat:@"%.1f KB", (double)uBytes/K_BYTES];
+    }
+    
+    return [NSString stringWithFormat:@"%@ B", bytes];
+}
+
+- (NSString *)formatDate:(NSDate *)date {
+    if (!date) {
+        return NSLocalizedString(@"Unconnected", nil);
+    }
+    
+    NSTimeInterval now = [[NSDate date] timeIntervalSince1970];
+    NSTimeInterval connectedDateInterval = [date timeIntervalSince1970];
+    NSUInteger seconds = (NSUInteger)round(now - connectedDateInterval);
+    NSString *dateString = [NSString stringWithFormat:@"%02zi:%02zi:%02zi",
+                            seconds / 3600, (seconds / 60) % 60, seconds % 60];
+    
+    return [NSString stringWithFormat:@"%@", dateString];
+}
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return kStatusSectionTotal;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    if (section == kStatusSectionConnectionInfo) {
+        return 6;
+    } else if (section == kStatusSectionStatistics) {
+        return 2;
+    } else if (section == kStatusSectionDNS){
+        if (_dnsList.count < 16) {
+            return _dnsList.count + 1;
+        } else {
+            return 16;
+        }
+    }
+    return 0;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell *cell = nil;
+    
+    if (indexPath.section == kStatusSectionDNS) {
+        DNSSettingCell *dnsSettingCell = [tableView dequeueReusableCellWithIdentifier:kDNSSettingCellID];
+        dnsSettingCell.delegate = self;
+        if (!dnsSettingCell) {
+            dnsSettingCell = [[DNSSettingCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kDNSSettingCellID];;
+        }
+        
+        NSInteger row = indexPath.row;
+        if (_dnsList.count < 16) {
+            if (row == 0) {
+                [dnsSettingCell configureCellWithMessage:@"" isAddCell:YES];
+            } else {
+                [dnsSettingCell configureCellWithMessage:[_dnsList objectAtIndex:row - 1] isAddCell:NO];
+            }
+        } else {
+            [dnsSettingCell configureCellWithMessage:[_dnsList objectAtIndex:row] isAddCell:NO];
+        }
+        
+        return dnsSettingCell;
+    } else {
+        cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
+    }
+    return cell;
+}
+
+
+#pragma mark - UITableViewDelegate
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    return 35;
+}
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+#pragma mark - DNSSettingCellDelegate
+- (void)DNSSettingButtonDidClickedWithCell:(UITableViewCell *)cell isAdd:(BOOL)bAdd {
+    DNSSettingCell* dnsCell = (DNSSettingCell *)(cell);
+    NSMutableArray *tmpArray = [NSMutableArray arrayWithArray:_dnsList];
+    NSString *errMessage = @"", *titleMessage = @"";
+    if (bAdd) {
+        NSArray *newDnsArray = [dnsCell.addDnsTextField.text componentsSeparatedByString:@";"];
+        BOOL bValidDNSServer = YES;
+        if ([newDnsArray count] > 0) {
+            for (NSString *signalDNS in newDnsArray) {
+                if (!isValidDNSServer([signalDNS UTF8String])) {
+                    bValidDNSServer = NO;
+                }
+            }
+        } else {
+            bValidDNSServer = NO;
+        }
+        
+        if (bValidDNSServer) {
+            [tmpArray addObjectsFromArray:newDnsArray];
+        } else {
+            errMessage = NSLocalizedString(@"The format of the DNS server is invalid.", nil);
+            titleMessage = NSLocalizedString(@"Error", nil);
+        }
+    } else {
+        [tmpArray removeObject:dnsCell.descText.text];
+        if([tmpArray count] <= 0) {
+            errMessage = NSLocalizedString(@"Make sure at least one DNS server exists in the system.", nil);
+            titleMessage = NSLocalizedString(@"Information", nil);
+        }
+    }
+    
+    if ([errMessage length] > 0) {
+        PopupDialog *popup = [ANPopupDialog singleButtonPopupDialogWithTitle:titleMessage message:errMessage];
+        [self presentViewController:popup animated:YES completion:nil];
+        return;
+    }
+    _dnsList = tmpArray;
+    ANInfo(@"new dns list=%@", _dnsList);
+    [self.tableView reloadData];
+    
+    NSString *dnsListString = [_dnsList componentsJoinedByString:@";"];
+    Gateway *currentGateway = [self getCurrentGateway];
+    currentGateway.customDnsList = dnsListString;
+    ANInfo(@"save current gateway custom dns list=%@", currentGateway.customDnsList);
+    GatewayManager *gatewayManager = [GatewayManager sharedInstance];
+    [gatewayManager updateGateway:currentGateway];
+    self.needReconnect = YES;
+    [self stopVPN];
+}
+
+- (Gateway *)getCurrentGateway {
+    AAAManager *manager = [AAAManager sharedInstance];
+    VPNAccount *account = manager.account;
+    GatewayManager *gm = [GatewayManager sharedInstance];
+    NSString *url = account.vsURL;
+    NSString *port = account.vsPort;
+    if ([url length] <= 0) {
+        NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:kAppGroupNameStatus];
+        NSString *oauthUrl = [userDefaults valueForKey:KEY_OAUTH_URL];
+        if (oauthUrl.length > 0) {
+            ANInfo(@"getCurrentGateway: Get oauth url[%@].", oauthUrl);
+            NSRange range = [oauthUrl rangeOfString:@"https://"];
+            oauthUrl = [oauthUrl substringFromIndex:range.location + range.length];
+            range = [oauthUrl rangeOfString:@"/prx/000/"];
+            url = [oauthUrl substringToIndex:range.location];
+            ANInfo(@"getCurrentGateway: Get url[%@].", url);
+        }
+    }
+    NSInteger index = [gm indexOfUrl:url andport:port];
+    
+    return [gm gatewayAtIndex:index];
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SubResourceViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SubResourceViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SubResourceViewController.h	(working copy)
@@ -0,0 +1,15 @@
+//
+//  SubResourceViewController.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/4.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface SubResourceViewController : UITableViewController
+
+- (void)setupModel:(NSArray *)model;
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SubResourceViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SubResourceViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SubResourceViewController.m	(working copy)
@@ -0,0 +1,367 @@
+//
+//  SubResourceViewController.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/8/4.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "Global.h"
+#import "ResourceCell.h"
+#import "NativeAppCell.h"
+#import "ResourceItem.h"
+#import "AppManager.h"
+#import "GCustomItem.h"
+#import "PubAppItem.h"
+#import "ANPopupDialog.h"
+#import "FBKVOController.h"
+#import "ANLogger.h"
+#import "ZTWKWebViewController.h"
+#import "SubResourceViewController.h"
+
+static NSString * const kSubResourceStoryBoardID = @"SubResourceViewControllerID";
+
+@interface SubResourceViewController () {
+    NSInteger _longPressedIndex;
+}
+
+@property (nonatomic, strong) NSArray *model;
+@property (nonatomic, strong) id browser;
+
+// For DesktopDirect
+@property (nonatomic, strong) NSIndexPath *currentIndex;
+@property (nonatomic, strong) ResourceItem *currentItem;
+@property (nonatomic, strong) FBKVOController *kvoController;
+@property (nonatomic, strong) UIControl *darkView;
+@property (nonatomic) BOOL silence;
+
+@end
+
+@implementation SubResourceViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    
+    [self registerCells];
+    
+    [self initKVOController];
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (void)setupModel:(NSArray *)model {
+    self.model = model;
+}
+
+- (void)registerCells {
+    [self.tableView registerNib:[UINib nibWithNibName:@"ResourceCell" bundle:nil] forCellReuseIdentifier:kResourceCellID];
+    [self.tableView registerNib:[UINib nibWithNibName:@"NativeAppCell" bundle:nil] forCellReuseIdentifier:kNativeAppCellID];
+}
+
+- (void)initKVOController {
+    self.kvoController = [FBKVOController controllerWithObserver:self];
+}
+
+- (UITableViewCell *)configureWebAppWithRow:(NSInteger)row {
+    ResourceCell *cell = [self.tableView dequeueReusableCellWithIdentifier:kResourceCellID];
+    if (!cell) {
+        cell = [[ResourceCell alloc] init];
+    }
+    
+    WebApp *app = [self.model objectAtIndex:row];
+    UIImage *image = nil;
+    BOOL isFolder = app.type == APP_TYPE_FOLDER;
+    if (isFolder) {
+        image = [UIImage imageNamed:FOLDER_APP_IMAGE_NAME];
+    } else {
+        image = [UIImage imageNamed:WEB_APP_IMAGE_NAME];
+        UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self
+                                                                                                       action:@selector(cellLongPressed:)];
+        [cell addGestureRecognizer:longPressGesture];
+    }
+    [cell configureCellWithImage:image name:app.name isFolder:isFolder];
+    
+    return cell;
+}
+
+- (UITableViewCell *)configureNativeAppWithRow:(NSInteger)row {
+    NativeAppCell *cell = [self.tableView dequeueReusableCellWithIdentifier:kNativeAppCellID];
+    if (!cell) {
+        cell = [[NativeAppCell alloc] init];
+    }
+    
+    NativeApp *app = [self.model objectAtIndex:row];
+    UIImage *image = nil;
+    if (app.customIcon) {
+        image = app.customIcon;
+    } else if (app.appIcon) {
+        image = app.appIcon;
+    } else {
+        image = [UIImage imageNamed:NATIVE_APP_IMAGE_NAME];
+    }
+    [cell configureCellWithImage:image name:app.name isFolder:NO];
+    [cell setDescriptionContent:app.desc];
+    
+    return cell;
+}
+
+- (UITableViewCell *)configureDesktopAppWithRow:(NSInteger)row {
+    ResourceCell *cell = [self.tableView dequeueReusableCellWithIdentifier:kResourceCellID];
+    if (!cell) {
+        cell = [[ResourceCell alloc] init];
+    }
+    
+    FolderItem *item = [self.model objectAtIndex:row];
+    BOOL isFolder = [item isKindOfClass:[FolderItem class]];  // Only pub-app & self-defined desktop has folder.
+    BOOL isCustomDesktop = [item isKindOfClass:[GCustomItem class]];
+    if (isCustomDesktop) {
+        isFolder = YES;
+    }
+    UIImage *image = nil;
+    if (item.icon != nil) {
+        image = item.icon;
+    } else {
+        image = (isFolder && !isCustomDesktop) ? [UIImage imageNamed:FOLDER_APP_IMAGE_NAME] : [UIImage imageNamed:DESKTOP_IMAGE_NAME];
+    }
+    [cell configureCellWithImage:image name:item.name isFolder:isFolder];
+    
+    return cell;
+}
+
+#pragma mark - Long press handler for WebApp
+- (void)cellLongPressed:(UIGestureRecognizer *)recognizer {
+    if (recognizer.state == UIGestureRecognizerStateBegan) {
+        CGPoint location = [recognizer locationInView:self.tableView];
+        NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
+        _longPressedIndex = indexPath.row;
+        ResourceCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
+        
+        [self showMenuWithCell:cell];
+    }
+}
+
+- (void)showMenuWithCell:(ResourceCell *)cell {
+    [cell becomeFirstResponder];
+    
+    UIMenuController *controller = [UIMenuController sharedMenuController];
+    UIMenuItem *openItem = [[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Open in Safari", nil) action:@selector(openWebPage:)];
+    [controller setMenuItems:[NSArray arrayWithObjects:openItem, nil]];
+    [controller setTargetRect:cell.contentView.frame inView:cell.contentView];
+    [controller setMenuVisible:YES animated:YES];
+}
+
+- (void)openWebPage:(id)sender {
+    if (_longPressedIndex >= self.model.count) {
+        ANError(@"Index (%zi) is out range of web apps count.", _longPressedIndex);
+        return;
+    }
+    
+    WebApp *app = [self.model objectAtIndex:_longPressedIndex];
+    if (app.type == APP_TYPE_WEBAPP) {
+        [[UIApplication sharedApplication] openURL:app.url];
+    }
+}
+
+#pragma mark - UITableViewDataSource
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return 1;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return self.model.count;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell *cell = nil;
+    NSInteger row = indexPath.row;
+    id app = [self.model objectAtIndex:row];
+    if ([app isKindOfClass:[ResourceApp class]]) {
+        APP_TYPE type = ((ResourceApp *)app).type;
+        if (type == APP_TYPE_WEBAPP || type == APP_TYPE_FOLDER) {
+            cell = [self configureWebAppWithRow:row];
+        } else if (type == APP_TYPE_NATIVEAPP || type == APP_TYPE_NATIVE_SDK) {
+            cell = [self configureNativeAppWithRow:row];
+        }
+    } else if ([app isKindOfClass:[ResourceItem class]]) {
+        cell = [self configureDesktopAppWithRow:row];
+    }
+    
+    return cell;
+}
+
+#pragma mark - UITableViewDelegate
+- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    return 15;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
+    return CGFLOAT_MIN;
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    [tableView deselectRowAtIndexPath:indexPath animated:YES];
+    
+    NSInteger row = indexPath.row;
+    id app = [self.model objectAtIndex:row];
+    if ([app isKindOfClass:[FolderApp class]]) {
+        APP_TYPE type = ((ResourceApp *)app).type;
+        if (type == APP_TYPE_WEBAPP) {
+            WebApp *webApp = (WebApp *)app;
+            NSString *urlString = [webApp.url absoluteString];
+            [self openWebPageInSecBrowserWithURLString:urlString];
+        } else if (type == APP_TYPE_FOLDER) {
+            NSArray *subModel = ((WebApp *)app).children;
+            [self showResourceInSubViewControllerWithModel:subModel];
+        } else if (type == APP_TYPE_NATIVEAPP || type == APP_TYPE_NATIVE_SDK) {
+            NativeApp *nativeApp = (NativeApp *)app;
+            [self openNativeAppWithScheme:nativeApp.scheme];
+        }
+    } else if ([app isKindOfClass:[GCustomItem class]]) {
+        // TODO: open!
+    } else if ([app isKindOfClass:[PubAppItem class]]) {
+        FolderItem *item = [self.model objectAtIndex:row];
+        [self didSelectHostItem:(HostItem *)item atIndexPath:indexPath];
+    }
+}
+
+#pragma mark - DesktopDirect
+- (void)didSelectHostItem:(HostItem *)hostItem atIndexPath:(NSIndexPath *)indexPath {
+    if (self.currentIndex
+        && self.currentIndex.row == indexPath.row
+        && hostItem.status < ResourceStatusReady) {
+        return;
+    }
+    
+    self.currentIndex = indexPath;
+    self.currentItem = hostItem;
+    
+    ResourceCell *cell = (ResourceCell *)[self.tableView cellForRowAtIndexPath:indexPath];
+    
+    __weak typeof(self) weakSelf = self;
+    [self.kvoController observe:hostItem
+                        keyPath:@"status"
+                        options:NSKeyValueObservingOptionNew
+                          block:^(SubResourceViewController *observer, HostItem *host, NSDictionary *change) {
+                              NSInteger hostStatus = host.status;
+                              dispatch_async(dispatch_get_main_queue(), ^{
+                                  [cell updateUI:host];
+                                  if (observer.currentIndex.row != indexPath.row) {
+                                      return;
+                                  }
+                                  
+                                  if (observer.silence) {
+                                      return;
+                                  }
+                                  if (host.status == ResourceStatusReady) {
+                                      [observer.kvoController unobserve:host];
+                                      NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
+                                      AppManager *appManager = [AppManager sharedInstance];
+                                      BOOL cliEnabledNEC = NO;
+                                      NSString *enabledNEC = appManager.desktopSettings.settings[@"jp-rdp"];
+                                      if (enabledNEC && [enabledNEC isEqualToString:@"1"])
+                                          cliEnabledNEC = YES;
+                                      if (cliEnabledNEC || [userDefaults integerForKey:@"desktop_client_vendor"] == 1) {
+                                          [observer openRDClientNEC:host];
+                                      } else {
+                                          [observer openRDClient:host];
+                                      }
+                                      // Reset power state
+                                      host.powerState = HostPowerStateDown;
+                                      return;
+                                  } else if (hostStatus >= ResourceStatusFailed && hostStatus < ResourceStatusResolveHostNameFailed) {
+                                      ANError(@"Cannot connect to remote host, error code: %zi", hostStatus);
+                                      
+                                      if (hostStatus == ResourceStatusPowerDown) {
+                                          NSString *message = NSLocalizedString(@"It seems the remote host is turned off. Would you like to try and wake it up?", nil);
+                                          
+                                          PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Cannot connect to remote host", nil)
+                                                                                                         message:message
+                                                                                                   confirmAction:^{
+                                                                                                       HostItem *host = [weakSelf.model objectAtIndex:weakSelf.currentIndex.row];
+                                                                                                       [host wakeUp];
+                                                                                                   }
+                                                                                                    cancelAction:nil];
+                                          
+                                          [weakSelf presentViewController:dialog animated:YES completion:nil];
+                                          
+                                          return;
+                                      } else {
+                                          [observer.kvoController unobserve:host];
+                                      }
+                                  }
+                              });
+                          }];
+    
+    [hostItem prepare];
+}
+
+- (void)openRDClient:(HostItem *)hostItem {
+    NSURL *url = hostItem.url;
+    if (!url) {
+        return;
+    }
+    
+    if (![[UIApplication sharedApplication] canOpenURL:url]) {
+        NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Application %@ has not been installed, Would you like to search it on App Store?", nil), @"RD Client"];
+        PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Cannot connect to remote host", nil)
+                                                                       message:message
+                                                                 confirmAction:^{
+                                                                     NSString *string = [NSString stringWithFormat:APPSTORE_SEARCH_STRING,
+                                                                                         [@"RD Client" stringByAddingPercentEncodingWithAllowedCharacters:
+                                                                                          NSCharacterSet.URLQueryAllowedCharacterSet]];
+                                                                     
+                                                                     OpenURL([NSURL URLWithString:string]);
+                                                                 }
+                                                                  cancelAction:nil];
+        
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+- (void)openRDClientNEC:(HostItem *)hostItem {
+    NSURL *url = hostItem.urlVendorNEC;
+    if (!url) {
+        return;
+    }
+    
+    if (![[UIApplication sharedApplication] canOpenURL:url]) {
+        NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Application %@ has not been installed, Would you like to search it on App Store?", nil),@"RD"];
+        PopupDialog *dialog = [ANPopupDialog doubleButtonsPopupDialogWithTitle:NSLocalizedString(@"Cannot connect to remote host", nil)
+                                                                       message:message
+                                                                 confirmAction:^{
+                                                                     NSString *string = @"https://itunes.apple.com/jp/app/rd-v1.3/id771611106?mt=8";
+                                                                     OpenURL([NSURL URLWithString:string]);
+                                                                 }
+                                                                  cancelAction:nil];
+        
+        [self presentViewController:dialog animated:YES completion:nil];
+    }
+}
+
+- (void)openWebPageInSecBrowserWithURLString:(NSString *)urlString {
+    ZTWKWebViewController *control = [[ZTWKWebViewController alloc] init];
+   control.webUrl = urlString;
+   [self.navigationController pushViewController:control animated:YES];
+}
+
+- (void)openNativeAppWithScheme:(NSString *)scheme {
+    NSURL *url = [NSURL URLWithString:scheme];
+    if (url.scheme == nil) {
+        url = [NSURL URLWithString:[NSString stringWithFormat:@"%@://", scheme]];
+    }
+    
+    OpenURL(url);
+}
+
+- (void)showResourceInSubViewControllerWithModel:(NSArray *)model {
+    UIStoryboard *mainBoard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
+    SubResourceViewController *viewController = [mainBoard instantiateViewControllerWithIdentifier:kSubResourceStoryBoardID];
+    [viewController setModel:model];
+    
+    [self.navigationController pushViewController:viewController animated:YES];
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SyferLockLoginViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SyferLockLoginViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SyferLockLoginViewController.h	(working copy)
@@ -0,0 +1,23 @@
+//
+//  SyferLockLoginViewController.h
+//  MobileNow
+//
+//  Created by wangxy on 16/5/3.
+//  Copyright © 2016年 ArrayNetworks. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+#define TOTAL_ITEMS_IN_COLLECTION_VIEW  12
+#define TOTAL_NUMBERS_ON_EACH_MATRIX_ITEM   9
+
+@interface SyferLockLoginViewController : UIViewController
+
+@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
+@property (weak, nonatomic) IBOutlet UITextField *passwordTextField;
+@property (weak, nonatomic) IBOutlet UILabel *gridPINLabel;
+@property (weak, nonatomic) IBOutlet UIButton *loginButton;
+@property (weak, nonatomic) IBOutlet UIBarButtonItem *cancelBarButton;
+@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *loginActivity;
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SyferLockLoginViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SyferLockLoginViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/SyferLockLoginViewController.m	(working copy)
@@ -0,0 +1,157 @@
+//
+//  SyferLockLoginViewController.m
+//  MobileNow
+//
+//  Created by wangxy on 16/5/3.
+//  Copyright © 2016年 ArrayNetworks. All rights reserved.
+//
+
+#import "Global.h"
+#import "AAAManager.h"
+#import "SyferLockLoginViewController.h"
+#import "SyferLockLoginCollectionViewCell.h"
+
+#define isPad   (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
+
+@interface SyferLockLoginViewController () <UICollectionViewDataSource, UICollectionViewDelegate, UITextFieldDelegate>
+
+@property (strong, nonatomic) UITapGestureRecognizer *tapGesture;
+
+@end
+
+@implementation SyferLockLoginViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    [self setAutomaticallyAdjustsScrollViewInsets:NO];
+    _collectionView.backgroundColor = [UIColor whiteColor];
+    _collectionView.dataSource = self;
+    _collectionView.delegate = self;
+    [SyferLockLoginCollectionViewCell registerCellForCollectionView:self.collectionView];
+    _passwordTextField.delegate = self;
+    [self configLocalizationStrings];
+    [self configLoginButton];
+    [self addTapGestureOnCollectionView];
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (IBAction)loginButtonTapped:(id)sender {
+    AAAManager *manager = [AAAManager sharedInstance];
+    VPNAccount *syferLockAccount = [[VPNAccount alloc] init];
+    syferLockAccount = [manager.account copy];
+    syferLockAccount.passWord = [_passwordTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
+    [manager continueVPNThreadWithSyferLockAccount:syferLockAccount];
+    
+    [self waitForLoginFinished];
+}
+
+- (IBAction)cancelButtonTapped:(id)sender {
+    [[AAAManager sharedInstance] cancelLoginTapped];
+}
+
+- (NSString *)syferLockSubStringWithIndex:(NSInteger)index {
+    NSString *allSyferLockNumbers = [AAAManager sharedInstance].syferLockInfo;
+    if (allSyferLockNumbers != nil) {
+        NSInteger rangeLength = TOTAL_NUMBERS_ON_EACH_MATRIX_ITEM;
+        return [allSyferLockNumbers substringWithRange:NSMakeRange(index * rangeLength, rangeLength)];
+    }
+    return nil;
+}
+
+- (void)configLocalizationStrings {
+    self.navigationItem.title = NSLocalizedString(@"GridGuard Login", nil);
+    self.cancelBarButton.title = NSLocalizedString(@"Cancel", nil);
+    self.gridPINLabel.text = NSLocalizedString(@"Enter GridPIN", nil);
+    [self.loginButton setTitle:NSLocalizedString(@"Login", nil)
+                      forState:UIControlStateNormal];
+}
+
+- (void)configLoginButton {
+    _loginButton.layer.shadowOffset = CGSizeMake(5.0, 5.0);
+    _loginButton.layer.shadowColor = MAIN_COLOR.CGColor;
+    _loginButton.layer.shadowOpacity = 0.25;
+    _loginButton.layer.cornerRadius = 2.5;
+    _loginButton.layer.masksToBounds = YES;
+    [_loginButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
+}
+
+- (void)waitForLoginFinished {
+    [self hideLoginButton];
+    [self showActivityIndicator];
+}
+
+- (void)showActivityIndicator {
+    [_loginActivity startAnimating];
+}
+
+- (void)hideLoginButton {
+    [_loginButton setHidden:YES];
+}
+
+- (void)addTapGestureOnCollectionView {
+    if (_tapGesture == nil) {
+        _tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self
+                                                              action:@selector(dismissKeyBoard:)];
+        
+    }
+    [self.collectionView addGestureRecognizer:_tapGesture];
+}
+
+- (IBAction)dismissKeyBoard:(UITapGestureRecognizer *)sender
+{
+    [self.passwordTextField resignFirstResponder];
+}
+
+#pragma mark - UITextFieldDelegate
+- (BOOL)textFieldShouldReturn:(UITextField *)textField {
+    if ([_passwordTextField isFirstResponder]) {
+        [_passwordTextField resignFirstResponder];
+    }
+    return YES;
+}
+
+#pragma mark - UICollectionViewDataSource
+- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
+    return TOTAL_ITEMS_IN_COLLECTION_VIEW;
+}
+
+- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
+    SyferLockLoginCollectionViewCell *cell = [[self collectionView] dequeueReusableCellWithReuseIdentifier:(NSString *)syferLockLoginReusableIdentifier
+                                                                                              forIndexPath:indexPath];
+    if (cell != nil) {
+        NSString *numbersOnMatrixItem = [self syferLockSubStringWithIndex:indexPath.item];
+        [cell configureCellWithNumberString:numbersOnMatrixItem];
+    }
+    return cell;
+}
+
+#pragma mark - UICollectionViewDelegateFlowLayout
+- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
+    return [SyferLockLoginCollectionViewCell syflerLockLoginViewCellSize];
+}
+
+- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {
+    // Add header view height to adjust the top edge to navigation.
+    return CGSizeMake(0, 10);
+}
+
+- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
+    if (isPad) {
+        return 30;
+    }
+    return 10;
+}
+
+- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
+    if (isPad) {
+        return 20;
+    }
+    return 15;
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/UIViewController+Activity.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/UIViewController+Activity.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/UIViewController+Activity.h	(working copy)
@@ -0,0 +1,15 @@
+//
+//  UIViewController+Activity.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/9/12.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface UIViewController (Activity)
+
+- (void)showLoginActivity:(BOOL)aBool;
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/UIViewController+Activity.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/UIViewController+Activity.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/UIViewController+Activity.m	(working copy)
@@ -0,0 +1,57 @@
+//
+//  UIViewController+Activity.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/9/12.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <objc/runtime.h>
+#import "UIViewController+Activity.h"
+
+static NSString * const ActivityDarkControlKey = @"ActivityDarkControlKey";
+static NSString * const ActivityOriginalTitleKey = @"ActivityOriginalTitleKey";
+
+@implementation UIViewController (Activity)
+
+- (void)showLoginActivity:(BOOL)aBool {
+    UIControl *darkControl = objc_getAssociatedObject(self, &ActivityDarkControlKey);
+    if (!darkControl) {
+        darkControl = [[UIControl alloc] initWithFrame:self.view.bounds];
+        darkControl.backgroundColor = [UIColor colorWithRed:0/255.0 green:0/255.0 blue:0/255.0 alpha:0.5];
+        objc_setAssociatedObject(self, &ActivityDarkControlKey, darkControl, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+    }
+    
+    if (aBool) {
+        UIActivityIndicatorView *a = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
+        [a startAnimating];
+        
+        UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 20)];
+        [view addSubview:a];
+        
+        UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(a.frame.size.width + 5, 0, 70, 20)];
+        label.adjustsFontSizeToFitWidth = YES;
+        label.textColor = [UIColor whiteColor];
+        
+        NSString *originalTitle = self.navigationItem.title;
+        objc_setAssociatedObject(self, &ActivityOriginalTitleKey, originalTitle, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+        UIFont * font = [UIFont boldSystemFontOfSize:17];
+        label.font = font;
+        label.text = NSLocalizedString(@"Verifying", nil);
+        label.backgroundColor = [UIColor clearColor];
+        [view addSubview:label];
+        
+        [self.view endEditing:YES];
+        self.navigationItem.titleView = view;
+        [self.view addSubview:darkControl];
+    } else {
+        self.navigationItem.titleView = nil;
+        NSString *originalTitle = objc_getAssociatedObject(self, &ActivityOriginalTitleKey);
+        if (originalTitle) {
+            self.navigationItem.title = originalTitle;
+        }
+        [darkControl removeFromSuperview];
+    }
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/UIViewController+HideKeyboard.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/UIViewController+HideKeyboard.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/UIViewController+HideKeyboard.h	(working copy)
@@ -0,0 +1,15 @@
+//
+//  UIViewController+HideKeyboard.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/9/12.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface UIViewController (HideKeyboard)
+
+- (void)enableHideKeyboard;
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/UIViewController+HideKeyboard.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/UIViewController+HideKeyboard.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/UIViewController+HideKeyboard.m	(working copy)
@@ -0,0 +1,24 @@
+//
+//  UIViewController+HideKeyboard.m
+//  MacTunnel
+//
+//  Created by wangxy on 2017/9/12.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#import "UIViewController+HideKeyboard.h"
+
+@implementation UIViewController (HideKeyboard)
+
+// To dismiss keyboard on tapping.
+- (void)enableHideKeyboard {
+    UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard)];
+    gesture.cancelsTouchesInView = NO;
+    [self.view addGestureRecognizer:gesture];
+}
+
+- (void)hideKeyboard {
+    [self.view endEditing:YES];
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ZTWKWebViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ZTWKWebViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ZTWKWebViewController.h	(working copy)
@@ -0,0 +1,19 @@
+//
+//  ZTWKWebViewController.h
+//  iSecSP
+//
+//  Created by YJoo on 2022/8/9.
+//  Copyright © 2022 Infosec. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface ZTWKWebViewController : UIViewController
+
+@property (nonatomic, copy) NSString *webUrl;
+
+@end
+
+NS_ASSUME_NONNULL_END
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ZTWKWebViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ZTWKWebViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ZTWKWebViewController.m	(working copy)
@@ -0,0 +1,155 @@
+//
+//  ZTWKWebViewController.m
+//  iSecSP
+//
+//  Created by YJoo on 2022/8/9.
+//  Copyright © 2022 Infosec. All rights reserved.
+//
+
+#import "ZTWKWebViewController.h"
+#import <WebKit/WebKit.h>
+#import "FBKVOController.h"
+#import "Global.h"
+
+@interface ZTWKWebViewController ()<WKUIDelegate, WKNavigationDelegate>
+
+@property (nonatomic, strong) WKWebView *webView;
+@property (nonatomic, strong) UIProgressView *progressView;
+@property (nonatomic, strong) FBKVOController *kvoController;
+
+@end
+
+@implementation ZTWKWebViewController
+
+- (WKWebView *)webView {
+    if (_webView == nil) {
+
+        _webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, screenWidth, screenHeight)];
+        _webView.navigationDelegate = self;
+        _webView.UIDelegate = self;
+    }
+    return _webView;
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    
+    self.view.backgroundColor = RGBA(239, 239, 244, 1);
+    
+    [self setNavigationItems];
+    [self initWebView];
+    [self initFBKVO];
+}
+
+
+- (void)initWebView
+{
+    [self.view addSubview:self.webView];
+    [_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:self.webUrl]]];
+
+    _progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0, SafeAreaTopHeight, screenWidth, 2)];
+    _progressView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
+    _progressView.progressTintColor = [UIColor greenColor];
+    [self.view addSubview:_progressView];
+}
+
+
+- (void)initFBKVO
+{
+   __weak typeof (self) weakSelf = self;
+   self.kvoController = [FBKVOController controllerWithObserver:self];
+   [self.kvoController observe:self.webView keyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew block:^(id  _Nullable observer, id  _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
+
+       weakSelf.progressView.alpha = 1;
+       [weakSelf.progressView setProgress:self.webView.estimatedProgress animated:YES];
+       if(weakSelf.webView.estimatedProgress >= 1.0f)
+       {
+           [UIView animateWithDuration:0.5 animations:^{
+               weakSelf.progressView.alpha = 0;
+           } completion:^(BOOL finished) {
+               [weakSelf.progressView setProgress:0.0f animated:NO];
+           }];
+       }
+   }];
+
+   [self.kvoController observe:self.webView keyPath:@"title" options:NSKeyValueObservingOptionNew block:^(id  _Nullable observer, id  _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
+        weakSelf.title = self.webView.title;
+   }];
+}
+
+- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(nonnull WKNavigationAction *)navigationAction decisionHandler:(nonnull void (^)(WKNavigationActionPolicy))decisionHandler
+{
+    if (navigationAction.targetFrame == nil) {
+        [_webView loadRequest:navigationAction.request];
+    }
+    
+    decisionHandler(WKNavigationActionPolicyAllow);
+}
+
+////页面加载完成后
+- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
+{
+    NSLog(@"");
+}
+
+//页面加载失败
+- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
+{
+    NSLog(@"");
+}
+
+-(void)setNavigationItems
+{
+    UIBarButtonItem *itemBack = [self barButtonItemWithTitle:@"后退" target:self action:@selector(goBackAction)];
+    UIBarButtonItem *itemReFresh = [self barButtonItemWithImage:[UIImage imageNamed:@"SecBrowserReload"] target:self action:@selector(refreshAction)];
+    self.navigationItem.rightBarButtonItems = @[itemBack, itemReFresh];
+}
+
+- (void)goBackAction
+{
+    [_webView goBack];
+}
+
+- (void)refreshAction
+{
+    [_webView reload];
+}
+
+- (UIBarButtonItem *)barButtonItemWithImage:(UIImage *)image target:(id)target action:(SEL)selector {
+    
+    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
+    
+    [button setBackgroundImage:image forState:UIControlStateNormal];
+    button.tintColor = nil;
+    
+    [button addTarget:target action:selector forControlEvents:UIControlEventTouchUpInside];
+    
+    button.size = button.currentBackgroundImage.size;
+    
+    return  [[UIBarButtonItem alloc] initWithCustomView:button];
+}
+
+- (UIBarButtonItem *)barButtonItemWithTitle:(NSString *)title target:(id)target action:(SEL)selector {
+    
+    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
+    button.backgroundColor = [UIColor clearColor];
+    [button setTitle:title forState:UIControlStateNormal];
+    [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
+    button.titleLabel.font = [UIFont systemFontOfSize:14];
+    [button addTarget:target action:selector forControlEvents:UIControlEventTouchUpInside];
+    
+    button.size = CGSizeMake(40, 40);
+    
+    return  [[UIBarButtonItem alloc] initWithCustomView:button];
+}
+
+- (void)pop {
+    
+    if (self.navigationController.viewControllers.count > 1) {
+        [self.navigationController popViewControllerAnimated:YES];
+    }else{
+        [self dismissViewControllerAnimated:YES completion:nil];
+    }
+}
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ZTWebAuthViewController.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ZTWebAuthViewController.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ZTWebAuthViewController.h	(working copy)
@@ -0,0 +1,21 @@
+//
+//  ZTWebAuthViewController.h
+//  MotionProPlus
+//
+//  Created by YJoo on 2022/6/2.
+//  Copyright © 2022 Infosec. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface ZTWebAuthViewController : UIViewController
+
+typedef void (^AuthCallback)(NSError *error, NSString *session, NSString *username, NSString *acsInfo);
+
+@property (nonatomic, strong) NSDictionary *infoDic;
+
+@end
+
+NS_ASSUME_NONNULL_END
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ZTWebAuthViewController.m
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ZTWebAuthViewController.m	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Controllers/ZTWebAuthViewController.m	(working copy)
@@ -0,0 +1,312 @@
+//
+//  ZTWebAuthViewController.m
+//  MotionProPlus
+//
+//  Created by YJoo on 2022/6/2.
+//  Copyright © 2022 Infosec. All rights reserved.
+//
+
+#import "ZTWebAuthViewController.h"
+#import <WebKit/WebKit.h>
+#import "ANLogger.h"
+#import "Global.h"
+#import "NSURLRequest+ForSSL.h"
+#import "Singleton.h"
+#import "MBProgressHUD.h"
+
+#define MP_WELCOME_LOCALHOST_URL   @"/prx/000/http/localhost/welcome"
+#define MP_WELCOME_LOCALH_URL      @"/prx/000/http/localh/welcome"
+#define MP_SESSION_PREFIX   @"ANsession"
+#define MP_USERNAME_COOKIE  @"username"
+#define MP_ACCESS_NAME      @"acs_mode"
+#define MP_ACCESS_DESC      @"acs_desc"
+#define MP_ROLE_NAMES       @"role_names"
+
+@interface ZTWebAuthViewController ()<WKUIDelegate, WKNavigationDelegate>
+{
+    NSString *_urlString;
+}
+
+@property (nonatomic, strong) WKWebView * webView;
+@property (copy, nonatomic) AuthCallback completion;
+@property (nonatomic, strong) NSMutableArray *cookies;
+@property (nonatomic, assign) BOOL isActivePop;
+
+@end
+
+@implementation ZTWebAuthViewController
+
+- (WKWebView *)webView {
+    if (_webView == nil) {
+
+        _webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, screenWidth, screenHeight)];
+        _webView.navigationDelegate = self;
+        _webView.UIDelegate = self;
+    }
+    return _webView;
+}
+
+-(void)viewWillDisappear:(BOOL)animated
+{
+    if (self.webView.isLoading) {
+        [self.webView stopLoading];
+    }
+    
+    if (_isActivePop){
+        
+        [self cancelButtonClicked];
+    }
+    
+    [self.navigationController popViewControllerAnimated:YES];
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    
+    self.title = @"WebAuth";
+    
+    self.isActivePop = YES;
+    [self.view addSubview:self.webView];
+    [self startLoadPage];
+}
+
+- (void)cancelButtonClicked
+{
+    if (self.completion) {
+        self.completion(nil, nil, nil, nil);
+    }
+}
+
+- (BOOL)startLoadWithHost:(NSString *)host alias:(NSString *)alias port:(NSString *)port url:(NSString *)url  completion:(AuthCallback)completion {
+    if (url.length > 0) {
+        _urlString = url;
+    } else {
+        _urlString = [self setHost:host alias:alias andPort:port];
+    }
+    if (_urlString == nil) {
+        // TODO: Add alert to show error to user.
+        return NO;
+    }
+    
+    self.completion = completion;
+    
+    return YES;
+}
+
+- (void)startLoadPage {
+    NSURL *url = [NSURL URLWithString:_urlString];
+    NSURLRequest *request = [NSURLRequest requestWithURL:url];
+    [NSURLRequest allowsAnyHTTPSCertificateForHost:url.host];
+    
+    [self.webView loadRequest:request];
+    [self showIndicator];
+}
+
+- (NSString *)setHost:(NSString *)host alias:(NSString *)alias andPort:(NSString *)port {
+    NSString *urlString = nil;
+    
+    if (!host || host.length == 0) {
+        ANError(@"WebView received invalid host.");
+        return nil;
+    }
+    
+    if (port && port.length > 0) {
+        host = [NSString stringWithFormat:@"%@:%@", host, port];
+    }
+    
+    if (alias && alias.length > 0) {
+        urlString = [NSString stringWithFormat:@"https://%@/%@", host, alias];
+        return urlString;
+    }
+    
+    urlString = [NSString stringWithFormat:@"https://%@", host];
+    
+    return urlString;
+}
+
+- (NSString *)retrieveUsernameFromCookieJar
+{
+    for (NSHTTPCookie *cookie in _cookies) {
+        if (cookie.name) {
+            if ([cookie.name isEqualToString:MP_USERNAME_COOKIE]) {
+                NSString *username = cookie.value;
+                ANDebug(@"WebAuth username is %@", username);
+                return username;
+            }
+        }
+    }
+    
+    return nil;
+}
+
+- (NSString *)retrieveAcsInfoFromCookieJar
+{
+    NSString *oauthAcsInfo, *username, *acsName, *acsDesc, *roleName;
+    for (NSHTTPCookie *cookie in _cookies) {
+        if (cookie.name) {
+            if ([cookie.name isEqualToString:MP_USERNAME_COOKIE]) {
+                username = cookie.value ?: @"";
+                ANInfo(@"WebAuth username is %@", username);
+                continue;
+            } else if ([cookie.name isEqualToString:MP_ACCESS_NAME]) {
+                acsName = cookie.value ?: @"";
+                ANInfo(@"WebAuth acsName is %@", acsName);
+                continue;
+            } else if ([cookie.name isEqualToString:MP_ACCESS_DESC]) {
+                acsDesc = cookie.value ?: @"";
+                ANInfo(@"WebAuth acsDesc is %@", acsDesc);
+                continue;
+            } else if ([cookie.name isEqualToString:MP_ROLE_NAMES]) {
+                roleName = cookie.value ?: @"";
+                ANInfo(@"WebAuth role is %@", roleName);
+                continue;
+            }
+        }
+    }
+    
+    oauthAcsInfo = [NSString stringWithFormat:@"username=%@&role_names=%@&acs_mode=%@&acs_desc=%@", username, roleName, acsName, acsDesc];
+    oauthAcsInfo = [oauthAcsInfo stringByReplacingOccurrencesOfString:@"(null)" withString:@""];
+    
+    return oauthAcsInfo;
+}
+
+- (NSString *)retrieveSessionFromCookieJar
+{
+    for (NSHTTPCookie *cookie in _cookies) {
+        if (cookie.name) {
+            if ([cookie.name hasPrefix:MP_SESSION_PREFIX]) {
+                NSString *ANSession = [NSString stringWithFormat:@"%@=%@", cookie.name, cookie.value];
+                return ANSession;
+            }
+        }
+    }
+    
+    return nil;
+}
+
+-(void) getWebCookies
+{
+    __weak __typeof(self) weakSelf = self;
+    if (@available(iOS 12.0, *)) {
+                
+        WKHTTPCookieStore *cookieStore = _webView.configuration.websiteDataStore.httpCookieStore;
+        [cookieStore getAllCookies:^(NSArray<NSHTTPCookie *> * _Nonnull cookiesArray) {
+           
+            weakSelf.cookies = cookiesArray.mutableCopy;
+            
+            NSString *username = [self retrieveUsernameFromCookieJar];
+            NSString *session = [self retrieveSessionFromCookieJar];
+            NSString *acsInfo = [self retrieveAcsInfoFromCookieJar];
+            [self didFinishedAuthenticationWithError:nil session:session username:username acsInfo:acsInfo];
+        }];
+    }
+}
+
+- (void)showIndicator {
+    
+    [MBProgressHUD showHUDAddedTo:self.view animated:YES];
+}
+
+- (void)hideIndicator {
+    
+    [MBProgressHUD hideHUDForView:self.view animated:YES];
+}
+
+- (void)didFinishedAuthenticationWithError:(NSError *)error session:(NSString *)session username:(NSString *)username acsInfo:(NSString *)acsInfo {
+    ANInfo(@"WebAuth did finished with error: %@.", error.localizedDescription);
+    
+    [self.navigationController popViewControllerAnimated:YES];
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        
+        self.isActivePop = NO;
+        if (self.completion) {
+            self.completion(error, session, username, acsInfo);
+        }
+    });
+}
+
+- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(nonnull WKNavigationAction *)navigationAction decisionHandler:(nonnull void (^)(WKNavigationActionPolicy))decisionHandler {
+    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:navigationAction.request.URL];
+    if ([request.URL.path isEqualToString:MP_WELCOME_LOCALHOST_URL] ||
+        [request.URL.path isEqualToString:MP_WELCOME_LOCALH_URL]) {
+        self.webView.navigationDelegate = self;
+        self.webView.UIDelegate = self;
+        
+        [self getWebCookies];
+        decisionHandler(WKNavigationActionPolicyCancel);
+    }else {
+        
+        decisionHandler(WKNavigationActionPolicyAllow);
+    }
+}
+
+////页面加载完成后
+- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
+    [self hideIndicator];
+}
+
+//页面加载失败
+- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error {
+    [self hideIndicator];
+    ANError(@"WebAuth received error: %@.", error);
+    
+    if ([error.domain isEqualToString:@"NSURLErrorDomain"]) {
+        switch (error.code) {
+            case NSURLErrorServerCertificateUntrusted:
+                // Ignore these errors.
+                return;
+                
+            default:
+                break;
+        }
+    }
+    
+//    [self didFinishedAuthenticationWithError:error session:nil username:nil acsInfo:nil];
+}
+
+- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {
+    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
+        
+        
+        dispatch_async( dispatch_get_global_queue(0, 0), ^{
+            NSURLCredential * card = [[NSURLCredential alloc] initWithTrust:challenge.protectionSpace.serverTrust];
+            completionHandler(NSURLSessionAuthChallengeUseCredential, card);
+           });
+        
+        
+    }
+}
+
+-(void)setInfoDic:(NSDictionary *)infoDic
+{
+    if (infoDic.count < 1)
+    {
+        return;
+    }
+    
+    NSString *host = [infoDic valueForKey:@"host"];
+    NSString *port = [infoDic valueForKey:@"port"];
+    NSString *alias = [infoDic valueForKey:@"alias"];
+    NSString *url = [infoDic valueForKey:@"url"];
+    ANInfo(@"send web auth para, host=%@, port=%@, alias=%@, url=%@", host, port, alias, url);
+    AuthCallback completion = [infoDic valueForKey:@"completion"];
+    
+    [self startLoadWithHost:host
+                      alias:alias
+                       port:port
+                        url:url
+                 completion:completion];
+}
+
+- (void)pop {
+    
+    [self cancelButtonClicked];
+    if (self.navigationController.viewControllers.count > 1) {
+        [self.navigationController popViewControllerAnimated:YES];
+    }else{
+        [self dismissViewControllerAnimated:YES completion:nil];
+    }
+}
+
+
+@end
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Global.h
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Global.h	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Global.h	(working copy)
@@ -0,0 +1,60 @@
+//
+//  Global.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/17.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#ifndef Global_h
+#define Global_h
+
+#ifdef __OBJC__
+#import <Foundation/Foundation.h>
+#endif
+
+// MARK: 这里还是走注释的方式吧，跑对应程序时，注释掉互斥引用，保证100%引用成功
+#if TARGET_OS_IPHONE
+#import <UIKit/UIKit.h>
+#import "UIView+frame.h"
+#elif TARGET_OS_MAC
+#import <AppKit/AppKit.h>
+#import <Foundation/Foundation.h>
+#endif
+
+
+#define UIColorFromRGBA(rgbValue, alphaValue) \
+    [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
+                    green:((float)((rgbValue & 0x00FF00) >> 8))/255.0 \
+                     blue:((float)(rgbValue & 0x0000FF))/255.0 alpha:alphaValue]
+
+#define MAIN_COLOR UIColorFromRGBA(0xE4701D, 1.0)
+
+#define IS_IOS_10_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0)
+#define IS_IOS_9_2_OR_LATER  ([[[UIDevice currentDevice] systemVersion] floatValue] > 9.1)
+
+#define OpenURL(url)  [[UIApplication sharedApplication] openURL:(url) options:@{} completionHandler:nil ]
+
+#define APP_URL_SCHEME  @"motionproplus"
+
+//保存认证方式
+#define AUTH_METHOD_NAME   @"auth_Method_Name"
+#define screenWidth  [UIScreen mainScreen].bounds.size.width
+#define screenHeight [UIScreen mainScreen].bounds.size.height
+#define ScaleX       screenWidth/375.0f
+#define SCaleY       screenHeight/667.0f
+#define SafeAreaTopHeight (screenHeight >= 812.0 ? 88 : 64)
+
+/** 自定义颜色*/
+#define RGBA(r,g,b,a) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a]
+
+#define ISNULLSTR(str) (str == nil || (NSObject *)str == [NSNull null] || str.length == 0 || [str isEqualToString:@"(null)"]||[str isEqualToString:@"<null>"])
+
+@protocol ANViewControllerSwitchProtocol <NSObject>
+
+@required
+- (void)switchFromSender:(id)sender withOption:(NSDictionary *)option;
+
+@end
+
+#endif /* Global_h */
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Global.h.iqiyi
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Global.h.iqiyi	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Global.h.iqiyi	(working copy)
@@ -0,0 +1,48 @@
+//
+//  Global.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/17.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#ifndef Global_h
+#define Global_h
+
+#import <UIKit/UIKit.h>
+#import "UIView+frame.h"
+
+#define UIColorFromRGBA(rgbValue, alphaValue) \
+    [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
+                    green:((float)((rgbValue & 0x00FF00) >> 8))/255.0 \
+                     blue:((float)(rgbValue & 0x0000FF))/255.0 alpha:alphaValue]
+
+#define MAIN_COLOR UIColorFromRGBA(0x00DC5A, 1.0)
+
+#define IS_IOS_10_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0)
+#define IS_IOS_9_2_OR_LATER  ([[[UIDevice currentDevice] systemVersion] floatValue] > 9.1)
+
+#define OpenURL(url)  [[UIApplication sharedApplication] openURL:(url)]
+
+#define APP_URL_SCHEME  @"motionproplus"
+
+//保存认证方式
+#define AUTH_METHOD_NAME   @"auth_Method_Name"
+#define screenWidth  [UIScreen mainScreen].bounds.size.width
+#define screenHeight [UIScreen mainScreen].bounds.size.height
+#define ScaleX       screenWidth/375.0f
+#define SCaleY       screenHeight/667.0f
+
+/** 自定义颜色*/
+#define RGBA(r,g,b,a) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a]
+
+#define ISNULLSTR(str) (str == nil || (NSObject *)str == [NSNull null] || str.length == 0 || [str isEqualToString:@"(null)"]||[str isEqualToString:@"<null>"])
+
+@protocol ANViewControllerSwitchProtocol <NSObject>
+
+@required
+- (void)switchFromSender:(id)sender withOption:(NSDictionary *)option;
+
+@end
+
+#endif /* Global_h */
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Global.h.zrt
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Global.h.zrt	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Global.h.zrt	(working copy)
@@ -0,0 +1,48 @@
+//
+//  Global.h
+//  MacTunnel
+//
+//  Created by wangxy on 2017/7/17.
+//  Copyright © 2017年 wangxy. All rights reserved.
+//
+
+#ifndef Global_h
+#define Global_h
+
+#import <UIKit/UIKit.h>
+#import "UIView+frame.h"
+
+#define UIColorFromRGBA(rgbValue, alphaValue) \
+    [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
+                    green:((float)((rgbValue & 0x00FF00) >> 8))/255.0 \
+                     blue:((float)(rgbValue & 0x0000FF))/255.0 alpha:alphaValue]
+
+#define MAIN_COLOR UIColorFromRGBA(0xE70012, 1.0)
+
+#define IS_IOS_10_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0)
+#define IS_IOS_9_2_OR_LATER  ([[[UIDevice currentDevice] systemVersion] floatValue] > 9.1)
+
+#define OpenURL(url)  [[UIApplication sharedApplication] openURL:(url)]
+
+#define APP_URL_SCHEME  @"motionproplus"
+
+//保存认证方式
+#define AUTH_METHOD_NAME   @"auth_Method_Name"
+#define screenWidth  [UIScreen mainScreen].bounds.size.width
+#define screenHeight [UIScreen mainScreen].bounds.size.height
+#define ScaleX       screenWidth/375.0f
+#define SCaleY       screenHeight/667.0f
+
+/** 自定义颜色*/
+#define RGBA(r,g,b,a) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a]
+
+#define ISNULLSTR(str) (str == nil || (NSObject *)str == [NSNull null] || str.length == 0 || [str isEqualToString:@"(null)"]||[str isEqualToString:@"<null>"])
+
+@protocol ANViewControllerSwitchProtocol <NSObject>
+
+@required
+- (void)switchFromSender:(id)sender withOption:(NSDictionary *)option;
+
+@end
+
+#endif /* Global_h */
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Info.plist
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Info.plist	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Info.plist	(working copy)
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleURLTypes</key>
+	<array>
+		<dict>
+			<key>CFBundleTypeRole</key>
+			<string>Editor</string>
+			<key>CFBundleURLIconFile</key>
+			<string>icon</string>
+			<key>CFBundleURLSchemes</key>
+			<array>
+				<string>motionproplus</string>
+			</array>
+		</dict>
+	</array>
+	<key>ITSAppUsesNonExemptEncryption</key>
+	<false/>
+	<key>LSApplicationQueriesSchemes</key>
+	<array>
+		<string>RD</string>
+		<string>rdp</string>
+	</array>
+	<key>NSAppTransportSecurity</key>
+	<dict>
+		<key>NSAllowsArbitraryLoads</key>
+		<true/>
+	</dict>
+	<key>UIStatusBarHidden~ipad</key>
+	<false/>
+</dict>
+</plist>
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Info.plist.InfosecStore
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Info.plist.InfosecStore	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Info.plist.InfosecStore	(working copy)
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>NSFaceIDUsageDescription</key>
+	<string>MotionPro Plus needs to use your FaceID, which can be configured in Settings</string>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleDisplayName</key>
+	<string>MotionPro</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>2.3.10</string>
+	<key>CFBundleURLTypes</key>
+	<array>
+		<dict>
+			<key>CFBundleTypeRole</key>
+			<string>Editor</string>
+			<key>CFBundleURLIconFile</key>
+			<string>icon</string>
+			<key>CFBundleURLSchemes</key>
+			<array>
+				<string>motionproplus</string>
+			</array>
+		</dict>
+	</array>
+	<key>CFBundleVersion</key>
+	<string>3</string>
+	<key>LSApplicationQueriesSchemes</key>
+	<array>
+		<string>RD</string>
+		<string>rdp</string>
+	</array>
+	<key>LSRequiresIPhoneOS</key>
+	<true/>
+	<key>NSAppTransportSecurity</key>
+	<dict>
+		<key>NSAllowsArbitraryLoads</key>
+		<true/>
+	</dict>
+	<key>UIMainStoryboardFile</key>
+	<string>Main</string>
+	<key>UIRequiredDeviceCapabilities</key>
+	<array>
+		<string>armv7</string>
+	</array>
+	<key>UIRequiresFullScreen</key>
+	<true/>
+	<key>UIStatusBarHidden~ipad</key>
+	<false/>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+	</array>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+	</array>
+	<key>UIUserInterfaceStyle</key>
+	<string>Light</string>
+</dict>
+</plist>
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Info.plist.MotionPro
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Info.plist.MotionPro	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Info.plist.MotionPro	(working copy)
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>NSFaceIDUsageDescription</key>
+	<string>MotionPro Plus needs to use your FaceID, which can be configured in Settings</string>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleDisplayName</key>
+	<string>MotionPro</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>2.3.10</string>
+	<key>CFBundleURLTypes</key>
+	<array>
+		<dict>
+			<key>CFBundleTypeRole</key>
+			<string>Editor</string>
+			<key>CFBundleURLIconFile</key>
+			<string>icon</string>
+			<key>CFBundleURLSchemes</key>
+			<array>
+				<string>motionproplus</string>
+			</array>
+		</dict>
+	</array>
+	<key>CFBundleVersion</key>
+	<string>3</string>
+	<key>LSApplicationQueriesSchemes</key>
+	<array>
+		<string>RD</string>
+		<string>rdp</string>
+	</array>
+	<key>LSRequiresIPhoneOS</key>
+	<true/>
+	<key>NSAppTransportSecurity</key>
+	<dict>
+		<key>NSAllowsArbitraryLoads</key>
+		<true/>
+	</dict>
+	<key>UIMainStoryboardFile</key>
+	<string>Main</string>
+	<key>UIRequiredDeviceCapabilities</key>
+	<array>
+		<string>armv7</string>
+	</array>
+	<key>UIRequiresFullScreen</key>
+	<true/>
+	<key>UIStatusBarHidden~ipad</key>
+	<false/>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+	</array>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+	</array>
+	<key>UIUserInterfaceStyle</key>
+	<string>Light</string>
+</dict>
+</plist>
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Info.plist.iqiyi
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Info.plist.iqiyi	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Info.plist.iqiyi	(working copy)
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>NSFaceIDUsageDescription</key>
+	<string>MotionPro Plus needs to use your FaceID, which can be configured in Settings</string>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleDisplayName</key>
+	<string>iQIYI VPN</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>2.0.20</string>
+	<key>CFBundleURLTypes</key>
+	<array>
+		<dict>
+			<key>CFBundleTypeRole</key>
+			<string>Editor</string>
+			<key>CFBundleURLIconFile</key>
+			<string>icon</string>
+			<key>CFBundleURLSchemes</key>
+			<array>
+				<string>motionproplus</string>
+			</array>
+		</dict>
+	</array>
+	<key>CFBundleVersion</key>
+	<string>121</string>
+	<key>LSApplicationQueriesSchemes</key>
+	<array>
+		<string>RD</string>
+		<string>rdp</string>
+	</array>
+	<key>LSRequiresIPhoneOS</key>
+	<true/>
+	<key>NSAppTransportSecurity</key>
+	<dict>
+		<key>NSAllowsArbitraryLoads</key>
+		<true/>
+	</dict>
+	<key>UIMainStoryboardFile</key>
+	<string>Main</string>
+	<key>UIRequiredDeviceCapabilities</key>
+	<array>
+		<string>armv7</string>
+	</array>
+	<key>UIRequiresFullScreen</key>
+	<true/>
+	<key>UIStatusBarHidden~ipad</key>
+	<false/>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+	</array>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+	</array>
+	<key>UIUserInterfaceStyle</key>
+	<string>Light</string>
+</dict>
+</plist>
Index: /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Info.plist.zrt
===================================================================
--- /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Info.plist.zrt	(nonexistent)
+++ /branches/ag_client_motionProGlobal_ios_new/MotionPro-iOS/Info.plist.zrt	(working copy)
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>NSFaceIDUsageDescription</key>
+	<string>MotionPro Plus needs to use your FaceID, which can be configured in Settings</string>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleDisplayName</key>
+	<string>中融专网</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>2.0.21</string>
+	<key>CFBundleURLTypes</key>
+	<array>
+		<dict>
+			<key>CFBundleTypeRole</key>
+			<string>Editor</string>
+			<key>CFBundleURLIconFile</key>
+			<string>icon</string>
+			<key>CFBundleURLSchemes</key>
+			<array>
+				<string>motionproplus</string>
+			</array>
+		</dict>
+	</array>
+	<key>CFBundleVersion</key>
+	<string>122</string>
+	<key>LSApplicationQueriesSchemes</key>
+	<array>
+		<string>RD</string>
+		<string>rdp</string>
+	</array>
+	<key>LSRequiresIPhoneOS</key>
+	<true/>
+	<key>NSAppTransportSecurity</key>
+	<dict>
+		<key>NSAllowsArbitraryLoads</key>
+		<true/>
+	</dict>
+	<key>UIMainStoryboardFile</key>
+	<string>Main</string>
+	<key>UIRequiredDeviceCapabilities</key>
+	<array>
+		<string>armv7</string>
+	</array>
+	<key>UIRequiresFullScreen</key>
+	<true/>
+	<key>UIStatusBarHidden~ipad</key>
+	<false/>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+	</array>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+	</array>
+	<key>UIUserInterfaceStyle</key>
+	<string>Light</string>
+</dict>
+</plist>
