Apex + "merge into"
Hi all,
I have a table named contacts.
I created a form+report and added some java script to auto-fill in the required fields.
Now I want to use the merge into (aka upsert) to insert the person if it doesn't exist or update it if i make some extra modifications.
Does anyone have a solution for this one?
thanks,
Pieter
Hi again!
Let's see what we can do.
1.) Create a stored procedure for the upsert. This is the interface from your database to your application.
CREATE OR REPLACE PROCEDURE merge_into_contactperson
p_id IN NUMBER,
p_firstname IN VARCHAR2,
p_name IN VARCHAR2,
p_address IN VARCHAR2,
p_zip IN VARCHAR2,
p_location IN VARCHAR2,
p_birthday IN DATE,
p_phone IN VARCHAR2,
p_cellphone IN VARCHAR2,
p_gender IN VARCHAR2,
p_contacttyp IN NUMBER,
p_company IN NUMBER,
p_club IN NUMBER,
p_remarks IN VARCHAR2,
p_or_id IN NUMBER
AS
BEGIN
MERGE INTO contactperson cp
USING (SELECT p_id AS id, p_firstname AS firstname, p_name AS name, p_address AS address,
p_zip AS zip, p_location AS location, p_birthday AS birthday, p_phone as phone,
p_cellphone AS cellphone, p_gender AS gender, p_contacttype as contacttyp, p_club AS club,
p_remarks AS remarks, p_or_id AS or_id
FROM dual) incoming
ON (cp.id = incoming.id)
WHEN MATCHED THEN
UPDATE SET cp.firstname = p_firstname,
cp.name = p_name,
cp.address = p_address,
cp.zip = p_zip,
cp.location = p_location,
cp.birthday = p_birthday,
cp.phone = p_phone,
cp.cellphone = p_cellphone,
cp.gender = p_gender,
cp.contacttype = p_contacttype,
cp.club = p_club,
cp.remarks = p_remarks,
cp.or_id = p_or_id WHEN NOT MATCHED THEN
INSERT VALUES (p_id, p_firstname, p_name, p_address, p_zip, p_location, p_birthday, p_phone,
p_cellphone, p_gender, p_contacttype, p_club, p_remarks, p_or_id)
END;
/2.) Create a Pageprocess of type PL/SQL on your APEX application page and name it "proc_merge_into_contactperson". Write in the following code into the processbody:
merge_into_contactperson (:P15_ID, :P15_FIRSTNAME, :P15_NAME, :P15_ADDRESS, :P15_ZIP, :P15_LOCATION, :P15_BIRTHDAY, :P15_PHONE,
:P15_CELLPHONE, :P15_GENDER, :P15_CONTACTTYPE, :P15_CLUB, :P15_REMARKS, :P15_OR_ID);3.) Make proc_merge_into_contactperson conditional for a button so that it will be executed if the button is pushed.
That's it. That's the whole process for integrating an UPSERT into an APEX application. I hope that this will help you along. If you have any further questions please post them.
Yours sincerely
Florian W.
Edited by: Florian W. on 30.06.2009 07:22
Similar Messages
-
I have 2 icloud accounts. can they be merged into one?
I have two iCloud accounts and want to delete one of them. Can the two be merged into one?
Welcome to the Apple Community.
You can't merge accounts but there may be some things you can do, what exactly are you trying to achieve by merging accounts. -
I have 20,00 images in my iphoto they have all been merged into one event. How do I restore them to the original events and dates?
Load the backup from before this happened
LN -
I have 2 ipods,one for music and the other for old time radio shows.Each had their own file.My computer crashed and I had to buy a new one.Now both ipod files are merged into one.How do I seperate them on the computer?
Hi Craig
Unfortunately, in your case, there isn't really a way to separate them as far as I can think.
You could try restoring from a backup, and choosing an older backup perhaps
Cheers -
Two separate iPhones got merged into one iTunes account. How can I separate them in iTunes???????. We are sharing all of each other's contacts at this time. Thanks for your help.
The reason you are receiving each other's text messages is because you are both using the same Apple ID for iMessage. To prevent this you need to use different IDs. (Note: you can still share the same ID for iTunes.) On one of the phones, go to Settings>Messages>Send & Receive, tap the ID, sign out, then sign back in with a separate ID.
To migrate your 3GS to a new iCloud account, start by saving any photo stream photos that you want to keep on the phone to your camera roll. To do this, open the my photo stream album, tap Edit, tap the photos, tap Share, tap Save to Camera Roll. Next, if you have any notes that you are syncing with iCloud that you want to keep, you'll need to email these to yourself so they can be recreated after moving to the new account.
Once this is done, go to Settings>iCloud, scroll to the bottom and tap Delete Account. (This will only delete the account from this phone, not from iCloud. The phone that will be keeping the account will not be effected by this.) When prompted about what to do with the iCloud data, choose Keep On My iPhone. Next, sign back in with a different Apple ID to create the new account, turn iCloud data syncing preferences and when prompted about merging with iCloud, choose Merge. This will upload the data to the new account.
Finally, if you have merged data in the two accounts that you want to separate you will have to go to icloud.com from your computer, sign into each iCloud account separately and manually delete the data you don't want from each account. -
I have recently transferred data from my old Mac to my new one. The result was good, but I have 2 users now, whose data I want to merge into 1 single user, so to avoid having to switch from one user to the other to view and use certain files. How to do it?
Here's an easy way:
Pick the user that you want to eliminate (making sure that the remaining user has administrator privileges) and move all of the data that you want to keep into the Shared folder. Reboot or log out and login to the user you want to keep. Copy all the data from the Shared folder into your account - placing it neatly in folders (Documents, Music, Movies, etc.).
Once the data is moved, log into the account you want to delete just once more to make certain that you've grabbed all the data you want to keep. Log out and log back into your admin account and go to System Preferences>Users & Groups and delete the 'old' user.
That should do it.
Clinton -
PI 7.1 runtime error: 2 messages are merged into one
Hi,
We have recently upgraded to 71. We are having a crtical issue with one of the interface. below are the details:
Background:Interface is using ABAP mapping to convert an Idoc into file.
File name is fed into u2018dynamic configurationu2019 in mapping program.
File adapter uses dynamic file name and saves the file using NFS.
Interface receives idocs in batch, so several Idocs are received by XI almost at the same time.
Interface has been working without any problem in version 3.00 for last 3 years.
Problem in 71.:On occasions (random, not always), 2 idocs are merged into one file. It means, only one file is created, which includes the data from 2 idocs.
In message pipeline, same file name is shown both message (in dynamic config after mapping)
We have tried u2018use temporary filenameu2019 option on file adapter, but problem is not resolved.
Any sugegstion pelase!Hi,
In your Graphical mapping create an UDF with code Thread.sleep(1000) and map this udf to any node (may be root node).
Note: The delay is in mili sec.
This udf will delay the mapping for specific time. I am not sure if it is going to solve your problem but you can try.
Regards,
Sarvesh -
Can I Create Chapters Separately in iBooks Author and Merge Into a Single iBook?
In a print page layout package like InDesign, chapters of a book can be created separately and then merged into one book file. Is it possible to do that to create an iBook in iBooks Author?
Thank you.Yes, it is possible and very easy to do.
If you want your chapters/sections/pages to have the same layout and colour scheme... make your template and and save as template - or use teh same free template for each chapter.
Create a Master version - and it is to this you will eventually copy and paste youe separate chapters.
Just select and copy the chapter and open the master.. then paste in the left "Book" column.
If you are using different chapter layouts - It also takes its template and that also appears in the hidden Layout tree.
I use this method on every book, simply because it does not slow down the machine. A multi chapter book with videos and photo images makes a big file - which is slow to process every time you preview or check things. -
My latest pano photo have missing landscape. Some of the photos are merged into one. I can provide the examples. What could cause this problem on a new 5C?
Thanks for the input. I was finally able to find some test conditions that duplicated the problem, and it is either that or some other out-of-spec diffraction distortion. So I sent it off for repair.
-
"Merge into" statement doesn't work
Hi Reader,
It seems that in some of our installed machines merge into statement doesn't;t work. We've already experienced this issue on databases installed within virtual machines, but also found on other configurations sporadically.
Using statement match a single/multiple records (according required logic)
statement:
MERGE INTO RNCATEGORIES CV
USING dual ON
( CV.DESIGNCENTERID = in_DESIGNCENTERID
AND CV.CADPACKAGENAME = in_CADPACKAGENAME
WHEN MATCHED THEN
UPDATE SET
PKGCATEGORYID = in_PKGCATEGORYID,
UserPackageType = in_UserPackageType
WHEN NOT MATCHED THEN
INSERT VALUES ( in_DESIGNCENTERID,
in_CADPACKAGENAME, in_PKGCATEGORYID,in_UserPackageType );
Table script:
CREATE TABLE RNCATEGORIES
DESIGNCENTERID RAW(16) NOT NULL,
CADPACKAGENAME NVARCHAR2(64) NOT NULL,
PKGCATEGORYID RAW(16),
USERPACKAGETYPE NVARCHAR2(64)
PK_RNCATEGORIES PRIMARY KEY (DESIGNCENTERID, CADPACKAGENAME)
Thanks in advance,
AmirAfter creating the table, your merge statement gives me
SQL> MERGE INTO RNCATEGORIES CV
2 USING dual ON
3 ( CV.DESIGNCENTERID = in_DESIGNCENTERID
4 AND CV.CADPACKAGENAME = in_CADPACKAGENAME
5 )
6 WHEN MATCHED THEN
7 UPDATE SET
8 PKGCATEGORYID = in_PKGCATEGORYID,
9 UserPackageType = in_UserPackageType
10 WHEN NOT MATCHED THEN
11 INSERT VALUES ( in_DESIGNCENTERID,
12 in_CADPACKAGENAME, in_PKGCATEGORYID,in_UserPackageType );
AND CV.CADPACKAGENAME = in_CADPACKAGENAME
ERROR at line 4:
ORA-00904: "IN_CADPACKAGENAME": invalid identifierwhich is about what I expected. The USING clause requires a select statement, not just a table name. It looks to me like this merge statement is in some kind of stored procedure, and that the in_XXX are variables passed to that procedure. If this is correct, then your merge needs to be more like:
MERGE INTO rncategories cv
USING (SELECT in_designcenterid dcid, in_cadpackagename cpn,
in_pkgcategoryid pcid, in_userpackagetype upt
FROM dual)
ON (cv.designcenterid = dcid and
cv.cadpackagename = cpn)
WHEN MATCHED THEN
UPDATE SET
pkgcategoryid = pcid
userpackagetype = upt
WHEN NOT MATCHED THEN
INSERT VALUES (dcid, cpn, pcid, upt);John -
Merge Into works in SQL, fails in PL/SQL
Database is 9i (Oracle9i Enterprise Edition Release 9.2.0.5.0)<br>
<br>
The 9i documentation--PL/SQL User's Guide and Reference
Release 2 (9.2)--makes it seem like this is part of the PL/SQL language, but the compiler disagrees.<br>
<br>
Anyone else encounter this?<br>
<br>
Test case:<br>
create table kev(d date, n number);<br><br>
Table created.<br>
<br>
..it works in SQL...<br>
MERGE INTO kev k<br>2 USING ( SELECT 1 n, sysdate d from dual ) s<br>
3 ON ( k.n = s.n )<br>
4 WHEN MATCHED THEN<br>
5 UPDATE<br>
6 SET k.d = s.d<br>
7 WHEN NOT MATCHED THEN<br>
8 INSERT (n,d)<br>
9 VALUES (s.n, s.d);<br>
<br>
1 row merged.<br>
<br>
..but not in PL/SQL...<br>
begin<br>2 MERGE INTO kev k<br>
3 USING ( SELECT 1 n, sysdate d from dual ) s<br>
4 ON ( k.n = s.n )<br>
5 WHEN MATCHED THEN<br>
6 UPDATE<br>
7 SET k.d = s.d<br>
8 WHEN NOT MATCHED THEN<br>
9 INSERT (n,d)<br>
10 VALUES (s.n, s.d);<br>
11 end;<br>
12 /<br>
MERGE INTO kev k<br>
*<br>
ERROR at line 2:<br>
ORA-06550: line 2, column 7:<br>
PLS-00103: Encountered the symbol "INTO" when expecting one of the following:
:= . ( @ % ; <a SQL statement><br>
<br>
Thanks.Answer
There are indeed DB parameters conflicting with the MERGE statement. The DB I am working on is for Oracle Applications. Apparently, although the applications are certified to run on current databases, the underlying code base has not really been brought up, and users are forced into some backward compatibility constraints. So I am stuck until we get our application upgraded from 11.5.7 to something better.
Hope this helps someone else.
Kevin
From the database initialization parameters:
# Events
# Events should not be set unless directed by Oracle Support,
# or by instruction as per the Applications documentation.
# The following events should be set for PL/SQL backward
# compatibility.
# These events should only be used if you are using Oracle
# Applications release 11.5.7. For later releases (i.e. 11.5.8
# or higher), you should remove these events.
event="10932 trace name context level 32768"
event="10933 trace name context level 512"
event="10943 trace name context level 16384" -
Primary key failure with merge into...should not happen
I get primary key constraint fail on this MERGE INTO sql.
Why? Shouldn't the merge into take care of this?
ORA-00001: unique constraint (NCSL.SYS_C001568) violated
MERGE INTO SessionTbl2 thistbl
USING
(SELECT 'b2cdd2f30b786c329ad2f8d04d0e79e9' sessionid FROM dual) thistbl2
ON (thistbl2.sessionid = thistbl.sessionid AND thistbl.varname=:varname)
WHEN MATCHED THEN
UPDATE SET thistbl.varvalue=:variablevalue,
thistbl.only_on_page=:onlyonpage,
thistbl.expire_tstamp=:expire_tstamp,
thistbl.inactivity_timeout=:inactivity_timeout,
thistbl.readonly=:readonly
WHEN NOT MATCHED THEN
INSERT (sessionid,varname,varvalue,tstamp,
only_on_page,expire_tstamp,inactivity_timeout,
readonly)
VALUES
(:cacheidval,:varname,:variablevalue,:nowts,
:onlyonpage,:expire_tstamp,:inactivity_timeout,
:readonly)As you say, this should not give a problem then, but the only way to be sure the system is doing what you believe it should do is to use the same variables in the test and in the insert statement. The bind variable depends on the programming language you use and may pass something else than the string that oracle generates in the select from dual. I do not say it will be as such, I just want to make sure that this is not the problem. I have seen things like this before and you keep on looking in the wrong direction for a solution.
Peter -
Hi All,
i need an expert advice in this matter, and if possible please explain with some code/example.Here is the situation.
This process will read all records in the STAGING_TABLE and process the data into the MY_DATABASE tables.
STG_ID will be used to populate the MY_ID with in MY_DATABASE.
Any records that fail the load process will be flagged as 'error' by populating the ERROR_TABLE with the reson for the failure. After the load has been performed, all error records will be corrcted and reloaded.
outline as below:
1. Read all staging table records.
2. Use the STG_ID value to determine whether the record already exists with in the MY_DATABASE tables.
3. If not exist, create the one with associated records.
4. If exists, compare the staging data to the MY_DATABASE data as per the rules. Then update the appropriate data in MY_DATABASE.
5. If any records are invalid, update the staging table record with the error message.
6. create a record in MY_LOGS table to indicate successfull completion of the process as well as the number of records processed.
Now my approach is to use MERGE INTO path. I know that we can do it with the help of PL/SQL. given the above scenerio which approach is the better one. we have millions of records to be processed. Do merge has the capability to take care of all the logics i.e(insert/update/logs/bad-records)
can we use Merge in procedure and packages ?
please give me some advise in this matter .
Thanks!read the following , you might get a better idea
http://download-west.oracle.com/docs/cd/B10501_01/server.920/a96540/statements_915a.htm#SQLRF01606
Have you considered using External Tables ? -
Playerglobal.swc Linkage Type: External or Merged Into Code?
Hi,
I downloaded Flash Pro CS6 with flex sdk version 11.3. It didn't contain Workers functionality, so I had to download the latest playerglobal.swc 11.8 version.
I then used Actionscript options and pointed to the playerglobal.swc.
When I published the fla with playerglobal.swc linkage type set to Merged into Code, the runtime pops up this error:
VerifyError: Error #1079: Native methods are not allowed in loaded code.
However, when I published the fla with playerglobal.swc linkage type set to External, the runtime pops up this error:
VerifyError: Error #1014: Class flash.system::Worker could not be found.
The only way to get rid of the VerifyError: Error #1079: Native methods are not allowed in loaded code is to get rid of all the code that reference Workers in the fla.
How can I use Workers in my project!???Here's a really old article but using it you can still get the general idea of how to properly update Flash Pro with a new version of Flash Player.
http://chrisgriffith.wordpress.com/2012/07/20/updating-flash-professional-cs6-to-support-1 1-4/
It's for Mac but if you're on Windows the paths inside the folders are the same and Flash itself can be found in (C:\Program Files (x86)\Adobe\Adobe Flash CS6) Just grab the player you choose, latest or use the archive link for older, update Flash Pro so it's an option you can select as a publish target:
http://www.adobe.com/support/flashplayer/downloads.html
As long as you've updated your debugger (C:\Program Files (x86)\Adobe\Adobe Flash CS6\Players\Debug) with the latest debugger, always test with the debugger (CTRL+SHIFT+ENTER, not just CTRL+ENTER). Otherwise you're using an older Flash Player. You can verify the version of the debugger you're testing with checking the Capabilities.version property,
e.g.:
import flash.system.Capabilities;
trace(Capabilities.version); // should say 11,8,xxx,xxx or whatever version you installed -
Hi All!
Following statement give me an error ORA-00904: Invalid column name in the string:
on (Mirror.ARCH_FLAG=qt.ARCH_FLAG and Mirror.CREDIT_HEADER_ID=qt.CREDIT_HEADER_ID)
merge into CREDIT_HEADER_P Mirror
using (select
CREDIT_HEADER_ID,
PO_DATE,
HP_RECEIVED_DATE,
PDA_ID,
CUSTOMER_BASE_NR,
CREDIT_TYPE,
CREDIT_CURRENCY,
CLAIM_SUBTYPE_ABREV,
CUST_PO_NO,
BILLING_NO,
OMS_START_SECTION_NO,
OMS_END_SECTION_NO,
OMS_SHIP_VIA,
OMS_CHANGE_REASON_CODE,
CUST_COMMENT,
SPECIAL_INSTRUCTIONS,
CASH_DISCOUNT,
TARGET_SYSTEM,
DATE_SENT_TO_TARGET_SYSTEM,
ARCH_FLAG,
RECORD_EXTRACTION_DATE,
LAST_MOD_DATE
from INC_CREDIT_HEADER_P) qt
on (Mirror.ARCH_FLAG = qt.ARCH_FLAG and Mirror.CREDIT_HEADER_ID = qt.CREDIT_HEADER_ID)
when matched then
update
set Mirror.CREDIT_HEADER_ID=qt.CREDIT_HEADER_ID,
Mirror.PO_DATE=qt.PO_DATE,
Mirror.HP_RECEIVED_DATE=qt.HP_RECEIVED_DATE,
Mirror.PDA_ID=qt.PDA_ID,
Mirror.CUSTOMER_BASE_NR=qt.CUSTOMER_BASE_NR,
Mirror.CREDIT_TYPE=qt.CREDIT_TYPE,
Mirror.CREDIT_CURRENCY=qt.CREDIT_CURRENCY,
Mirror.CLAIM_SUBTYPE_ABREV=qt.CLAIM_SUBTYPE_ABREV,
Mirror.CUST_PO_NO=qt.CUST_PO_NO,
Mirror.BILLING_NO=qt.BILLING_NO,
Mirror.OMS_START_SECTION_NO=qt.OMS_START_SECTION_NO,
Mirror.OMS_END_SECTION_NO=qt.OMS_END_SECTION_NO,
Mirror.OMS_SHIP_VIA=qt.OMS_SHIP_VIA,
Mirror.OMS_CHANGE_REASON_CODE=qt.OMS_CHANGE_REASON_CODE,
Mirror.CUST_COMMENT=qt.CUST_COMMENT,
Mirror.SPECIAL_INSTRUCTIONS=qt.SPECIAL_INSTRUCTIONS,
Mirror.CASH_DISCOUNT=qt.CASH_DISCOUNT,
Mirror.TARGET_SYSTEM=qt.TARGET_SYSTEM,
Mirror.DATE_SENT_TO_TARGET_SYSTEM=qt.DATE_SENT_TO_TARGET_SYSTEM,
Mirror.ARCH_FLAG=qt.ARCH_FLAG,
Mirror.RECORD_EXTRACTION_DATE=qt.RECORD_EXTRACTION_DATE,
Mirror.LAST_MOD_DATE=qt.LAST_MOD_DATE,
Mirror.RECORD_STATUS='M'
when not matched then
insert (
Mirror.CREDIT_HEADER_ID,
Mirror.PO_DATE,
Mirror.HP_RECEIVED_DATE,
Mirror.PDA_ID,
Mirror.CUSTOMER_BASE_NR,
Mirror.CREDIT_TYPE,
Mirror.CREDIT_CURRENCY,
Mirror.CLAIM_SUBTYPE_ABREV,
Mirror.CUST_PO_NO,
Mirror.BILLING_NO,
Mirror.OMS_START_SECTION_NO,
Mirror.OMS_END_SECTION_NO,
Mirror.OMS_SHIP_VIA,
Mirror.OMS_CHANGE_REASON_CODE,
Mirror.CUST_COMMENT,
Mirror.SPECIAL_INSTRUCTIONS,
Mirror.CASH_DISCOUNT,
Mirror.TARGET_SYSTEM,
Mirror.DATE_SENT_TO_TARGET_SYSTEM,
Mirror.ARCH_FLAG,
Mirror.RECORD_EXTRACTION_DATE,
Mirror.LAST_MOD_DATE
values (
qt.CREDIT_HEADER_ID,
qt.PO_DATE,
qt.HP_RECEIVED_DATE,
qt.PDA_ID,
qt.CUSTOMER_BASE_NR,
qt.CREDIT_TYPE,
qt.CREDIT_CURRENCY,
qt.CLAIM_SUBTYPE_ABREV,
qt.CUST_PO_NO,
qt.BILLING_NO,
qt.OMS_START_SECTION_NO,
qt.OMS_END_SECTION_NO,
qt.OMS_SHIP_VIA,
qt.OMS_CHANGE_REASON_CODE,
qt.CUST_COMMENT,
qt.SPECIAL_INSTRUCTIONS,
qt.CASH_DISCOUNT,
qt.TARGET_SYSTEM,
qt.DATE_SENT_TO_TARGET_SYSTEM,
qt.ARCH_FLAG,
qt.RECORD_EXTRACTION_DATE,
qt.LAST_MOD_DATE
But! If I do:
select Mirror.CREDIT_HEADER_ID
from CREDIT_HEADER_P Mirror
or
select Mirror.ARCH_FLAG
from CREDIT_HEADER_P Mirror
I don't get any error. I copied (not entered new!) The column and table name from the statement above! If I submit Mirror.ARCH_FLAG and Mirror.CREDIT_HEADER_ID with 1, it works also. Any ideas?
Regards,
Andrejhttp://download-west.oracle.com/docs/cd/B10501_01/server.920/a96540/statements_915a.htm#2080942
You cannot specify DEFAULT when updating a view.
You cannot update a column that is referenced in the ON condition clause. Problem is you use ARCH_FLAG and CREDIT_HEADER_ID in ON clause -
on (Mirror.ARCH_FLAG = qt.ARCH_FLAG and Mirror.CREDIT_HEADER_ID = qt.CREDIT_HEADER_ID)
and try to update them:
set Mirror.CREDIT_HEADER_ID=qt.CREDIT_HEADER_ID,
Mirror.ARCH_FLAG=qt.ARCH_FLAG,
It violates the deterministic.
Rgds.
Maybe you are looking for
-
I need to make a point here: Vista is NOT the problem with Creative's drivers. On the contrary, it's the other way around! Vista is suffering as an operating system because of the terrible drivers written by companies such as Creative (and to a lesse
-
Upload an XML file into the Internal table
Hi Guys, I want to know, how to upload an xml file into the Internal table through ABAP programming
-
ALL IPHOTO LIBRARY VANISHED!
I was sorting my pictures and wanted to add some new ones from a memory key. I tried drag and drop, but it took too much time. The little wheel for my mouse was rolling forever, my computer froze, and i had no choice to restart it. When it came on ag
-
Change font when replying a HTML messages
I want to change the font when I reply an e-mail in HTML. The current font is big. A colleague of mine is able to reply using the same font the message was composed with his Android
-
Diff bw SQLERRM and DBMS_ UTILITY. FORMAT_ CALL_ STACK
Dear One and all, In recent times i read some where using DBMS_UTILITY.FORMAT_CALL_STACK is the suitable alternative instead of using SQLERRM is it so ? Could any one one tell me what is the exact difference b/w both with simple program / and how to