Rupert Anderson's Blog

Mainly SoapUI, API, Open Source stuff and Elite Dangerous!

5500Lyr Passenger Site Seeing Mission

Brief

I’ve done a fair few passenger sight seeing missions mainly just for the money and in the interests of quick turn around, stayed under 250Lyr for each target for multi hops etc. This time I wanted to go beyond the 1000Lyr navigation limit and learn to plot a longer route whilst improving my exploration experience.

Passenger Mission Target Reached

Passenger Mission Target Reached!

The Passenger Mission

  • Finally picked out a longer range passenger mission – 2765.97Ls to see an earth like world / secretive (no scans) / but normal in other respects, not a criminal or wanted. 3W 6D 23H to do it. 7 first class passengers.
  • Kitted out the Asp Explorer for long distance – TODO provide loadout, was nothing fancy, with the class 6 passenger cabin it could only jump about 29Lyrs max, so probably wasn’t that stripped out in terms of modules.
  • Since its longer than 1000Ls, used Neutron Router (Neutron Router) to break it into 1000Ls chunks
Elite Dangerous Neutron Router

Elite Dangerous Neutron Router

Ship Condition & Learnings Afterwards

  • Down to 95% hull due to 4 emergency stops whilst scooping across the journey
  • Some heat damage across modules (AFM modules not used to repair):
  • Elite Dangerous - exploration module damage
  • All heat sinks used – very useful when a mistake is made scooping or jumping too close to the star. Next time I’ll take more than 1 set due to their usefulness and limited ammo.
  • Taking a passenger provides a target destination and money, but potentially narrows the exploration to a there-and-back on a schedule – think I would enjoy the exploration more if the passenger aspect wasn’t in the back of my mind, would probably wander more.

The Rewards

  • 11,637,360 Credits (includes bonus for avoiding a scan on the return journey)
  • About 1.8Mil Credits of scans including many sheets of first discovered bonuses
  • Elite Dangerous - explorer first discovery
  • Jumped from rank Scout (80%) through Trailblazer to Pathfinder (80%)
  • This was my first major exploration into uninhabited space – enjoyed it!

Mining pristine rings in an unpopulated anarchy

Exploring LHS 2661

Exploring LHS 2661 In My DBX

The Location

My current chosen home world is Belobog. Have been mining Major reserve asteroid belts at Sango, this was pretty easy going and quite profitable. To step things up, I wanted to try a pristine reserve. The only pristine reserves I’d found during exploration were about 100Lyrs away, near Lave, and that was just a metal rich belt. So, to save time I found a list of close by systems with pristine reserves on http://edtools.ddns.net/ – LHS 2661 was the closest, at around 40Lyrs. Being unpopulated and unexplored, it looked like just the kind of weird place I like! The round-trip from Belobog wouldn’t be that far being just 2 hops with my T6‘s 4A hyperdrive. Also, I don’t fit a scoop, so the round trip is well within a full tank (no station there to fill up). Target pristine system found!

Next, since the system was unexplored, I had no idea exactly what kind of pristine reserves were present on LHS 2661, as no system map was available. So I readied up my DBX and set off. The place seemed deceptively peaceful, I managed to scan all bodies without seeing a single other ship. The exploration was a success, revealing multiple metal rich belts and better a single pristine metallic ring on the further gas giant! The metallic ring is on the furthest planet (about 2500Ls away for the White Drawf you jump into too), but thats OK, it only takes a couple of minutes with nothing much to slow your supercruise.

Mining There

Compared to a populated system, there seem to be no ships flying around when in supercruise. Also there are no RES sites, you must manually drop into rings at low speed to avoid hull damage – I stay under 100Km/s, not sure how much faster you can go safely. In terms of the actual mining, it’s been way better than anything I’ve experienced so far. The concentrations much higher than in Major reserves (occasionally up to 55%, often 25-35%) and some nice mixes like 25% Osmium and 25% Platinum, plus a bit of Panite every so often. I probably won’t go back to non-pristine reserves after now.

