Sage ERP X3 Development - EX - Part 1-1

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 25

Sage ERP X3

Development - Fundamentals
Exercises

Doc. Ref. :

19-01-2015

Table of content

1.0 LAB 1 – Domain management 4


Creating the data structure 4
1.1 Activity code 4
1.2 Local Menu 4
1.3 Table 5

2.0 LAB 1 – Domain management 6


Creating the GRAPHICAL structure & interface 6
2.1 Screens 6
2.2 Object 7
2.3 Window 8
2.4 Function 8
2.5 Menu Item 8
2.6 Navigation Page 8
2.7 Additional Requirements 9

3.0 LAB 1 – Domain management 10


Header and detail management 10
3.1 Tables 10
3.2 Screens 11
3.3 Object 11
3.4 Process 11

4.0 LAB 2 – Playing.with the X3 language 12


4.1 Playing with integers 12
4.2 Playing with strings 13
4.3 Playing with arrays 14
4.4 Playing with trace files 15
4.5 Playing with boxes 16

5.0 OPTIONAL - LAB 3 17


The XPI Object 17
5.1 Activity code 17
5.2 Table 17
5.3 Screens 19
5.4 Menu 20
5.5 Object 20
5.6 Window 20
5.7 Additional Requirements 21
5.8 Enhancements 21

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 2
Introduction

In much of the processes where common data are created (such as Customers or
Products) the exercise notes mention XXX in the data codes or designations. Replace that
with your own initials. This is to distinguish your data from other delegate’s data in case
the servers are shared.

As beginners, you will be guided on how to access the menu. You will have a step by
step instruction on how to work on your exercises.

The exercises are so easy because the main objective is to let you manipulate the
software. But at the end of each required exercises there are extra questions that you are
invited to do by yourself to test your complete comprehension of the functionalities
presented in this training.

1.0 LAB 1 – Domain management


Requirement
Creating the data structure
Your customer, a Domain name
reseller, needs to manage domain-specific information attached to end- and by-products:
Expiry criteria, status, information about business partners etc.
They have decided to implement this in a separate function, where a product code
manages the attached information. The product code will be linked to an actual
ITMMASTER product but not yet created as an X3 product.

Objective: This exercise will show you the main features as an overview of the X3
development platform.

1.1 Activity code


Development > Data and parameters > Development setup > Activity
codes

First create an activity code that will identify your project: XTR

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 3
1.2 Local Menu
Development > Data and parameters > Tables > Local menus - messages

Create the local menu 6200. It will contain the eventual existing web extensions.
Don’t forget to tick the checkbox “Local Menu” and to select it as “changeable”.

Number Code Message


1 1 .com
2 1 .org
3 1 .info

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 4
1.3 Table
Development > Data and parameters > Tables > Tables

Managed information should be contained in this table and include the following fields:
Table: XDOMMAG, Product information
Abbreviation: XDM
Index: XDM0, Descriptors: DOMCOD, no duplicates

Field Types Length Dimensio Normal title


n
DOMCOD ITM 1 Domain code
DOMTYP BPR 10 Domain Partner
DOMDES DES 1 Domain Name
STA A 3 1 EPP Status
ID BPR 10 Partner's ID
STREET A 50 10 Address
CRY CRY 10 Country
TEL TEL 10 Telephone
EMAIL MAI 10 E-mail Address
EXT MM 6200 10 Web Extension
CLOB ACB 1 Text file (clob)
NBLIG ABS 1 Number of line 1
NBLIG2 ABS 1  Number of line 2
REGDAT D 1 Registration date
EXPDAT D 1 Expiry date
CREDAT D 1 Creation date
UPDDAT D 1 Update date
CREUSR AUS 1 User creation
UPDUSR AUS 1 User update

Remark: We are using type MM for the local menu because this one is setup as it could
be modified to manage the choices displayed (screen development – field actions).
We would have used M type otherwise.

2.0 LAB 1 – Domain management


Creating the GRAPHICAL structure & interface

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 5
1.4 Screens
Development > Script dictionary > Screens > Screens

The information should be viewed via a header screen and two tabs.

Header Screen: XDM0


Abbreviation: XDM0
Reference table: XDOMMAG

Field Type Lengt Description


s h
DOMCO ITM Domain code
D
DOMDE DES Domain
S Name
STA A 3 EPP Status
EXPDAT D Expiry date
REGDA D Registration
T date

