snapshot 1.16.2 → 1.16.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +39 -31
- data/lib/assets/SnapshotHelper.swift +1 -1
- data/lib/assets/SnapshotHelper2-3.swift +1 -1
- data/lib/snapshot/dependency_checker.rb +1 -1
- data/lib/snapshot/reports_generator.rb +2 -0
- data/lib/snapshot/runner.rb +6 -2
- data/lib/snapshot/version.rb +1 -1
- metadata +26 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70abd64b29b5646bd7ff8d9d047ef7ccd1738788
|
4
|
+
data.tar.gz: 704d63b601b0b03a5174c1fca805360c8eb3585a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a753bf566dcb00ba9a760a14455521cb301b9a80014592ac7fdafbf0c70ff6ad864c1b4f6fbafd0bdc5c103480c99139f05f9524d91198a2045a044d44a5d3a
|
7
|
+
data.tar.gz: dbe4f50c958ee5d19c41803dc0a8dd93f69d595401f3c56565e706d699606c716877b2ce75732801fda46a958748acdb59311b974a9cbd94fd50d915040fd73d
|
data/README.md
CHANGED
@@ -35,7 +35,13 @@ snapshot
|
|
35
35
|
|
36
36
|
###### Automate taking localized screenshots of your iOS app on every device
|
37
37
|
|
38
|
-
|
38
|
+
<hr />
|
39
|
+
<h4 align="center">
|
40
|
+
Check out the new <a href="https://docs.fastlane.tools/getting-started/ios/screenshots">fastlane documentation</a> on how to generate screenshots
|
41
|
+
</h4>
|
42
|
+
<hr />
|
43
|
+
|
44
|
+
_snapshot_ generates localized iOS screenshots for different device types and languages for the App Store and can be uploaded using ([`deliver`](https://github.com/fastlane/fastlane/tree/master/deliver)).
|
39
45
|
|
40
46
|
You have to manually create 20 (languages) x 6 (devices) x 5 (screenshots) = **600 screenshots**.
|
41
47
|
|
@@ -49,7 +55,7 @@ It's hard to get everything right!
|
|
49
55
|
|
50
56
|
More information about [creating perfect screenshots](https://krausefx.com/blog/creating-perfect-app-store-screenshots-of-your-ios-app).
|
51
57
|
|
52
|
-
|
58
|
+
_snapshot_ runs completely in the background - you can do something else, while your computer takes the screenshots for you.
|
53
59
|
|
54
60
|
Get in contact with the developer on Twitter: [@FastlaneTools](https://twitter.com/FastlaneTools)
|
55
61
|
|
@@ -67,7 +73,7 @@ Get in contact with the developer on Twitter: [@FastlaneTools](https://twitter.c
|
|
67
73
|
|
68
74
|
-------
|
69
75
|
|
70
|
-
<h5 align="center"><code>snapshot</code> is part of <a href="https://fastlane.tools">fastlane</a>: The easiest way to automate
|
76
|
+
<h5 align="center"><code>snapshot</code> is part of <a href="https://fastlane.tools">fastlane</a>: The easiest way to automate beta deployments and releases for your iOS and Android apps.</h5>
|
71
77
|
|
72
78
|
# Features
|
73
79
|
- Create hundreds of screenshots in multiple languages on all simulators
|
@@ -75,11 +81,11 @@ Get in contact with the developer on Twitter: [@FastlaneTools](https://twitter.c
|
|
75
81
|
- Do something else, while the computer takes the screenshots for you
|
76
82
|
- Integrates with [`fastlane`](https://fastlane.tools) and [`deliver`](https://github.com/fastlane/fastlane/tree/master/deliver)
|
77
83
|
- Generates a beautiful web page, which shows all screenshots on all devices. This is perfect to send to Q&A or the marketing team
|
78
|
-
-
|
84
|
+
- _snapshot_ automatically waits for network requests to be finished before taking a screenshot (we don't want loading images in the App Store screenshots)
|
79
85
|
|
80
86
|
##### [Like this tool? Be the first to know about updates and new fastlane tools](https://tinyletter.com/krausefx)
|
81
87
|
|
82
|
-
After
|
88
|
+
After _snapshot_ successfully created new screenshots, it will generate a beautiful HTML file to get a quick overview of all screens:
|
83
89
|
|
84
90
|
![assets/htmlPagePreviewFade.jpg](assets/htmlPagePreviewFade.jpg)
|
85
91
|
|
@@ -150,7 +156,7 @@ XCUIApplication *app = [[XCUIApplication alloc] init];
|
|
150
156
|
|
151
157
|
![assets/snapshot.gif](assets/snapshot.gif)
|
152
158
|
|
153
|
-
You can try the
|
159
|
+
You can try the _snapshot_ [example project](https://github.com/fastlane/fastlane/tree/master/snapshot/example) by cloning this repo.
|
154
160
|
|
155
161
|
To quick start your UI tests, you can use the UI Test recorder. You only have to interact with the simulator, and Xcode will generate the UI Test code for you. You can find the red record button on the bottom of the screen (more information in [this blog post](https://krausefx.com/blog/run-xcode-7-ui-tests-from-the-command-line))
|
156
162
|
|
@@ -162,13 +168,13 @@ snapshot
|
|
162
168
|
|
163
169
|
Your screenshots will be stored in the `./screenshots/` folder by default (or `./fastlane/screenshots` if you're using [fastlane](https://fastlane.tools))
|
164
170
|
|
165
|
-
If any error occurs while running the snapshot script on a device, that device will not have any screenshots, and
|
171
|
+
If any error occurs while running the snapshot script on a device, that device will not have any screenshots, and _snapshot_ will continue with the next device or language. To stop the flow after the first error, run
|
166
172
|
|
167
173
|
```sh
|
168
174
|
snapshot --stop_after_first_error
|
169
175
|
```
|
170
176
|
|
171
|
-
Also by default,
|
177
|
+
Also by default, _snapshot_ will open the HTML after all is done. This can be skipped with the following command
|
172
178
|
|
173
179
|
|
174
180
|
```sh
|
@@ -181,19 +187,19 @@ There are a lot of options available that define how to build your app, for exam
|
|
181
187
|
snapshot --scheme "UITests" --configuration "Release" --sdk "iphonesimulator"
|
182
188
|
```
|
183
189
|
|
184
|
-
Reinstall the app before running
|
190
|
+
Reinstall the app before running _snapshot_
|
185
191
|
|
186
192
|
```sh
|
187
193
|
snapshot --reinstall_app --app_identifier "tools.fastlane.app"
|
188
194
|
```
|
189
195
|
|
190
|
-
By default
|
196
|
+
By default _snapshot_ automatically retries running UI Tests if they fail. This is due to randomly failing UI Tests (e.g. [#372](https://github.com/fastlane/snapshot/issues/372)). You can adapt this number using
|
191
197
|
|
192
198
|
```sh
|
193
199
|
snapshot --number_of_retries 3
|
194
200
|
```
|
195
201
|
|
196
|
-
Add photos and/or videos to the simulator before running
|
202
|
+
Add photos and/or videos to the simulator before running _snapshot_
|
197
203
|
|
198
204
|
```sh
|
199
205
|
snapshot --add_photos MyTestApp/Assets/demo.jpg --add_videos MyTestApp/Assets/demo.mp4
|
@@ -205,7 +211,7 @@ For a list for all available options run
|
|
205
211
|
snapshot --help
|
206
212
|
```
|
207
213
|
|
208
|
-
After running
|
214
|
+
After running _snapshot_ you will get a nice summary:
|
209
215
|
|
210
216
|
<img src="assets/testSummary.png" width="500">
|
211
217
|
|
@@ -254,13 +260,13 @@ You can run this command in the terminal to delete and re-create all iOS simulat
|
|
254
260
|
snapshot reset_simulators
|
255
261
|
```
|
256
262
|
|
257
|
-
**Warning**: This will delete **all** your simulators and replace by new ones! This is useful, if you run into weird problems when running
|
263
|
+
**Warning**: This will delete **all** your simulators and replace by new ones! This is useful, if you run into weird problems when running _snapshot_.
|
258
264
|
|
259
265
|
You can use the environment variable `SNAPSHOT_FORCE_DELETE` to stop asking for confirmation before deleting.
|
260
266
|
|
261
267
|
## Update snapshot helpers
|
262
268
|
|
263
|
-
Some updates require the helper files to be updated.
|
269
|
+
Some updates require the helper files to be updated. _snapshot_ will automatically warn you and tell you how to update.
|
264
270
|
|
265
271
|
Basically you can run
|
266
272
|
|
@@ -285,7 +291,7 @@ name.text = NSUserDefaults.standardUserDefaults().stringForKey("firstName")
|
|
285
291
|
// name.text = "Felix"
|
286
292
|
```
|
287
293
|
|
288
|
-
|
294
|
+
_snapshot_ includes `-FASTLANE_SNAPSHOT YES`, which will set a temporary user default for the key `FASTLANE_SNAPSHOT`, you may use this to detect when the app is run by _snapshot_.
|
289
295
|
|
290
296
|
```swift
|
291
297
|
if NSUserDefaults.standardUserDefaults().boolForKey("FASTLANE_SNAPSHOT") {
|
@@ -293,7 +299,7 @@ if NSUserDefaults.standardUserDefaults().boolForKey("FASTLANE_SNAPSHOT") {
|
|
293
299
|
}
|
294
300
|
```
|
295
301
|
|
296
|
-
Specify multiple argument strings and
|
302
|
+
Specify multiple argument strings and _snapshot_ will generate screenshots for each combination of arguments, devices, and languages. This is useful for comparing the same screenshots with different feature flags, dynamic text sizes, and different data sets.
|
297
303
|
|
298
304
|
```ruby
|
299
305
|
# Snapfile for A/B Test Comparison
|
@@ -305,24 +311,24 @@ launch_arguments([
|
|
305
311
|
|
306
312
|
# How does it work?
|
307
313
|
|
308
|
-
The easiest solution would be to just render the UIWindow into a file. That's not possible because UI Tests don't run on a main thread. So
|
314
|
+
The easiest solution would be to just render the UIWindow into a file. That's not possible because UI Tests don't run on a main thread. So _snapshot_ uses a different approach:
|
309
315
|
|
310
|
-
When you run unit tests in Xcode, the reporter generates a plist file, documenting all events that occurred during the tests ([More Information](http://michele.io/test-logs-in-xcode)). Additionally, Xcode generates screenshots before, during and after each of these events. There is no way to manually trigger a screenshot event. The screenshots and the plist files are stored in the DerivedData directory, which
|
316
|
+
When you run unit tests in Xcode, the reporter generates a plist file, documenting all events that occurred during the tests ([More Information](http://michele.io/test-logs-in-xcode)). Additionally, Xcode generates screenshots before, during and after each of these events. There is no way to manually trigger a screenshot event. The screenshots and the plist files are stored in the DerivedData directory, which _snapshot_ stores in a temporary folder.
|
311
317
|
|
312
|
-
When the user calls `snapshot(...)` in the UI Tests (Swift or Objective C) the script actually does a rotation to `.Unknown` which doesn't have any effect on the actual app, but is enough to trigger a screenshot. It has no effect to the application and is not something you would do in your tests. The goal was to find *some* event that a user would never trigger, so that we know it's from
|
318
|
+
When the user calls `snapshot(...)` in the UI Tests (Swift or Objective C) the script actually does a rotation to `.Unknown` which doesn't have any effect on the actual app, but is enough to trigger a screenshot. It has no effect to the application and is not something you would do in your tests. The goal was to find *some* event that a user would never trigger, so that we know it's from _snapshot_. On tvOS, there is no orientation so we ask for a count of app views with type "Browser" (which should never exist on tvOS).
|
313
319
|
|
314
|
-
|
320
|
+
_snapshot_ then iterates through all test events and check where we either did this weird rotation (on iOS) or searched for browsers (on tvOS). Once _snapshot_ has all events triggered by _snapshot_ it collects a ordered list of all the file names of the actual screenshots of the application.
|
315
321
|
|
316
|
-
In the test output, the Swift
|
322
|
+
In the test output, the Swift _snapshot_ function will print out something like this
|
317
323
|
|
318
324
|
> snapshot: [some random text here]
|
319
325
|
|
320
|
-
|
326
|
+
_snapshot_ finds all these entries using a regex. The number of _snapshot_ outputs in the terminal and the number of _snapshot_ events in the plist file should be the same. Knowing that, _snapshot_ automatically matches these 2 lists to identify the name of each of these screenshots. They are then copied over to the output directory and separated by language and device.
|
321
327
|
|
322
|
-
2 thing have to be passed on from
|
328
|
+
2 thing have to be passed on from _snapshot_ to the `xcodebuild` command line tool:
|
323
329
|
|
324
330
|
- The device type is passed via the `destination` parameter of the `xcodebuild` parameter
|
325
|
-
- The language is passed via a temporary file which is written by
|
331
|
+
- The language is passed via a temporary file which is written by _snapshot_ before running the tests and read by the UI Tests when launching the application
|
326
332
|
|
327
333
|
If you find a better way to do any of this, please submit an issue on GitHub or even a pull request :+1:
|
328
334
|
|
@@ -330,9 +336,15 @@ Also, feel free to duplicate radar [23062925](https://openradar.appspot.com/rada
|
|
330
336
|
|
331
337
|
# Tips
|
332
338
|
|
339
|
+
<hr />
|
340
|
+
<h4 align="center">
|
341
|
+
Check out the new <a href="https://docs.fastlane.tools/getting-started/ios/screenshots">fastlane documentation</a> on how to generate screenshots
|
342
|
+
</h4>
|
343
|
+
<hr />
|
344
|
+
|
333
345
|
## [`fastlane`](https://fastlane.tools) Toolchain
|
334
346
|
|
335
|
-
- [`fastlane`](https://fastlane.tools): The easiest way to automate
|
347
|
+
- [`fastlane`](https://fastlane.tools): The easiest way to automate beta deployments and releases for your iOS and Android apps
|
336
348
|
- [`deliver`](https://github.com/fastlane/fastlane/tree/master/deliver): Upload screenshots, metadata and your app to the App Store
|
337
349
|
- [`frameit`](https://github.com/fastlane/fastlane/tree/master/frameit): Quickly put your screenshots into the right device frames
|
338
350
|
- [`PEM`](https://github.com/fastlane/fastlane/tree/master/pem): Automatically generate and renew your push notification profiles
|
@@ -374,17 +386,13 @@ When the app dies directly after the application is launched there might be 2 pr
|
|
374
386
|
|
375
387
|
## Determine language
|
376
388
|
|
377
|
-
To detect the currently used localization in your tests,
|
378
|
-
|
379
|
-
```javascript
|
380
|
-
You can access the language using the `deviceLanguage` variable.
|
381
|
-
```
|
389
|
+
To detect the currently used localization in your tests, access the `deviceLanguage` variable from `SnapshotHelper.swift`.
|
382
390
|
|
383
391
|
# Need help?
|
384
392
|
Please submit an issue on GitHub and provide information about your setup
|
385
393
|
|
386
394
|
# Code of Conduct
|
387
|
-
Help us keep
|
395
|
+
Help us keep _snapshot_ open and inclusive. Please read and follow our [Code of Conduct](https://github.com/fastlane/fastlane/blob/master/CODE_OF_CONDUCT.md).
|
388
396
|
|
389
397
|
# License
|
390
398
|
This project is licensed under the terms of the MIT license. See the LICENSE file.
|
@@ -107,7 +107,7 @@ open class Snapshot: NSObject {
|
|
107
107
|
|
108
108
|
class func waitForLoadingIndicatorToDisappear() {
|
109
109
|
#if os(tvOS)
|
110
|
-
return
|
110
|
+
return
|
111
111
|
#endif
|
112
112
|
|
113
113
|
let query = XCUIApplication().statusBars.children(matching: .other).element(boundBy: 1).children(matching: .other)
|
@@ -109,7 +109,7 @@ public class Snapshot: NSObject {
|
|
109
109
|
|
110
110
|
class func waitForLoadingIndicatorToDisappear() {
|
111
111
|
#if os(tvOS)
|
112
|
-
return
|
112
|
+
return
|
113
113
|
#endif
|
114
114
|
|
115
115
|
let query = XCUIApplication().statusBars.childrenMatchingType(.Other).elementBoundByIndex(1).childrenMatchingType(.Other)
|
@@ -10,7 +10,7 @@ module Snapshot
|
|
10
10
|
def self.check_xcode_select
|
11
11
|
unless `xcode-select -v`.include? "xcode-select version"
|
12
12
|
UI.error '#############################################################'
|
13
|
-
UI.error "# You have to install
|
13
|
+
UI.error "# You have to install Xcode command line tools to use snapshot"
|
14
14
|
UI.error "# Install the latest version of Xcode from the AppStore"
|
15
15
|
UI.error "# Run xcode-select --install to install the developer tools"
|
16
16
|
UI.error '#############################################################'
|
@@ -53,6 +53,8 @@ module Snapshot
|
|
53
53
|
# and the iPhone 6 is inlucded in the iPhone 6 Plus
|
54
54
|
{
|
55
55
|
'AppleTV1080p' => 'Apple TV',
|
56
|
+
'iPhone7Plus' => "iPhone7Plus (5.5-Inch)",
|
57
|
+
'iPhone7' => "iPhone7 (4.7-Inch)",
|
56
58
|
'iPhone6sPlus' => "iPhone6sPlus (5.5-Inch)",
|
57
59
|
'iPhone6Plus' => "iPhone6Plus (5.5-Inch)",
|
58
60
|
'iPhone6s' => "iPhone6s (4.7-Inch)",
|
data/lib/snapshot/runner.rb
CHANGED
@@ -13,7 +13,7 @@ module Snapshot
|
|
13
13
|
if File.exist?("./fastlane/snapshot.js") or File.exist?("./snapshot.js")
|
14
14
|
UI.error "Found old snapshot configuration file 'snapshot.js'"
|
15
15
|
UI.error "You updated to snapshot 1.0 which now uses UI Automation"
|
16
|
-
UI.error "Please follow the migration guide: https://github.com/fastlane/
|
16
|
+
UI.error "Please follow the migration guide: https://github.com/fastlane/fastlane/blob/master/snapshot/MigrationGuide.md"
|
17
17
|
UI.error "And read the updated documentation: https://github.com/fastlane/fastlane/tree/master/snapshot"
|
18
18
|
sleep 3 # to be sure the user sees this, as compiling clears the screen
|
19
19
|
end
|
@@ -22,7 +22,11 @@ module Snapshot
|
|
22
22
|
|
23
23
|
verify_helper_is_current
|
24
24
|
|
25
|
-
|
25
|
+
# Also print out the path to the used Xcode installation
|
26
|
+
# We go 2 folders up, to not show "Contents/Developer/"
|
27
|
+
values = Snapshot.config.values(ask: false)
|
28
|
+
values[:xcode_path] = File.expand_path("../..", FastlaneCore::Helper.xcode_path)
|
29
|
+
FastlaneCore::PrintTable.print_values(config: values, hide_keys: [], title: "Summary for snapshot #{Snapshot::VERSION}")
|
26
30
|
|
27
31
|
clear_previous_screenshots if Snapshot.config[:clear_previous_screenshots]
|
28
32
|
|
data/lib/snapshot/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: snapshot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.16.
|
4
|
+
version: 1.16.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Felix Krause
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-10-
|
11
|
+
date: 2016-10-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fastimage
|
@@ -30,7 +30,7 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
33
|
+
version: 0.53.0
|
34
34
|
- - "<"
|
35
35
|
- !ruby/object:Gem::Version
|
36
36
|
version: 1.0.0
|
@@ -40,7 +40,7 @@ dependencies:
|
|
40
40
|
requirements:
|
41
41
|
- - ">="
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version: 0.
|
43
|
+
version: 0.53.0
|
44
44
|
- - "<"
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: 1.0.0
|
@@ -50,28 +50,40 @@ dependencies:
|
|
50
50
|
requirements:
|
51
51
|
- - ">="
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: 0.2.
|
53
|
+
version: 0.2.4
|
54
|
+
- - "<"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 1.0.0
|
54
57
|
type: :runtime
|
55
58
|
prerelease: false
|
56
59
|
version_requirements: !ruby/object:Gem::Requirement
|
57
60
|
requirements:
|
58
61
|
- - ">="
|
59
62
|
- !ruby/object:Gem::Version
|
60
|
-
version: 0.2.
|
63
|
+
version: 0.2.4
|
64
|
+
- - "<"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 1.0.0
|
61
67
|
- !ruby/object:Gem::Dependency
|
62
68
|
name: plist
|
63
69
|
requirement: !ruby/object:Gem::Requirement
|
64
70
|
requirements:
|
65
|
-
- - "
|
71
|
+
- - ">="
|
66
72
|
- !ruby/object:Gem::Version
|
67
73
|
version: 3.1.0
|
74
|
+
- - "<"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 4.0.0
|
68
77
|
type: :runtime
|
69
78
|
prerelease: false
|
70
79
|
version_requirements: !ruby/object:Gem::Requirement
|
71
80
|
requirements:
|
72
|
-
- - "
|
81
|
+
- - ">="
|
73
82
|
- !ruby/object:Gem::Version
|
74
83
|
version: 3.1.0
|
84
|
+
- - "<"
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: 4.0.0
|
75
87
|
- !ruby/object:Gem::Dependency
|
76
88
|
name: bundler
|
77
89
|
requirement: !ruby/object:Gem::Requirement
|
@@ -185,33 +197,33 @@ dependencies:
|
|
185
197
|
- !ruby/object:Gem::Version
|
186
198
|
version: '0'
|
187
199
|
- !ruby/object:Gem::Dependency
|
188
|
-
name:
|
200
|
+
name: webmock
|
189
201
|
requirement: !ruby/object:Gem::Requirement
|
190
202
|
requirements:
|
191
203
|
- - "~>"
|
192
204
|
- !ruby/object:Gem::Version
|
193
|
-
version:
|
205
|
+
version: 1.19.0
|
194
206
|
type: :development
|
195
207
|
prerelease: false
|
196
208
|
version_requirements: !ruby/object:Gem::Requirement
|
197
209
|
requirements:
|
198
210
|
- - "~>"
|
199
211
|
- !ruby/object:Gem::Version
|
200
|
-
version:
|
212
|
+
version: 1.19.0
|
201
213
|
- !ruby/object:Gem::Dependency
|
202
|
-
name:
|
214
|
+
name: rubocop
|
203
215
|
requirement: !ruby/object:Gem::Requirement
|
204
216
|
requirements:
|
205
217
|
- - "~>"
|
206
218
|
- !ruby/object:Gem::Version
|
207
|
-
version:
|
219
|
+
version: 0.44.0
|
208
220
|
type: :development
|
209
221
|
prerelease: false
|
210
222
|
version_requirements: !ruby/object:Gem::Requirement
|
211
223
|
requirements:
|
212
224
|
- - "~>"
|
213
225
|
- !ruby/object:Gem::Version
|
214
|
-
version:
|
226
|
+
version: 0.44.0
|
215
227
|
description: Automate taking localized screenshots of your iOS app on every device
|
216
228
|
email:
|
217
229
|
- snapshot@krausefx.com
|