Pirates!
Despite the system seeming devoid of ships, pirates show up within minutes of dropping in. Luckily, if you only have limpets in your hold, they just scan you, insult you and leave, never to hassle you again. However, if you happen to have anything else in your hold, things can turn bad very quickly! Even with my Asp Explorer, running seems to be the only option, as the type of pirates that have picked on me so far (always a wing, Viper/Cobra/Imperial Clipper/Asp Explorer/Federal Dropship) would be too tough to risk fighting in a mining setup (limited hardpoints, 3A shields and no armour). Also, you will be mass locked, meaning evasive action and boosting is necessary for a while before a jump is possible (got taken down to 55% hull once). So, the safe course of action if you want to mine in peace seems to be:

  1. Don’t carry anything but limpets
  2. Drop into the ring
  3. Fly close to it and start prospecting, but don’t mine anything yet
  4. When the pirates show up, let them scan you and leave
  5. Once they leave the area, they never seem to return
  6. Mine in peace and prosper!

Sometimes you also see other NPC miners, these seem to remain in the vicinity happily mining away. Once, after a pirate scanned me, they flew off and ‘lit up’ the poor NPC miner, causing him to run away under heavy fire!

Replace Request In REST TestSteps SoapUI Plugin

Say you have the following scenario:

  1. A SoapUI REST Project defining a Service / Resource / Method / Request
  2. Have generated lots of REST Request TestSteps from it
  3. Then later you need to update the request content in the service definition
  4. And need all related TestSteps to also have their request content updated across all your TestSuites and TestCases  in the project?

Then you could manually update them, maybe write a script or even edit the project definition XML… or you could try this new SoapUI Plugin!

What It Does

  • Adds a new menu item under the REST request menu
  • When clicked this finds all TestSteps that were generated from the REST request
  • Replaces the found TestSteps request content with the content from the REST request
  • Only the request content for matching TestSteps is replaced, no other objects are changed

Usage

Here’s an example:

1. Consider the following small sample REST project:

  • There are 4 requests under resource1, lets pick Request 4.
  • Request 4 has two related REST Test Request TestSteps, both called Method3 – Request 4, one under TestCase 1 and the other under TestCase 2.
  • Then we edit the request content for Request 4.

2.Then to replace the request content in the 2 related TestSteps with the Request 4 request content:

  • Right-click on Request 4
  • Select the new menu item Replace Request In All TestStep(s)

3. Then you should see the the following message:

At this point:

  • The 2 Request 4 related TestSteps should have their request content replaced with Request 4s
  • No other TestSteps should be affected.

4. Alternatively, if you try this on a request with no related TestSteps (like Request 2), then you should see the message:

At this point nothing will be changed.

Installation

  • Please refer to the build and deployment steps on the GitHub project page https://github.com/bearsoftware/ReplaceRequestInAllTestStepsAction
  • The first time you run the build, lots of SoapUI dependencies will be automatically downloaded and tests run, this might take a couple of minutes.
  • I tested the custom action against SoapUI 5.3.0, but it should work on other versions.

Development Approach

The approach I am going to take is:

  • Phase 1 (Done!) : First develop and trial the functionality as a SoapUI custom Action extension – this has allowed me to focus on the getting the core functionality ready for evaluation with the minimum focus on packaging.
  • Phase 2 (Future Option) : Repackage the functionality as a SoapUI Plugin jar as a slightly neater option.
  • Phase 3 (Future Option) : If the functionality seems popular and useful, I could make a pull request integrate the action code directly code into the SoapUI GitHub project as standard functionality.

Notes

In terms of limitations / further thoughts:

  • At this stage this functionality should really be referred to as a SoapUI custom Action, rather than a plugin – I decided to call it a plugin because I may soon provide a way to repackage it as one (Phase 2).
  • Currently only the request content gets replaced, not changes to the the parameters or media type – if this would be useful it could be added?
  • I haven’t done any performance tests e.g. replaced 100 TestSteps, although I can – please let me know if you see any problems.

