screen-object 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +2 -0
- data/ChangeLog +7 -0
- data/Gemfile +9 -0
- data/Rakefile +28 -0
- data/cucumber.yml +4 -0
- data/features/button.feature +28 -0
- data/features/checkbox.feature +11 -0
- data/features/navigation.feature +10 -0
- data/features/step_definitions/button_step.rb +46 -0
- data/features/step_definitions/checkbox_step.rb +12 -0
- data/features/step_definitions/navigation_steps.rb +14 -0
- data/features/step_definitions/table_step.rb +5 -0
- data/features/step_definitions/textfield_step.rb +5 -0
- data/features/support/appium.txt +9 -0
- data/features/support/appium_ios.txt +11 -0
- data/features/support/env.rb +30 -0
- data/features/support/screen.rb +79 -0
- data/features/support/screens/buttons_screen.rb +8 -0
- data/features/support/screens/landing_screen.rb +6 -0
- data/features/support/screens/main_screen.rb +6 -0
- data/features/table.feature +11 -0
- data/features/textfield.feature +10 -0
- data/lib/screen-object.rb +161 -0
- data/lib/screen-object/.DS_Store +0 -0
- data/lib/screen-object/accessors.rb +457 -0
- data/lib/screen-object/accessors/button.rb +36 -0
- data/lib/screen-object/accessors/checkbox.rb +38 -0
- data/lib/screen-object/accessors/element.rb +144 -0
- data/lib/screen-object/accessors/image.rb +25 -0
- data/lib/screen-object/accessors/table.rb +26 -0
- data/lib/screen-object/accessors/text.rb +46 -0
- data/lib/screen-object/accessors/textfield.rb +41 -0
- data/lib/screen-object/appium_server.rb +58 -0
- data/lib/screen-object/elements.rb +21 -0
- data/lib/screen-object/load_appium.rb +31 -0
- data/lib/screen-object/screen_factory.rb +43 -0
- data/lib/screen-object/version.rb +4 -0
- data/screen-object.gemspec +28 -0
- data/spec/integration/appium_server_spec.rb +24 -0
- data/spec/lib/appium_server_spec.rb +59 -0
- data/spec/lib/screen_object_spec.rb +37 -0
- data/spec/screen-object/button_spec.rb +25 -0
- data/spec/screen-object/checkbox_spec.rb +35 -0
- data/spec/screen-object/element_spec.rb +205 -0
- data/spec/screen-object/image_spec.rb +21 -0
- data/spec/screen-object/text_field_spec.rb +37 -0
- data/spec/screen-object/text_spec.rb +29 -0
- data/spec/spec_helper.rb +29 -0
- metadata +201 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a485a4dff88029c7ac2fa3e3ffe8b63c423606de
|
4
|
+
data.tar.gz: a5fbeb35806fd5724d172a5f1dc97df562f99347
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d43363bd1486fa6efc5272cdb98b3d8943d3dc6664d3a720c07871ccaad2869f5c050520543bb726edd7e1ab3b4066a0a009c9c96f3a6cda9e2afa66807e7552
|
7
|
+
data.tar.gz: 9504a4f5d599ade809cf776d44b2afd2cf7146e3e2172ae2e98ada91d6a13166ae93111a67eb037e25034ba9b3a6da689befe3e2e86a8ca1dc0b69460b553050
|
data/.rspec
ADDED
data/ChangeLog
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
require 'cucumber'
|
4
|
+
require 'cucumber/rake/task'
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
|
7
|
+
Bundler::GemHelper.install_tasks
|
8
|
+
|
9
|
+
|
10
|
+
#Rake::Task['release'].clear
|
11
|
+
|
12
|
+
|
13
|
+
Cucumber::Rake::Task.new(:features, 'Run the features') do |task|
|
14
|
+
task.profile = 'default'
|
15
|
+
end
|
16
|
+
|
17
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
18
|
+
spec.ruby_opts = "-I lib:spec"
|
19
|
+
spec.pattern = 'spec/lib/*_spec.rb'
|
20
|
+
end
|
21
|
+
task :spec
|
22
|
+
|
23
|
+
RSpec::Core::RakeTask.new(:integration) do |spec|
|
24
|
+
spec.ruby_opts = "-I lib:spec"
|
25
|
+
spec.pattern = 'spec/integration/*_spec.rb'
|
26
|
+
end
|
27
|
+
|
28
|
+
task :integration
|
data/cucumber.yml
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
Feature: Button
|
2
|
+
In order to access the buttons functionality
|
3
|
+
we need to test all the operations
|
4
|
+
|
5
|
+
Background:
|
6
|
+
Given I am on UICatalog screen
|
7
|
+
|
8
|
+
|
9
|
+
Scenario: Verify the button exists
|
10
|
+
When I verify the existence of the button
|
11
|
+
Then I should see the return value as true on button existence
|
12
|
+
|
13
|
+
#Scenario: Verify the output when button doesn't exist
|
14
|
+
# When I verify the existence of the button that is not present
|
15
|
+
# Then I should see the return value as false on button existence
|
16
|
+
|
17
|
+
Scenario: Click the button
|
18
|
+
When I click the UICatalog button
|
19
|
+
Then I should see the message to confirm the button is clicked
|
20
|
+
|
21
|
+
#Scenario: Click the button that does not exist
|
22
|
+
# When I click the button that does not exist
|
23
|
+
|
24
|
+
Scenario: Verify if the value is true when verifying the isenabled method
|
25
|
+
When I verify the existence of the button using isenabled method return value should be true
|
26
|
+
|
27
|
+
Scenario: Verify if the value is false when verifying the isenabled method for disabled button
|
28
|
+
When I verify the existence of the button using isenabled method return value should be false
|
@@ -0,0 +1,11 @@
|
|
1
|
+
Feature: CheckBox
|
2
|
+
In order to access the checkbox functionality
|
3
|
+
we need to test all the operations
|
4
|
+
|
5
|
+
Background:
|
6
|
+
Given I am on login page
|
7
|
+
|
8
|
+
|
9
|
+
Scenario: Verify the checkbox exists
|
10
|
+
When I verify the existence of the checkbox
|
11
|
+
Then I should see the return value as true on checkbox existence
|
@@ -0,0 +1,10 @@
|
|
1
|
+
Feature: Adding navigation capabilities to the screen-object
|
2
|
+
|
3
|
+
|
4
|
+
Scenario: Navigating to a screen
|
5
|
+
When I navigate to the buttons screen
|
6
|
+
Then the title for the buttons screen should be "Buttons"
|
7
|
+
|
8
|
+
Scenario: Doing multiple things on a page
|
9
|
+
When I navigate to the buttons screen
|
10
|
+
Then I should be able to click several buttons
|
@@ -0,0 +1,46 @@
|
|
1
|
+
Given(/^I am on UICatalog screen$/) do
|
2
|
+
|
3
|
+
end
|
4
|
+
|
5
|
+
When(/^I verify the existence of the button$/) do
|
6
|
+
puts "Checking for the existence of button using exists method. Should be true. -- #{on(Screen).ui_catalog_exists?}"
|
7
|
+
|
8
|
+
end
|
9
|
+
|
10
|
+
Then(/^I should see the return value as true on button existence$/) do
|
11
|
+
fail unless on(Screen).ui_catalog_exists?
|
12
|
+
end
|
13
|
+
|
14
|
+
When(/^I verify the existence of the button that is not present$/) do
|
15
|
+
puts "Checking for the existence of button using exist method. Should be false -- #{on(Screen).no_button_exists?}"
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
Then(/^I should see the return value as false on button existence$/) do
|
20
|
+
fail unless !on(Screen).no_button_exists?
|
21
|
+
end
|
22
|
+
|
23
|
+
When(/^I verify the existence of the button using isenabled method return value should be true$/) do
|
24
|
+
puts "Checking for the existence of button using enabled method.Should be true -- #{on(Screen).is_ui_catalog_enabled}"
|
25
|
+
fail unless on(Screen).is_ui_catalog_enabled
|
26
|
+
end
|
27
|
+
|
28
|
+
When(/^I verify the existence of the button using isenabled method return value should be false$/) do
|
29
|
+
puts "Checking for the existence of button using enabled method. should be false -- #{on(Screen).no_button_exists?}"
|
30
|
+
fail unless !on(Screen).no_button_exists?
|
31
|
+
end
|
32
|
+
|
33
|
+
When(/^I click the UICatalog button$/) do
|
34
|
+
on(Screen).click_ui_catalog
|
35
|
+
sleep 2
|
36
|
+
end
|
37
|
+
|
38
|
+
Then(/^I should see the message to confirm the button is clicked$/) do
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
When(/^I click the button that does not exist$/) do
|
43
|
+
puts '1'
|
44
|
+
on(Screen).no_button_click
|
45
|
+
puts on(Screen).no_button_click
|
46
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
When(/^I verify the existence of the checkbox$/) do
|
2
|
+
puts "Checking for the existence of button using exists method. Should be true. -- #{on(Screen).remember_me?}"
|
3
|
+
end
|
4
|
+
|
5
|
+
|
6
|
+
Then(/^I should see the return value as true on checkbox existence$/) do
|
7
|
+
fail unless on(Screen).remember_me?
|
8
|
+
puts on(Screen).remember_me_checked?
|
9
|
+
on(Screen).remember_me_uncheck
|
10
|
+
sleep 2
|
11
|
+
puts on(Screen).remember_me_checked?
|
12
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
When(/^I navigate to the buttons screen$/) do
|
2
|
+
navigate_to(ButtonsScreen)
|
3
|
+
end
|
4
|
+
|
5
|
+
Then(/^the title for the buttons screen should be "([^"]*)"$/) do |title|
|
6
|
+
on(ButtonsScreen).title_text.should == title
|
7
|
+
end
|
8
|
+
|
9
|
+
Then(/^I should be able to click several buttons$/) do
|
10
|
+
on(ButtonsScreen) do |screen|
|
11
|
+
screen.text_button
|
12
|
+
screen.contact_add
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,5 @@
|
|
1
|
+
When(/^I verify the existence of the text filed return value should be true$/) do
|
2
|
+
puts "Checking for the existence of button using exists method. Should be true. -- #{on(Screen).username_exists?}"
|
3
|
+
fail unless on(Screen).username_exists?
|
4
|
+
on(Screen).enter_username('adf')
|
5
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'appium_lib'
|
3
|
+
require 'cucumber/ast'
|
4
|
+
require 'require_all'
|
5
|
+
require 'screen-object'
|
6
|
+
|
7
|
+
require_relative 'screen'
|
8
|
+
require_rel 'screens'
|
9
|
+
|
10
|
+
appium_txt = IO.readlines(File.dirname(File.expand_path('./', __FILE__)) + "/appium.txt")
|
11
|
+
path = appium_txt[3].split(34.chr)
|
12
|
+
$AppPath = path[1]
|
13
|
+
Appium::Driver.new(Appium.load_appium_txt file: File.expand_path('./', __FILE__), verbose: true)
|
14
|
+
|
15
|
+
Before {
|
16
|
+
ScreenObject::Load_App.start_driver
|
17
|
+
}
|
18
|
+
|
19
|
+
After {
|
20
|
+
ScreenObject::Load_App.quit_driver
|
21
|
+
}
|
22
|
+
|
23
|
+
World(ScreenObject::ScreenFactory)
|
24
|
+
|
25
|
+
|
26
|
+
ScreenObject::ScreenFactory.routes = {
|
27
|
+
default: [[LandingScreen, :go_to_main_screen],
|
28
|
+
[MainScreen, :go_to_buttons_screen],
|
29
|
+
[ButtonsScreen, :title]]
|
30
|
+
}
|
@@ -0,0 +1,79 @@
|
|
1
|
+
class Screen
|
2
|
+
include ScreenObject
|
3
|
+
|
4
|
+
#ios
|
5
|
+
button(:ui_catalog, "name~UICatalog")
|
6
|
+
button(:no_button, "name~nobutton")
|
7
|
+
text(:ui_catalog_text, "xpath~//UIAStaticText[@name='UICatalog']")
|
8
|
+
text_field(:username, "xpath~//UIAApplication[1]/UIAWindow[1]/UIAScrollView[1]/UIATextField[1]")
|
9
|
+
text_field(:no_textfield, "name~notextfield")
|
10
|
+
checkbox(:remember, "id~c/rememberMe")
|
11
|
+
table(:table_view, 'xpath~UIAApplication[1]/UIAWindow[2]/UIATableView[1]')
|
12
|
+
|
13
|
+
# Button methods
|
14
|
+
|
15
|
+
def table_cell_count
|
16
|
+
table_view_cell_count
|
17
|
+
end
|
18
|
+
|
19
|
+
def remember_me?
|
20
|
+
remember?
|
21
|
+
end
|
22
|
+
|
23
|
+
def remember_me_checked?
|
24
|
+
remember_checked?
|
25
|
+
end
|
26
|
+
|
27
|
+
def remember_me_uncheck
|
28
|
+
check_remember
|
29
|
+
end
|
30
|
+
|
31
|
+
def ui_catalog_exists?
|
32
|
+
ui_catalog?
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def no_button_exists?
|
37
|
+
no_button?
|
38
|
+
end
|
39
|
+
|
40
|
+
def no_button_click
|
41
|
+
no_button
|
42
|
+
end
|
43
|
+
|
44
|
+
def enter_username(atext)
|
45
|
+
self.username=atext
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_username
|
49
|
+
username
|
50
|
+
end
|
51
|
+
|
52
|
+
def username_exists?
|
53
|
+
username?
|
54
|
+
end
|
55
|
+
|
56
|
+
def no_textfield_exists?
|
57
|
+
no_textfield?
|
58
|
+
end
|
59
|
+
|
60
|
+
def is_ui_catalog_enabled
|
61
|
+
ui_catalog_enabled?
|
62
|
+
end
|
63
|
+
|
64
|
+
def is_nobutton_enabled
|
65
|
+
no_button_isenabled?
|
66
|
+
end
|
67
|
+
|
68
|
+
def click_ui_catalog
|
69
|
+
ui_catalog
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Text Methods
|
74
|
+
|
75
|
+
def UICatalog_text?
|
76
|
+
ui_catalog_text?
|
77
|
+
end
|
78
|
+
|
79
|
+
# Table Methods
|
@@ -0,0 +1,8 @@
|
|
1
|
+
class ButtonsScreen
|
2
|
+
include ScreenObject
|
3
|
+
|
4
|
+
text(:title, "xpath~//UIAApplication[1]/UIAWindow[2]/UIANavigationBar[1]/UIAStaticText[1]")
|
5
|
+
button(:text_button, "name~Button")
|
6
|
+
button(:contact_add, "xpath~//UIAApplication[1]/UIAWindow[2]/UIATableView[1]/UIATableCell[2]")
|
7
|
+
|
8
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
#UIAApplication[1]/UIAWindow[2]/UIATableView[1]
|
2
|
+
|
3
|
+
Feature: Table
|
4
|
+
In order to access the table functionality
|
5
|
+
we need to test all the operations
|
6
|
+
|
7
|
+
Background:
|
8
|
+
Given I am on UICatalog screen
|
9
|
+
|
10
|
+
Scenario: Verify the table cell count method
|
11
|
+
When I verify the count of table cells I should get an integer
|
@@ -0,0 +1,10 @@
|
|
1
|
+
Feature: Button
|
2
|
+
In order to access the text functionality
|
3
|
+
we need to test all the operations
|
4
|
+
|
5
|
+
|
6
|
+
Background:
|
7
|
+
Given I am on login page
|
8
|
+
|
9
|
+
Scenario: Verify the text field exists method
|
10
|
+
When I verify the existence of the text filed return value should be true
|
@@ -0,0 +1,161 @@
|
|
1
|
+
=begin
|
2
|
+
***********************************************************************************************************
|
3
|
+
Copyright 2016 Capital One Services, LLC
|
4
|
+
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
you may not use this file except in compliance with the License.
|
7
|
+
You may obtain a copy of the License at
|
8
|
+
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
See the License for the specific language governing permissions and limitations under the License.
|
15
|
+
***********************************************************************************************************
|
16
|
+
=end
|
17
|
+
|
18
|
+
require 'appium_lib'
|
19
|
+
require 'screen-object/load_appium'
|
20
|
+
require 'screen-object/accessors'
|
21
|
+
require 'screen-object/elements'
|
22
|
+
require 'screen-object/screen_factory'
|
23
|
+
require 'screen-object/accessors/element'
|
24
|
+
|
25
|
+
# this module adds screen object when included.
|
26
|
+
# This module will add instance methods and screen object that you use to define and interact with mobile objects
|
27
|
+
|
28
|
+
module ScreenObject
|
29
|
+
|
30
|
+
def self.included(cls)
|
31
|
+
cls.extend ScreenObject::Accessors
|
32
|
+
end
|
33
|
+
|
34
|
+
def driver
|
35
|
+
ScreenObject::AppElements::Element.new('').driver
|
36
|
+
end
|
37
|
+
|
38
|
+
def swipe(start_x,start_y,end_x,end_y,touch_count,duration)
|
39
|
+
driver.swipe(:start_x => start_x, :start_y => start_y, :end_x => end_x, :end_y => end_y,:touchCount => touch_count,:duration => duration)
|
40
|
+
end
|
41
|
+
|
42
|
+
def landscape
|
43
|
+
driver.driver.rotate :landscape
|
44
|
+
end
|
45
|
+
|
46
|
+
def portrait
|
47
|
+
driver.driver.rotate :portrait
|
48
|
+
end
|
49
|
+
|
50
|
+
def back
|
51
|
+
driver.back
|
52
|
+
end
|
53
|
+
|
54
|
+
def wait_until(timeout = 5, message = nil, &block)
|
55
|
+
wait = Selenium::WebDriver::Wait.new(timeout: timeout, message: message)
|
56
|
+
wait.until &block
|
57
|
+
end
|
58
|
+
|
59
|
+
def wait_step(timeout = 5, message = nil, &block)
|
60
|
+
default_wait = driver.default_wait
|
61
|
+
wait = Selenium::WebDriver::Wait.new(:timeout => driver.set_wait(timeout), :message => message)
|
62
|
+
wait.until &block
|
63
|
+
driver.set_wait(default_wait)
|
64
|
+
end
|
65
|
+
|
66
|
+
def enter
|
67
|
+
#pending implementation
|
68
|
+
end
|
69
|
+
|
70
|
+
def scroll_down_find(locator,locator_value,num_loop = 15)
|
71
|
+
scr = driver.window_size
|
72
|
+
screenHeightStart = (scr.height) * 0.5
|
73
|
+
scrollStart = screenHeightStart.to_i
|
74
|
+
screenHeightEnd = (scr.height) * 0.2
|
75
|
+
scrollEnd = screenHeightEnd.to_i
|
76
|
+
for i in 0..num_loop
|
77
|
+
begin
|
78
|
+
if (driver.find_element(locator,locator_value).displayed?)
|
79
|
+
break
|
80
|
+
end
|
81
|
+
rescue
|
82
|
+
driver.swipe(:start_x => 0,:start_y => scrollStart,:end_x =>0,:end_y =>scrollEnd,:touchCount => 2,:duration => 0)
|
83
|
+
false
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def scroll_down_click(locator,locator_value,num_loop = 15)
|
89
|
+
scr = driver.window_size
|
90
|
+
screenHeightStart = (scr.height) * 0.5
|
91
|
+
scrollStart = screenHeightStart.to_i
|
92
|
+
screenHeightEnd = (scr.height) * 0.2
|
93
|
+
scrollEnd = screenHeightEnd.to_i
|
94
|
+
for i in 0..num_loop
|
95
|
+
begin
|
96
|
+
if (driver.find_element(locator,locator_value).displayed?)
|
97
|
+
driver.find_element(locator,locator_value).click
|
98
|
+
break
|
99
|
+
end
|
100
|
+
rescue
|
101
|
+
driver.swipe(:start_x => 0,:start_y => scrollStart,:end_x =>0,:end_y =>scrollEnd,:touchCount => 2,:duration => 0)
|
102
|
+
false
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def scroll_up_find(locator,locator_value,num_loop = 15)
|
108
|
+
scr = driver.window_size
|
109
|
+
screenHeightStart = (scr.height) * 0.5
|
110
|
+
scrollStart = screenHeightStart.to_i
|
111
|
+
screenHeightEnd = (scr.height) * 0.2
|
112
|
+
scrollEnd = screenHeightEnd.to_i
|
113
|
+
for i in 0..num_loop
|
114
|
+
begin
|
115
|
+
if (driver.find_element(locator,locator_value).displayed?)
|
116
|
+
break
|
117
|
+
end
|
118
|
+
rescue
|
119
|
+
driver.swipe(:start_x => 0,:start_y => scrollEnd,:end_x =>0,:end_y =>scrollStart,:touchCount => 2,:duration => 0)
|
120
|
+
false
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
def scroll_up_click(locator,locator_value,num_loop = 15)
|
127
|
+
scr = driver.window_size
|
128
|
+
screenHeightStart = (scr.height) * 0.5
|
129
|
+
scrollStart = screenHeightStart.to_i
|
130
|
+
screenHeightEnd = (scr.height) * 0.2
|
131
|
+
scrollEnd = screenHeightEnd.to_i
|
132
|
+
for i in 0..num_loop
|
133
|
+
begin
|
134
|
+
if (driver.find_element(locator,locator_value).displayed?)
|
135
|
+
driver.find_element(locator,locator_value).click
|
136
|
+
break
|
137
|
+
end
|
138
|
+
rescue
|
139
|
+
driver.swipe(:start_x => 0,:start_y => scrollEnd,:end_x =>0,:end_y =>scrollStart,:touchCount => 2,:duration => 0)
|
140
|
+
false
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
def drag_and_drop_element(source_locator,source_locator_value,target_locator,target_locator_value)
|
147
|
+
l_draggable = driver.find_element(source_locator,source_locator_value)
|
148
|
+
l_droppable = driver.find_element(target_locator,target_locator_value)
|
149
|
+
obj1= Appium::TouchAction.new
|
150
|
+
obj1.long_press(:x => l_draggable.location.x,:y => l_draggable.location.y).move_to(:x => l_droppable.location.x,:y => l_droppable.location.y).release.perform
|
151
|
+
end
|
152
|
+
|
153
|
+
def keyboard_hide
|
154
|
+
begin
|
155
|
+
driver.hide_keyboard
|
156
|
+
rescue
|
157
|
+
false
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|