Requirements for the header screen:

DOMCOD is mandatory.

When the product code is entered, the system should check if the product exists in the
ITMMASTER table. If so, the product designation should be initialized with the product
designation from the ITMMASTER table. If not, nothing is done.

Tips: Select the right type of link.

The field DOMDES is a free text field. It will contain the full name in order to display the
corresponding web page in the future second tab.

Tab Screen: XDM1

Abbreviation: XDM1

This tab will split in 3 parts:

The 1st block should be an array with customer’s information

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 6
The 2nd block should be an array containing the extension associated to the domain name.

The 3rd block should be a text area (CLOB)

Field Type Leng Remarks : 1st block, PARAMETER: NBLIG


th
ID BPR When the customer code is entered, the system should check if the customer
exists in the BPCUSTOMER table. If so, the customer’s name should be
initialized from the BPCUSTOMER table. If not, nothing is done.
STREE A 50 Address
T
CRY CRY Country
TEL TEL Phone
EMAIL MAI E-mail Address
Field Remarks: 2nd block, PARAMETER: NBLIG2
EXT M 6200 Web Extension, local menu as a drop down list
Field Remarks: 3rd block
CLOB ACB  text area (multi-line text)

Requirements for this tab:

There should be a tunnel right-click from ID to the Business partner function (GESBPR),
and a selection box to select existing customers.

1.5 Object
Development > Script dictionary > Objects

Create the object that will interface the tables and the screens. This object, also as left list,
will show 2 columns as the DOMCOD and its description DOMDES.

Object: XDM (Simple)


- Selection columns: DOMCOD, DOMDES

Once your object is validated, it should have created the function GESXDM.

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 7
1.6 Window
Development > Script dictionary > Windows

Create the window gathering all the previous items like object, and screens.

Window: OXDM (Object window)


- Add your screens XDM0 and XDM1. Also add your object XDM into this window.
Browser: XDM

1.7 Function
Development > Script dictionary > Functions

Check the function created by the object: GESXDM.


See which action is plugged and which parameters are required.
.

1.8 Menu Item


Administration > Authoring > Menu Items

Create a menu item SPE_GESXDM to open the function GESXDM, the link type should
be:

Function (Convergence).

1.9 Navigation Page


Administration > Authoring > Navigation Page

Add the menu option to the ‘home’ navigation page


Personalization of the navigation page is done in the “navigation pages” activity in the
“Administration Syrause” page.
Use the button “Edit Page content” for the “Home” navigation page and create the module
XDEV : this module will contain all the functions of the training. Create a sub-module with

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 8
the Code XSDEV and add the menu Item SPE_GESXDM to it by clicking on the “select”
button.

To add a new To add a new To select a To add a new


module sub-module menu item block

A block

1.10 Additional Requirements


When creating a record (hitting the CREATION button), control the registration date. If the
date is less than today’s date:
1. Stop the creation and display an error message of your choice.
Tips: Use a label that allows you to stop the creation (search in the help file).
Use the system variable “date$”

2. Use a local menu to store this error message. Adapt your code.
You will create a local menu number 6000 (Local menu not ticked = message list).

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 9
3. Using the same code, handle this error with the dedicated label DATE_ERROR. You
should display a message using:
Messages available in the local menu 6000 (message list)

Tips: Use the “onerrgo” statement.


Trigger a dummy error by trying to read a dummy file: use instruction “openi”
Use the “mess” instruction.

3.0 LAB 1 – Domain management


Requirement
Header and detail management
We will adapt the development
in order to use a real simple object with header/detail management.

Objective: This exercise will show you how to handle Header/Detail tables with a simple
object

1.11 Tables
Development > Data and parameters > Tables > Tables

Create a table XDOMMAGD. This table will be used to manage the details. We will use
the field dimensioned to 10 in the table XDOMMAG.

Table: XDOMMAGD, Domain Management detail


Abbreviation: XDD
Index: XDD0, Descriptors: DOMCOD, DOMLIN, no duplicates

Field Types Length Dimensio Normal title


n
DOMCOD ITM 1 Domain code
DOMLIN L 1 Line number
ID BPR 1 Partner's ID
STREET A 50 1 Address
CRY CRY 1 Country
TEL TEL 1 Telephone

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 10
EMAIL MAI 1 E-mail Address

Once XDOMMAGD is created, clean the table XDOMMAG in order to avoid duplicate
fields. Erase the fields NBLIG.

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 11
1.12 Screens
Development > Script dictionary > Screens > Screens