I’ve linked to this blog article from the SoapUI O/S Feature Request. Please let me know if there are any questions / issues / suggestions that you have either here or on the feature request. Thanks!

R2-Using SoapUI Groovy Grape dependencies

Scenario

If you want to use a Groovy or Java library that isn’t bundled with SoapUI, then the standard way is to add it to /bin/ext and restart SoapUI, as per Recipe R1. A slick alternative approach is to use the Groovy Grape dependency manager to add Maven repository artefacts as part of your Groovy Scripts on-the-fly!

Why bother?

There’s no compelling reason to use Grape over the standard way to include dependencies. However a different approach can sometimes present its own opportunities, some differences and possible advantages are:

  • Grape dependencies can be added at runtime without a restart.
  • Grape driven scripts are self contained and document their own dependencies.
  • Grape dependencies are managed and centralised by Groovy rather than SoapUI (see the More section).
  • Ease of use – there’s no need to manually download or package Grape dependencies.

Prep

Recipe Test Version Info:
SoapUI 5.2.1 (standard distribution / installer)
O/S: Windows 10
Java: Bundled JRE

Other: ivy-2.1.0.jar,ivy-2.4.0.jar,jsoup-1.9.2.jar,jsoup-1.10.1.jar

Project Setup
To try this out, we just need somewhere to run a Groovy script within SoapUI e.g. a Groovy TestStep.

Steps

1.Create A Groovy script with unresolved dependencies
Create a script that needs a dependency that SoapUI doesn’t already have in its /lib folder. In this example, I picked a script that requires libraries from the HTML parser JSoup. The script just parses an HTML string and extracts the anchor tag and displays it in a popup (once we satisfy all its dependencies).

import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element

def html = "<p>An <a href='http://rupertanderson.com/'><b>example</b></a> link.</p>"
Document doc = Jsoup.parse(html)
Element link = doc.select("a").first()

log.info link

2. (Optional) Test that the dependency is initially unresolved
As a test to make sure that the dependency doesn’t already exist within SoapUI’s classpath, run the above script to verify that the required imports are not resolved. You should see a SoapUI Error popup containing something like:

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed: Script2.groovy: 3: unable to resolve class org.jsoup.nodes.Document @ line 3, column 1. import org.jsoup.nodes.Document ^ org.codehaus.groovy.syntax.SyntaxException: unable to resolve class….

3. Add Ivy jar
Unfortunately we can’t use Grape without first adding the Ivy jar. At time of writing the latest version of ivy is ivy-2.4.0.jar, this can be obtained from:

https://mvnrepository.com/artifact/org.apache.ivy/ivy/2.4.0

For classpath reasons this needs to be added to /lib (not /bin/ext/) otherwise you will see the error:

SoapUI missing Ivy dependency

3. Add a Grape statement

To get the script working, we need to use Grapes to include the JSoup dependency. Again, Maven Central can help us, as it provides a useful Grapes tab with the syntax we need:

// https://mvnrepository.com/artifact/org.jsoup/jsoup
@Grapes(
@Grab(group='org.jsoup', module='jsoup', version='1.10.1')
)

Then paste this in above the imports like so:

@Grab(group='org.jsoup', module='jsoup', version='1.10.1')
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element

def html = "<p>An <a href='http://rupertanderson.com/'><b>example</b></a> link.</p>"
Document doc = Jsoup.parse(html)
Element link = doc.select("a").first()

log.info link

4.Run the script successfully!
Run again, and you should see the anchor tag from within the html variable extracted and output in the log:

<a href="http://rupertanderson.com/"><b>example</b></a>

More

Local Repository

If you were wondering where SoapUI stores the locally cached artefacts when they are downloaded, the default location is:

${user.home}/.groovy/grape 

If you have Groovy installed, then typing the following in a shell:

grape list

Will give you a list of all artefacts cached in the above location.

For configuration options please see:
http://docs.groovy-lang.org/latest/html/documentation/grape.html#Grape-Advancedconfiguration

Feature Request