Adapt the screen XDM1:


Field Type Length Remarks : 1st block
NBLIG ABS
DOMLIN L 8 Line number Action type Action Name Parameters
(hidden)
CONTROL DIVLINCONT LIG:”DOML
CREFLG C Creation flag IN”
(hidden)
AFTER_LINE DIVLINNUM
UPDFLG C Update flag
(hidden)
Remark: don’t forget to add the new table XDOMMAGD as a reference table.

1.13 Object
Development > Script dictionary > Objects

Now that you have a new table, the object needs to be aware of its existence. Indeed, it
will allow it to handle automatically this new table for you (open/close).
In the “Environment” tab, add the new table XDOMMAGD.

1.14 Process
1. Set the required routines (TABLEAUX) in the specific process SPEXDM. Those
routines will allow you to handle automatically the table XDOMMAG with the screen
XDM1.
Tips: Use the DETAIL MANAGEMENT FOR SIMPLE OBJECT document.
DON’T FORGET TO HANDLE THE NEW LABELS IN $ACTION.

4. Creation of a versioning system:


Add a new field in the table XDOMMAG and screen XDM0 that will contain the revision
number. When a record is modified, increment this number.
a. Field : XREVNUM, shortint
Tips: Look for an event that occurred after the modification of a record (search in
the help file), in order to be sure that a modification occurred.
Use the instructions “Trbegin”, “Readlock”, “Rewrite”, “Commit”, “Rollback”

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 12
b. Adapt your code in order to use a “standard” way of recording.

4.0 LAB 2 – Playing.with the X3 language


1.15 Playing with
integers

Requirement
We want to create a program that will use the power of 2. We want 2 variables containing
different powers of 2:
- Variable XSHORTINT : Contains powers of 2 up to 15 (Minus 1)
- Variable XLONGINT : Contains powers of 2 up to 31 (Minus 1)

Objectives: We want to experience the behavior of the different integer type to see the
capabilities and limits of each.

1. Create a new source file named XINTMANAG ( Eclipse )


5. In the new source file, create 2 variables :
a. XSHORTINT : local, shortint
b. XLONGINT : local, integer
6. Initialize these 2 variables with powers of 2, respecting the requirements.
a. Display both values with a message box
Tips: Use the instruction infbox and num$

b. Write the results here :


XSHORTINT= …
 Equivalent to 2^…
XLONGINT=…
 Equivalent to 2^…

7. Try to assign XLONGINT to XSHORTINT


a. Display both values with a message box
Tips: Use the instruction infbox and num$

b. Write the results here :


XSHORTINT= …
 Equivalent to 2^…
XLONGINT=…
 Equivalent to 2^…

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 13
Do you have an error? What is this error?

1.16 Playing with strings

Requirement:
We want to create a program that will use strings. We want 3 variables containing strings:
 Variable XHELLO : Contains the string “Hello”
 Variable XWORLD : Contains the string “World”
 Variable XHELLOWORLD : Blank

Objectives: We want to experience the behavior of the string type to see capabilities
and limits.

1. Create a new source file named XSTRMANAG (Ecilpse)


a. In the new source file, create 3 variables :
a. XHELLO : local, char
b. XWORLD : local, char
c. XHELLOWWORLD : local char (10)

8. Initialize the 2 first variables with a string respecting the requirements.


a. Display both values with a message box
Tips: Use the instruction infbox

b. Write the results here :


XHELLO= …
XWORLD=…

9. Try to Concatenate variables XHELLO and XWORLD into XHELLOWORLD


a. Display XHELLOWORLD value with a message box
Tips: Use the instruction infbox

b. Write the result here :


XHELLOWWORLD= …

10. Try to concatenate the variables XHELLO and XWORLD into XHELLOWORLD, but
with a space in between “Hello” and “World”.
a. Using one technique :
Write the technique here: …

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 14
i. Display the value with a message box

b. Using another technique :


Write the technique here: …

i. Display the value with a message box

What happened to the text in the variable XHELLOWORLD? Why?

1.17 Playing with arrays

Requirement:
We want to create a program that will use arrays of strings and integers. We want 3 arrays
containing different types:
- Variable XARRSTR : Array of 5 strings
- Variable XARRINT : Array of 5 integers
- Variable XARRMIX : Array of 5 strings

Objectives: We want to experience the behavior of arrays to see capabilities and limits.

1. Create a new source file named XARRMANAG


2. In the new source file, create 3 variables :
a) XARRSTR : local, char(30), Size=5
b) XARRINT : local, integer, size=5
c) XARRMIX : local, char (250), Size=5

3. Initialize the 2 first variables respectively with strings and integers of your choice.
a) Display values of both arrays with a message box
Tips: Use the instruction infbox

b) Write the results here :


XARRSTR(0)= … XARRINT(0)= …
XARRSTR(1)= … XARRINT(1)= …
XARRSTR(2)= … XARRINT(2)= …
XARRSTR(3)= … XARRINT(3)= …
XARRSTR(4)= … XARRINT(4)= …

4. Try to merge the arrays XARRSTR and XARRINT into XARRMIX.


a) Display the value with a message box
Tips: Use the instruction infbox.

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 15
Use a loop.

b) Write the results here :

XARRMIX(0)= …
XARRMIX(1)= …
XARRMIX(2)= …
XARRMIX(3)= …
XARRMIX(4)= …

1.18 Playing with trace files

Requirement
We want to create a program that will use a trace file. We want different types of
information inside:
 Information
 Warning
 Error

Objectives: We want to experience the different type of information available in a trace


file to see capabilities and limits.

1. Create a new source file named MYTRACEFILE (Eclipse)

2. In the new source file, open a new trace file entitled “My 1st trace file”

3. Add “My 1st text” as an information text

4. Add “My 1st error message” as an error message

5. Add “My 1st warning message” as a warning message

6. Close and Read the trace file

Tips: For error and warning messages, play with the last parameter of the
ECR_TRACE function.

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 16
Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 17
1.19 Playing with boxes

Requirement:
We want to create a program that will use boxes. We want different types of boxes:
 Information box
 Error box
 Question box
 Time out box

Objectives: We want to experience the different boxes to see capabilities and limits.

1. Create a new source file named MYBOXES (Eclipse)


11. In the new source file, display the text « information » in an information box :
a) Display the text « Line 2 » on a second line, using a line break.
b) Display the text « / Line 2 » on a the same line as « Information »
Tips: Border your text with « | » in order to display the character « / »

12. Call an error message with the text « Error »

13. Call a question box asking « Do you want to continue? »:

a) If YES: call a timeout warning box asking « Are you sure? »


i. If YES: call an information timeout box displaying « Good ».
ii. If NO : call an error timeout box displaying « Not good»
b) If NO : call a critical message box saying « End of program »

5.0 OPTIONAL - LAB 3


The XPI Object THIS LAB IS OPTIONAL FOR THE
TRAINEE TO PRACTICE AFTER THE
TRAINING.

Requirement

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 18
Your customer, a pharmaceutical company, needs to manage pharmacy-specific
information attached to end- and by-products: Expiry criteria, medical classification,
certification information, status etc.
They have decided to implement this in a separate function, where a product code
manages the attached information. The product code may be linked to an actual
ITMMASTER product or just a code existing in this function but not yet created as an X3
product.

1.20 Activity code


First create an activity code that will identify your project: XPI

1.21 Table
Managed information should include the following fields:
Table: XPRODINFO Product information, abbreviation XPI

Field Name Type Remarks


PRODCOD Product code AC – 15 Key field
PRODDES Description A – 35
PRODSTA Status Local menu Local menu with following
values:
M 6201
In development
Certification
Active
Withdrawn
Obsolete
PRODCLA Classification Misc. table Miscellaneous table should hold
following values:
ADI 6001
PAR Parapharmacy
TRA Traditional medicine
CHI Chinese medicine
BEA Beauty products
PHA Regular pharmacy
MANDAT Manufacturing D
date
EXPDAYS Lifespan (Days) L Number of days before
expiration.
EXPDAT Expiration date D

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 19
CERCOD Certification Special data This field should display 2 digits
code type followed by a dash (-) followed
XCC (Certif. by 4 letters then a dash then 2
code) digits (e.g. 34-AJER-66). The
value in the database should
exclude the dash character.
BPSNUM Preferred Supplier (BPS) Automatic link to the supplier
Supplier function
NBLIG ABS Technical Variable, Grid Line
counter
PRODCOMP Components ARRAY of Automatic link to the products
Products (ITM) function
with dimension =
50
PRODPCT Percentage Percentage of
each
component.
Decimal, dim.=
50
Precision of 2
decimals.
REM Remarks (Long Rich text field Rich text field linked to clob
desc.)
AC0
CREDAT Creation date
UPDDAT Mod. date
CREUSR Creation user
UPDUSR Mod. User

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 20
1.22 Screens
The information should be viewed via a header screen and two tabs.