If you like using the Grape functionality and would like to see Grape dependency management added as part of the standard SoapUI product, then maybe vote for this feature request:

https://community.smartbear.com/t5/SoapUI-Feature-Requests/Adding-Groovy-Grape-dependency-management-out-of-the-box/idi-p/130390

Links

  • For more JSoup examples see https://jsoup.org/cookbook/

Issue/Fix: SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder”

Introduction

This probably a minor issue for most, but the error message isn’t great and it inhibits (sometimes helpful) log messages in certain situations e.g. when running SoapUI from the shell, testrunner scripts and Maven.

Issue

You run SoapUI from the shell / terminal and you see something like:

tests-MacBook-Pro:app test$ ./bin/soapui.sh 
================================
=
= SOAPUI_HOME = /Applications/SoapUI-5.2.1.app/Contents/java/app
=
================================
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Configuring log4j from [/Applications/SoapUI-5.2.1.app/Contents/java/app/bin/soapui-log4j.xml]

Fix

The error just means that no suitable slf4j logger implementation can be found, as per http://www.slf4j.org/codes.html#StaticLoggerBinder – the slf4j-api-1.6.1.jar is there in <SoapUI Home>/app/java/lib already. If no suitable logger implementation is added, then the documentation explains that as of version 1.6, the nop logger implementation will be used – but this doesn’t log anything and you get the warning every time.

There are two main options here depending on how you install/use SoapUI. Taking either option should result in no error and potentially extra logging:


tests-MacBook-Pro:app test$ ./bin/soapui.sh
================================
=
= SOAPUI_HOME = /Applications/SoapUI-5.2.1.app/Contents/java/app
=
================================
Configuring log4j from [/Applications/SoapUI-5.2.1.app/Contents/java/app/bin/soapui-log4j.xml]

Option 1 – SoapUI Was Installed Using The Installer

  1. Pick an slf4j logger implementation from http://mvnrepository.com/artifact/org.slf4j  e.g. download slf4j-simple-1.6.1.jar
  2. Add it to <SoapUI Home>/java/app/lib
  3. Try to run SoapUI again and the error message should be gone and logging may be seen.

Option 2 – SoapUI Built & Run From Source Code (Using Maven)

When building and running SoapUI from source code using maven just add the dependency for the chosen logger implementation (see option 1 – step 1) to the pom.xml for the SoapUI project soapui-project/soapui/pom.xml – for example:

<!-- Logging -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.14</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>1.6.1</version>
</dependency>
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.1.1</version>
</dependency>
<!-- In-app analytics -->

SoapUI Google Analytics NullPointerException On Ubuntu

Hi,

This is just a quick post to consolidate my findings when investigating why a Null Pointer Exception occurs in SoapUI when running on Ubuntu. The error occurs in the analytics code when it tries to obtain the machine’s MAC address. For now, I have hopefully found a quick work around explained below.

I tested this when running SoapUI 5.2.1 (built & run from source code) on a clean install of Ubuntu 14.04.4, Java 1.7u79 and running on VirtualBox.

Problem Description

When starting you may see:

ubuntu-nullpointer-on-startup

Aside from com.eviware.soapui.analytics.AnalyticsManager, a similar error can also be seen in com.eviware.soapui.analytics.providers.GoogleAnalyticsProvider.getMacAddressString when using different areas of functionality.

Looking at either of those classes where the NPE occurs we can see route cause is the same piece of code:


NetworkInterface network = NetworkInterface.getByInetAddress(InetAddress.getLocalHost());
byte mac[] = network.getHardwareAddress();
MessageDigest hasher = MessageDigest.getInstance("SHA-1");
return createHexBinary(hasher.digest(mac));

You can probably see that network is coming back as null.

Investigation

To understand why, and work around the problem, try running a snippet of the same code with logging added e.g. something like:


package com.company;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.security.MessageDigest;

public class Main {

   public static void main(String[] args) {

      try {
         NetworkInterface network = NetworkInterface.getByInetAddress(InetAddress.getLocalHost());
         System.out.println("Machine Name="+ InetAddress.getLocalHost());
         System.out.println("Network Interface="+network);
         byte mac[] = network.getHardwareAddress();
         System.out.println("Mac Address="+mac);
         MessageDigest hasher = MessageDigest.getInstance("SHA-1");
         System.out.println("Hashed Mac"+hasher.digest(mac));
      } 
      catch(Exception e){
         System.out.println("Error generating Analytics session ID - returning empty String"+ e);
      }
   }
}

Depending on how your hosts file / network settings are, you may see something like:


Machine Name=ubuntutest-VirtualBox/127.0.1.1
Network Interface=null
Error generating Analytics session ID - returning empty Stringjava.lang.NullPointerException

The Machine Name will vary on your machine, but the Network Interface can be seen as null and a NullPointerException is caught. The problem seems to be that NetworkInterface.getByInetAddress cannot match the Machine Name to any of the Network Interface values. Running ifconfg shows that there is indeed no match available:


ubuntutest@ubuntutest-VirtualBox:~$ ifconfig
eth0 Link encap:Ethernet HWaddr 07:07:27:79:d2:07
inet addr:10.0.2.30 Bcast:10.0.2.255 Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:fe79:d101/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:21 errors:0 dropped:0 overruns:0 frame:0
TX packets:73 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:3086 (3.0 KB) TX bytes:10810 (10.8 KB)

lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:46 errors:0 dropped:0 overruns:0 frame:0
TX packets:46 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:3559 (3.5 KB) TX bytes:3559 (3.5 KB)

Work-Around

So without fixing the code, one quick solution is to change the /etc/hosts entry for your machine name to use the same IP address as eth0. So in my case, I did something like:


sudo nano /etc/hosts

And added:


10.0.2.30 &nbsp; &nbsp; &nbsp;ubuntutest-VirtualBox

Running the above snippet should then show the Network Interface correctly matched and the Mac Address found e.g.


Machine Name=ubuntutest-VirtualBox/10.0.2.30
Network Interface=name:eth0 (eth0)
Mac Address=[B@520b368f
Hashed Mac[B@4a5e88f7

Note – adding a host entry pointing to lo (127.0.0.1) solves the first problem of matching the Network Interface, but then fails when the code tries to obtain the MAC address with network.getHardwareAddress() – unlike eth0, the interface lo doesn’t have one!

Starting up SoapUI should now occur without the Analytics NPE.

Code Fix

Aside from having / changing your network settings to help the code work, it would probably be better to fix the code in SoapUI to iterate over the possible Network Interfaces until it finds one with a MAC address. I’ll maybe take more of a look at this later.

Comments

There are probably more or even better options for solving this problem, but I just wanted to get some options down in response to various SoapUI Community posts featuring this error for users running on Ubuntu. Hopefully this will help somewhat, please come in with any suggestions / corrections / comments!

Thanks,

Rup

R1-Developing and using custom Groovy libraries In SoapUI

Scenario

So maybe you’ve built up some useful Groovy code for over time that you use again and again, spread across your projects, but would rather manage it from one place? If so, this recipe shows how you can create and import them via jar files so that you can reuse them from SoapUI objects like Groovy TestSteps, Setup/Teardown Scripts and Script Assertions.

Why bother?

  • This way of packaging your Java/Groovy code promotes reuse and can ease the maintainability of your commonly used test code.
  • It is possible to use these libraries to override existing SoapUI code/functionality i.e. create patches.
  • Whilst various recipes in the SoapUI Cookbook show how to use prebuilt Java/Groovy libraries, I felt this was a valid recipe and building block in its own right.

TIP: Quick Start – People who already have a suitable Java/Groovy library and just want to know how to use it in SoapUI, can jump in at step #6

Prep

This recipe uses Groovy and Gradle (v2.12) to compile and package the example Groovy class as a jar file. If you haven’t got Gradle, please refer to http://www.groovy-lang.org/download.html and https://docs.gradle.org/current/userguide/installation.html

For mac/linux I used SDKMAN! (http://sdkman.io/) e.g.

sdk install gradle
sdk install groovy (This is optional, useful if you want to run some Groovy without SoapUI)

Steps

1.Create the following directory structure

soapuilib/src/main/groovy/custom

2.Get some Groovy code

For this example, I have knocked together a simple script to generate sequential ids. It may be of little practical use, but I wanted something with a simple public static method to call. Since the method is static, there will be no need to instantiate the class before calling it in step #8.

 
package custom 

import java.util.concurrent.atomic.AtomicLong 

public class SequentialIdGenerator { 
   public static final long counterSeed = 1000 
   public static final String prefix = "id"
   private static AtomicLong counter = new AtomicLong(counterSeed) 
   
   public static String nextId() { 
     return prefix + counter.incrementAndGet() 
   } 
} 
  • create the above script as a text file called SequentialIdGenerator.groovy
  • copy it to soapuilib/src/main/groovy/custom

3.Create Gradle build script

For this part, there are plenty of options to build the code and package it, such as Maven, Ant or just running the right shell commands! The following minimal Gradle script allows us to compile and package the code as a jar in one easy statement.

apply plugin: 'groovy'

version = '1.0'

jar {
   classifier = 'library'
   manifest {
      attributes 'Implementation-Title': 'SoapUI Sample Groovy Library', 'Implementation-Version': version
   }
}

repositories {
   mavenCentral()
}

dependencies {
   compile 'org.codehaus.groovy:groovy:2.1.7' //Matches Groovy in SoapUI 5.2.1
}

  • Create the above Gradle script as soapuilib/build.gradle
INFO: Groovy Version – (At time of writing) The current version of Groovy is v2.4.6, but SoapUI 5.2.1 ships with Groovy 2.1.7. If you try to compile with a Groovy version 2.3+ and use it with SoapUI, you will see an error popup and log message in like ‘org/codehaus/groovy/runtime/typehandling/ShortTypeHandling‘ – see http://glaforge.appspot.com/article/groovy-2-3-5-out-with-upward-compatibility for more details and options. Basically, you can still use the latest Groovy version, but will need to include an additional groovy-backports-compat23 dependency!

5.Compile it & Create jar file

Now we’re ready to use the Gradle script to compile the sample script from step #2 and package it as a jar file.

  • Open a shell/command prompt at soapuilib/
  • gradle clean build jar

You should then see output like:


tests-MacBook-Pro:soapuilib test$ gradle clean build jar
:clean
:compileJava UP-TO-DATE
:compileGroovy
:processResources UP-TO-DATE
:classes
:jar
:assemble
:compileTestJava UP-TO-DATE
:compileTestGroovy UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build

BUILD SUCCESSFUL

Total time: 5.499 secs

This build could be faster, please consider using the Gradle Daemon: https://docs.gradle.org/2.12/userguide/gradle_daemon.html

and our new library jar file created under the directory:

soapuilib/build/soapuilib-1.0-sample.jar

6.Add jar file to SoapUI

To make our new Groovy library jar available for use in SoapUI, it should be added in SoapUI Home under the following external library directory:

SoapUI ext Directory

Or the Windows equivalent e.g. C:\Program Files\SmartBear\SoapUI-5.2.1\bin\ext

7.Verify jar file is imported

When SoapUI is restarted, you should see the following log entry indicating that the jar file has been successfully added to the SoapUI classpath:

SoapUI ext Lib Loaded
8.Call the code

Our SequentialIdGenerator has a public static method nextId() that we can call, so to do this we can either import the class (Example 1)  or just prefix the class with its package (Example 2). See below:

  • Example 1 – Call from Groovy TestStep:
import custom.*

log.info SequentialIdGenerator.nextId()

Gives output like:


Thu May 12 16:49:20 BST 2016:INFO:id1001

  • Example 2 – Call from Property Expansion:

${= custom.SequentialIdGenerator.nextId()}

More

This section may evolve over time e.g. include details of further use-cases and examples. Anything you’d like to see, please ask!

Links

No links yet.