Header Screen: XPI0


Fields: PRODCOD, PRODDES.
Requirements for the header screen:
4. PRODCOD is mandatory.
5. When the product code is entered, the system should check if the product
exists in the ITMMASTER table. If so, the product designation should be
initialized with the product designation from the ITMMASTER table. If not,
nothing is done.

Tab 1: XPI1
Field Remarks
PRODSTA Local menu as a drop down list.
PRODCLA Field linked to a miscellaneous table, should automatically show the
description to the right of the field.
MANDAT Blank if zero date
EXPDAYS Blank if zero
EXPDAT Blank if zero date
CERCOD This field should display 2 digits followed by a dash (-) followed by 4
letters then a dash then 2 digits (e.g. 34-AJER-66). The value in the
database should exclude the dash character.
BPSNUM Display the supplier description automatically to the right of the field.
BPSCTY A3 City, display only
BPSCRY CRY Country, display only
BPSTEL A15 Telephone

Requirements for this tab:


1. The validity date should be initialized to the manufacturing date + the lifespan days.
2. PRODCLA should have an automatic description field to its right containing the
product class description.
3. If PRODSTA is not 'Certification' or 'Active', the user should not be able to enter a
CERCOD.
4. EXPDAT cannot be smaller than MANDAT and must be at least 15 days after
MANDAT.
5. BPSNUM should have an automatic field to its right with the supplier name.

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 21
6. BPSNUM should be controlled: If the supplier does not exist, there should be an
error message.
7. There should be a tunnel right-click from BPSNUM to the suppliers function, and a
selection box to select existing suppliers.

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 22
Tab 2: XPI2
2 blocks, one table and one list block
Field Remarks
NBLIG # of lines = 50
PRODCOMP Components ARRAY of Automatic link to the products
Products (ITM) function
PRODPCT Percentage Percentage of
each component
REM Remarks (Long Rich text field Clob (10 lines/ 85 characters)
description.) (AC0)

Requirements for this tab:


3. Field PRODCOMP is mandatory.
4. The screen should contain a table block displaying the components as a
datasheet.
5. Components should be controlled as existing products, and should have a tunnel
menu and a selection box for products.
6. The “table” block screen should have three columns: The product code, the
product designation and the percentage.
7. The percentage cannot be higher than 100%.
8. The same component may not be entered twice in the datasheet.

1.23 Menu
Create a menu XDEV, as the last item in the Main menu (GENE)

1.24 Object
Object : XPI (Simple)
Selection columns: PRODCOD, PRODDES

1.25 Window
Window: OXPI (Object window)
Browser: XPI

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 23
1.26 Additional Requirements
1. When the record is created or saved, the system should check that the sum of
component percentages is equal to 100.
2. When a BOM is created/modified in the BOM maintenance (GESBOD), a new
record should be created for that product, or the existing record should be
amended. The components of this product should be the BOM components
(tables BOM/BOMD).
3. When a product code (PRODCOD) is entered in the header in XPI, and if this
product is a BOM, the component information should be read from tables BOM
and BOMD and the components tab should be initialized with the list of
components and their percentages.
4. A menu in the products maintenance should open the XPI record for that
product if it exists. If not, the menu should be disabled.
5. A button in the XPI object should tunnel to the products maintenance for the
related product if it exists. If not, the button should be disabled.

1.27 Enhancements
The exercise should be modified so the components are stored in a detail table
XPRODINFOD, one component per record

We want a report giving the sales figure by product for the last 12 months, with a total by
family of products

Product apr07 may07 jun07 jul07 aug07 sep07 oct07 nov07 dec07 jan08
feb08
RT200 200 100 0 89 98 65 45 56 67 12 17
Etc…
Local integer A 4 bytes
Local char B(10)
Local date D
Local decimal C
Local integer E(10) : Local integer E(1..10)
Local char F(10)(25)
Local shortint G 2 bytes
Local Libelle H : one byte

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 24
Thank you.

Product manual ¦ Erreur ! Utilisez l'onglet Accueil pour appliquer _Cover date au texte que vous souhaitez faire apparaître
ici. 25

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy