create schema if not exists Online_shopping_system;
set search_path to Online_shopping_system;
drop table if exists customers;
drop table if exists addresses ;
drop table if exists categories ;
drop table if exists orderitems ;
drop table if exists orders ;
drop table if exists payments ;
drop table if exists products ;
drop table if exists reviews ;
create table if not exists customers(
customerid int primary key,
name varchar( 30 ) ,
email varchar( 30 ) ,
phone varchar( 30 ) ,
registrationdate date
) ;
create table if not exists addresses(
addressid int primary key,
customerid int ,
city varchar( 20 ) ,
country varchar( 20 ) ,
postalcode varchar( 20 ) ,
foreign key ( customerid) references customers( customerid)
) ;
create table if not exists payments (
paymentid int primary key,
orderid int ,
paymentdate date,
amount int ,
method varchar( 20 ) ,
foreign key ( orderid) references orders( orderid)
) ;
create table if not exists categories(
categoryid int primary key,
categoryname varchar( 20 )
) ;
create table if not exists products(
productid int primary key,
categoryid int ,
productname varchar( 30 ) ,
price int ,
stock int ,
foreign key ( categoryid) references categories( categoryid)
) ;
create table if not exists orders(
orderid int primary key,
customerid int ,
addressid int ,
orderdate date,
status varchar( 20 ) ,
foreign key ( customerid) references customers( customerid) ,
foreign key ( addressid) references addresses( addressid)
) ;
create table if not exists orderitems
(
orderid int ,
productid int ,
quantity int ,
unitprice int ,
primary key( orderid, productid) ,
foreign key ( orderid) references orders( orderid) ,
foreign key( productid) references products( productid)
) ;
create table if not exists reviews(
reviewid int primary key,
customerid int ,
productid int ,
rating int ,
comment varchar( 200 ) ,
reviewdate date,
foreign key ( customerid) references customers( customerid) ,
foreign key ( productid) references products( productid)
) ;
insert into customers values
( 1 , 'Ahmed Ali' , 'ahmed@gmail.com' , '01011111111' , '2025-01-10' ) ,
( 2 , 'Sara Mohamed' , 'sara@gmail.com' , '01022222222' , '2025-02-15' ) ,
( 3 , 'Omar Hassan' , 'omar@gmail.com' , '01033333333' , '2025-03-20' ) ,
( 4 , 'Mona Adel' , 'mona@gmail.com' , '01044444444' , '2025-04-05' ) ,
( 5 , 'Youssef Sami' , 'youssef@gmail.com' , '01055555555' , '2025-05-12' ) ;
INSERT INTO addresses VALUES
( 1 , 1 , 'Cairo' , 'Egypt' , '11511' ) ,
( 2 , 1 , 'Giza' , 'Egypt' , '12511' ) ,
( 3 , 2 , 'Alexandria' , 'Egypt' , '21511' ) ,
( 4 , 3 , 'Mansoura' , 'Egypt' , '35511' ) ,
( 5 , 4 , 'Cairo' , 'Egypt' , '11512' ) ,
( 6 , 5 , 'Tanta' , 'Egypt' , '31511' ) ;
INSERT INTO categories VALUES
( 1 , 'Laptops' ) ,
( 2 , 'Phones' ) ,
( 3 , 'Accessories' ) ;
INSERT INTO products VALUES
( 1 , 1 , 'Dell XPS 13' , 35000 , 10 ) ,
( 2 , 1 , 'HP Pavilion' , 28000 , 8 ) ,
( 3 , 2 , 'iPhone 15' , 50000 , 12 ) ,
( 4 , 2 , 'Samsung S24' , 42000 , 15 ) ,
( 5 , 3 , 'Wireless Mouse' , 500 , 50 ) ,
( 6 , 3 , 'Mechanical Keyboard' , 1500 , 30 ) ;
INSERT INTO orders VALUES
( 1 , 1 , 1 , '2025-06-01' , 'Delivered' ) ,
( 2 , 2 , 3 , '2025-06-05' , 'Pending' ) ,
( 3 , 1 , 2 , '2025-06-07' , 'Delivered' ) ,
( 4 , 3 , 4 , '2025-06-10' , 'Shipped' ) ,
( 5 , 5 , 6 , '2025-06-12' , 'Pending' ) ;
INSERT INTO orderitems VALUES
( 1 , 1 , 1 , 35000 ) ,
( 1 , 5 , 2 , 500 ) ,
( 2 , 3 , 1 , 50000 ) ,
( 3 , 2 , 1 , 28000 ) ,
( 3 , 6 , 1 , 1500 ) ,
( 4 , 4 , 1 , 42000 ) ,
( 5 , 5 , 3 , 500 ) ,
( 5 , 6 , 2 , 1500 ) ;
INSERT INTO payments VALUES
( 1 , 1 , '2025-06-01' , 36000 , 'Credit Card' ) ,
( 2 , 2 , '2025-06-05' , 50000 , 'Cash' ) ,
( 3 , 3 , '2025-06-07' , 29500 , 'Credit Card' ) ,
( 4 , 4 , '2025-06-10' , 42000 , 'PayPal' ) ;
INSERT INTO reviews VALUES
( 1 , 1 , 1 , 5 , 'Excellent laptop' , '2025-06-15' ) ,
( 2 , 2 , 3 , 4 , 'Very good phone' , '2025-06-16' ) ,
( 3 , 3 , 4 , 5 , 'Amazing camera' , '2025-06-17' ) ,
( 4 , 1 , 5 , 4 , 'Good mouse' , '2025-06-18' ) ,
( 5 , 5 , 6 , 5 , 'Great keyboard' , '2025-06-19' ) ;
select * from orders;
-- List all products with price > 100 ordered by price in descending order
select* from products
where price > 100
order by price desc;
-- Customers names and ids from a New York city
select distinct name, customers.customerid
from customers join addresses
on customers.customerid = addresses.customerid
where city= 'Cairo' ;
-- another solution
select name, customerid
from customers
where customerid in (
select customerid
from addresses
where city= 'Cairo'
)
-- Orders in the last 20 days
select* from orders
where orderdate>= current_date - interval '20 days' ;
-- Reviews with rating >= 4 sorted by newest
select* from reviews
where rating >= 4
order by reviewdate desc;
-- Show products with their category names
select products.*, categoryname
from products join categories
on products.categoryid = categories.categoryid ;
-- Show payments with order date
select payments.*, orderdate
from payments join orders
on payments.orderid = orders.orderid ;
-- List reviews with product names and customer names
select productname, name
from reviews join products
on reviews.productid = products.productid
join customers
on customers.customerid = reviews.customerid ;
-- List all orders with customer name, city, and order date
select name, city, orderdate
from orders join customers
on orders.customerid = customers.customerid
join addresses
on addresses.customerid = customers.customerid ;
-- Show each order item with product name, category, and quantity
select productname, categoryname, quantity
from categories join products
on categories.categoryid = products.categoryid
join orderitems
on products.productid = orderitems.orderid ;
-- Customers who never placed an order
select customers.*
from customers left join orders
on customers.customerid = orders.customerid
where orders.orderid is null ;
-- Orders with no payments
select orders.*
from orders left join payments
on orders.orderid = payments.orderid
where payments.orderid is null ;
-- part 2
-- Number of orders per customer
select customers.customerid , customers.name , count( * ) as NumberOfOrders
from orders inner join customers
on orders.customerid = customers.customerid
group by customers.customerid , customers.name ;
-- Total spending per customer
select customers.customerid , sum( amount) as total_amount
from orders join customers
on orders.customerid = customers.customerid
join payments
on orders.orderid = payments.orderid
group by customers.customerid
-- Number of products per category
select products.categoryid , count( productid) as no_of_products
from products join categories
on products.categoryid = categories.categoryid
group by products.categoryid ;
-- Average rating per product
select products.productid , avg ( rating) as avg_rating
from products join reviews
on products.productid = reviews.productid
group by products.productid
-- Total quantity sold per product for those ever sold
select products.productid , sum( quantity) as total
from products join orderitems
on products.productid = orderitems.productid
join orders
on orderitems.orderid = orders.orderid
group by products.productid
-- Total revenue per order
select products.productid as product_id, count( * ) as total
from products join reviews
on products.productid = reviews.productid
group by product_id
-- Customers who made more than 5 orders
select customers.customerid
from customers join orders
on customers.customerid = orders.customerid
group by customers.customerid
having count( orderid) > 5 ;
-- Customers who spent more than 1000
select customers.customerid
from orders join customers
on orders.customerid = customers.customerid
join payments
on orders.orderid = payments.orderid
group by customers.customerid
having sum( amount) > 1000 ;
-- Orders with total value > 500
select orders.orderid
from orders join payments
on orders.orderid = payments.orderid
group by orders.orderid
having sum( amount) > 500 ;
-- Products with price above average
select productid
from products
where price
>
(
select avg( price)
from products)
-- Most expensive product
select * from products
where price= ( select max( price) from products) ;
Y3JlYXRlIHNjaGVtYSBpZiBub3QgZXhpc3RzIE9ubGluZV9zaG9wcGluZ19zeXN0ZW07CiAKc2V0IHNlYXJjaF9wYXRoIHRvIE9ubGluZV9zaG9wcGluZ19zeXN0ZW07CiAKZHJvcCB0YWJsZSBpZiBleGlzdHMgY3VzdG9tZXJzOwpkcm9wIHRhYmxlIGlmIGV4aXN0cyBhZGRyZXNzZXMgOwpkcm9wIHRhYmxlIGlmIGV4aXN0cyBjYXRlZ29yaWVzIDsKZHJvcCB0YWJsZSBpZiBleGlzdHMgb3JkZXJpdGVtcyA7CmRyb3AgdGFibGUgaWYgZXhpc3RzIG9yZGVycyA7CmRyb3AgdGFibGUgaWYgZXhpc3RzIHBheW1lbnRzIDsKZHJvcCB0YWJsZSBpZiBleGlzdHMgcHJvZHVjdHMgOwpkcm9wIHRhYmxlIGlmIGV4aXN0cyByZXZpZXdzIDsKIApjcmVhdGUgdGFibGUgaWYgbm90IGV4aXN0cyBjdXN0b21lcnMoCmN1c3RvbWVyaWQgaW50IHByaW1hcnkga2V5LApuYW1lIHZhcmNoYXIoMzApLAplbWFpbCB2YXJjaGFyKDMwKSwKcGhvbmUgdmFyY2hhcigzMCksCnJlZ2lzdHJhdGlvbmRhdGUgZGF0ZQopOwpjcmVhdGUgdGFibGUgaWYgbm90IGV4aXN0cyBhZGRyZXNzZXMoCmFkZHJlc3NpZCBpbnQgcHJpbWFyeSBrZXksCmN1c3RvbWVyaWQgaW50ICwKY2l0eSB2YXJjaGFyKDIwKSwKY291bnRyeSB2YXJjaGFyKDIwKSwKcG9zdGFsY29kZSB2YXJjaGFyKDIwKSwKZm9yZWlnbiBrZXkgKGN1c3RvbWVyaWQpIHJlZmVyZW5jZXMgY3VzdG9tZXJzKGN1c3RvbWVyaWQpIAopOwogCiAKY3JlYXRlIHRhYmxlIGlmIG5vdCBleGlzdHMgcGF5bWVudHMgKApwYXltZW50aWQgaW50IHByaW1hcnkga2V5LApvcmRlcmlkIGludCAsCnBheW1lbnRkYXRlIGRhdGUsCmFtb3VudCBpbnQsCm1ldGhvZCB2YXJjaGFyKDIwKSwKZm9yZWlnbiBrZXkgKG9yZGVyaWQpIHJlZmVyZW5jZXMgb3JkZXJzKG9yZGVyaWQpCik7CiAKY3JlYXRlIHRhYmxlIGlmIG5vdCBleGlzdHMgY2F0ZWdvcmllcygKY2F0ZWdvcnlpZCBpbnQgcHJpbWFyeSAga2V5LApjYXRlZ29yeW5hbWUgdmFyY2hhcigyMCkKKTsKIApjcmVhdGUgdGFibGUgaWYgbm90IGV4aXN0cyBwcm9kdWN0cygKcHJvZHVjdGlkIGludCBwcmltYXJ5IGtleSwKY2F0ZWdvcnlpZCBpbnQsCnByb2R1Y3RuYW1lIHZhcmNoYXIoMzApLApwcmljZSBpbnQsCnN0b2NrIGludCwKZm9yZWlnbiBrZXkgKGNhdGVnb3J5aWQpIHJlZmVyZW5jZXMgY2F0ZWdvcmllcyhjYXRlZ29yeWlkKSAKKTsKIAogCmNyZWF0ZSB0YWJsZSBpZiBub3QgZXhpc3RzIG9yZGVycygKb3JkZXJpZCBpbnQgcHJpbWFyeSBrZXksCmN1c3RvbWVyaWQgaW50LAphZGRyZXNzaWQgaW50LApvcmRlcmRhdGUgZGF0ZSwKc3RhdHVzIHZhcmNoYXIoMjApLApmb3JlaWduIGtleSAoY3VzdG9tZXJpZCkgcmVmZXJlbmNlcyBjdXN0b21lcnMoY3VzdG9tZXJpZCksCmZvcmVpZ24ga2V5IChhZGRyZXNzaWQpIHJlZmVyZW5jZXMgYWRkcmVzc2VzKGFkZHJlc3NpZCkKKTsKIApjcmVhdGUgdGFibGUgaWYgbm90IGV4aXN0cyBvcmRlcml0ZW1zCigKb3JkZXJpZCBpbnQsCnByb2R1Y3RpZCBpbnQsCnF1YW50aXR5IGludCwKdW5pdHByaWNlIGludCwKcHJpbWFyeSBrZXkob3JkZXJpZCxwcm9kdWN0aWQpLApmb3JlaWduIGtleSAob3JkZXJpZCkgcmVmZXJlbmNlcyBvcmRlcnMob3JkZXJpZCksCmZvcmVpZ24ga2V5KHByb2R1Y3RpZCkgcmVmZXJlbmNlcyBwcm9kdWN0cyhwcm9kdWN0aWQpCik7CiAKY3JlYXRlIHRhYmxlIGlmIG5vdCBleGlzdHMgcmV2aWV3cygKcmV2aWV3aWQgaW50IHByaW1hcnkga2V5LApjdXN0b21lcmlkIGludCwKcHJvZHVjdGlkIGludCwKcmF0aW5nIGludCwKY29tbWVudCB2YXJjaGFyKDIwMCksCnJldmlld2RhdGUgZGF0ZSwKZm9yZWlnbiBrZXkgKGN1c3RvbWVyaWQpIHJlZmVyZW5jZXMgY3VzdG9tZXJzKGN1c3RvbWVyaWQpLApmb3JlaWduIGtleSAocHJvZHVjdGlkKSByZWZlcmVuY2VzIHByb2R1Y3RzKHByb2R1Y3RpZCkKKTsKIAogCmluc2VydCBpbnRvIGN1c3RvbWVycyB2YWx1ZXMKKDEsJ0FobWVkIEFsaScsJ2FobWVkQGdtYWlsLmNvbScsJzAxMDExMTExMTExJywnMjAyNS0wMS0xMCcpLAooMiwnU2FyYSBNb2hhbWVkJywnc2FyYUBnbWFpbC5jb20nLCcwMTAyMjIyMjIyMicsJzIwMjUtMDItMTUnKSwKKDMsJ09tYXIgSGFzc2FuJywnb21hckBnbWFpbC5jb20nLCcwMTAzMzMzMzMzMycsJzIwMjUtMDMtMjAnKSwKKDQsJ01vbmEgQWRlbCcsJ21vbmFAZ21haWwuY29tJywnMDEwNDQ0NDQ0NDQnLCcyMDI1LTA0LTA1JyksCig1LCdZb3Vzc2VmIFNhbWknLCd5b3Vzc2VmQGdtYWlsLmNvbScsJzAxMDU1NTU1NTU1JywnMjAyNS0wNS0xMicpOwogCiAKSU5TRVJUIElOVE8gYWRkcmVzc2VzIFZBTFVFUwooMSwxLCdDYWlybycsJ0VneXB0JywnMTE1MTEnKSwKKDIsMSwnR2l6YScsJ0VneXB0JywnMTI1MTEnKSwKKDMsMiwnQWxleGFuZHJpYScsJ0VneXB0JywnMjE1MTEnKSwKKDQsMywnTWFuc291cmEnLCdFZ3lwdCcsJzM1NTExJyksCig1LDQsJ0NhaXJvJywnRWd5cHQnLCcxMTUxMicpLAooNiw1LCdUYW50YScsJ0VneXB0JywnMzE1MTEnKTsKIAogCiAKSU5TRVJUIElOVE8gY2F0ZWdvcmllcyBWQUxVRVMKKDEsJ0xhcHRvcHMnKSwKKDIsJ1Bob25lcycpLAooMywnQWNjZXNzb3JpZXMnKTsKIAogCklOU0VSVCBJTlRPIHByb2R1Y3RzIFZBTFVFUwooMSwxLCdEZWxsIFhQUyAxMycsMzUwMDAsMTApLAooMiwxLCdIUCBQYXZpbGlvbicsMjgwMDAsOCksCigzLDIsJ2lQaG9uZSAxNScsNTAwMDAsMTIpLAooNCwyLCdTYW1zdW5nIFMyNCcsNDIwMDAsMTUpLAooNSwzLCdXaXJlbGVzcyBNb3VzZScsNTAwLDUwKSwKKDYsMywnTWVjaGFuaWNhbCBLZXlib2FyZCcsMTUwMCwzMCk7CiAKIAogCklOU0VSVCBJTlRPIG9yZGVycyBWQUxVRVMKKDEsMSwxLCcyMDI1LTA2LTAxJywnRGVsaXZlcmVkJyksCigyLDIsMywnMjAyNS0wNi0wNScsJ1BlbmRpbmcnKSwKKDMsMSwyLCcyMDI1LTA2LTA3JywnRGVsaXZlcmVkJyksCig0LDMsNCwnMjAyNS0wNi0xMCcsJ1NoaXBwZWQnKSwKKDUsNSw2LCcyMDI1LTA2LTEyJywnUGVuZGluZycpOwogCiAKSU5TRVJUIElOVE8gb3JkZXJpdGVtcyBWQUxVRVMKKDEsMSwxLDM1MDAwKSwKKDEsNSwyLDUwMCksCiAKKDIsMywxLDUwMDAwKSwKIAooMywyLDEsMjgwMDApLAooMyw2LDEsMTUwMCksCiAKKDQsNCwxLDQyMDAwKSwKIAooNSw1LDMsNTAwKSwKKDUsNiwyLDE1MDApOwogCiAKIAogCklOU0VSVCBJTlRPIHBheW1lbnRzIFZBTFVFUwooMSwxLCcyMDI1LTA2LTAxJywzNjAwMCwnQ3JlZGl0IENhcmQnKSwKKDIsMiwnMjAyNS0wNi0wNScsNTAwMDAsJ0Nhc2gnKSwKKDMsMywnMjAyNS0wNi0wNycsMjk1MDAsJ0NyZWRpdCBDYXJkJyksCig0LDQsJzIwMjUtMDYtMTAnLDQyMDAwLCdQYXlQYWwnKTsKIAogCklOU0VSVCBJTlRPIHJldmlld3MgVkFMVUVTCigxLDEsMSw1LCdFeGNlbGxlbnQgbGFwdG9wJywnMjAyNS0wNi0xNScpLAooMiwyLDMsNCwnVmVyeSBnb29kIHBob25lJywnMjAyNS0wNi0xNicpLAooMywzLDQsNSwnQW1hemluZyBjYW1lcmEnLCcyMDI1LTA2LTE3JyksCig0LDEsNSw0LCdHb29kIG1vdXNlJywnMjAyNS0wNi0xOCcpLAooNSw1LDYsNSwnR3JlYXQga2V5Ym9hcmQnLCcyMDI1LTA2LTE5Jyk7CiAKIApzZWxlY3QgKiBmcm9tIG9yZGVyczsKIAotLUxpc3QgYWxsIHByb2R1Y3RzIHdpdGggcHJpY2UgPiAxMDAgb3JkZXJlZCBieSBwcmljZSBpbiBkZXNjZW5kaW5nIG9yZGVyCnNlbGVjdCogZnJvbSBwcm9kdWN0cwp3aGVyZSBwcmljZSA+IDEwMApvcmRlciBieSBwcmljZSBkZXNjOwogCi0tQ3VzdG9tZXJzIG5hbWVzIGFuZCBpZHMgZnJvbSBhIE5ldyBZb3JrIGNpdHkKc2VsZWN0IGRpc3RpbmN0IG5hbWUsIGN1c3RvbWVycy5jdXN0b21lcmlkCmZyb20gY3VzdG9tZXJzIGpvaW4gYWRkcmVzc2VzCm9uIGN1c3RvbWVycy5jdXN0b21lcmlkPWFkZHJlc3Nlcy5jdXN0b21lcmlkIAp3aGVyZSBjaXR5PSdDYWlybyc7CiAKLS0gYW5vdGhlciBzb2x1dGlvbiAKc2VsZWN0IG5hbWUsY3VzdG9tZXJpZApmcm9tIGN1c3RvbWVycyAKd2hlcmUgY3VzdG9tZXJpZCBpbiAoCnNlbGVjdCBjdXN0b21lcmlkIApmcm9tIGFkZHJlc3NlcyAKd2hlcmUgY2l0eT0nQ2Fpcm8nCikKIAotLU9yZGVycyBpbiB0aGUgbGFzdCAyMCBkYXlzCnNlbGVjdCogZnJvbSBvcmRlcnMKd2hlcmUgb3JkZXJkYXRlPj0gY3VycmVudF9kYXRlIC0gaW50ZXJ2YWwgJzIwIGRheXMnOwogCi0tUmV2aWV3cyB3aXRoIHJhdGluZyA+PSA0IHNvcnRlZCBieSBuZXdlc3QKc2VsZWN0KmZyb20gcmV2aWV3cyAKd2hlcmUgcmF0aW5nID49NApvcmRlciBieSByZXZpZXdkYXRlIGRlc2M7CiAKLS1TaG93IHByb2R1Y3RzIHdpdGggdGhlaXIgY2F0ZWdvcnkgbmFtZXMKc2VsZWN0IHByb2R1Y3RzLiosY2F0ZWdvcnluYW1lCmZyb20gcHJvZHVjdHMgam9pbiBjYXRlZ29yaWVzIApvbiBwcm9kdWN0cy5jYXRlZ29yeWlkPWNhdGVnb3JpZXMuY2F0ZWdvcnlpZDsKIAotLVNob3cgcGF5bWVudHMgd2l0aCBvcmRlciBkYXRlCnNlbGVjdCBwYXltZW50cy4qLG9yZGVyZGF0ZQpmcm9tIHBheW1lbnRzIGpvaW4gb3JkZXJzIApvbiBwYXltZW50cy5vcmRlcmlkPW9yZGVycy5vcmRlcmlkOwogCi0tTGlzdCByZXZpZXdzIHdpdGggcHJvZHVjdCBuYW1lcyBhbmQgY3VzdG9tZXIgbmFtZXMKc2VsZWN0IHByb2R1Y3RuYW1lLG5hbWUgCmZyb20gcmV2aWV3cyBqb2luIHByb2R1Y3RzIApvbiByZXZpZXdzLnByb2R1Y3RpZD1wcm9kdWN0cy5wcm9kdWN0aWQgCmpvaW4gY3VzdG9tZXJzIApvbiBjdXN0b21lcnMuY3VzdG9tZXJpZD1yZXZpZXdzLmN1c3RvbWVyaWQ7CiAKLS1MaXN0IGFsbCBvcmRlcnMgd2l0aCBjdXN0b21lciBuYW1lLCBjaXR5LCBhbmQgb3JkZXIgZGF0ZQpzZWxlY3QgbmFtZSxjaXR5LG9yZGVyZGF0ZQpmcm9tIG9yZGVycyBqb2luIGN1c3RvbWVycyAKb24gb3JkZXJzLmN1c3RvbWVyaWQ9Y3VzdG9tZXJzLmN1c3RvbWVyaWQKam9pbiBhZGRyZXNzZXMKb24gYWRkcmVzc2VzLmN1c3RvbWVyaWQ9Y3VzdG9tZXJzLmN1c3RvbWVyaWQ7CiAKLS1TaG93IGVhY2ggb3JkZXIgaXRlbSB3aXRoIHByb2R1Y3QgbmFtZSwgY2F0ZWdvcnksIGFuZCBxdWFudGl0eQpzZWxlY3QgcHJvZHVjdG5hbWUsY2F0ZWdvcnluYW1lLHF1YW50aXR5CmZyb20gY2F0ZWdvcmllcyBqb2luIHByb2R1Y3RzCm9uIGNhdGVnb3JpZXMuY2F0ZWdvcnlpZD1wcm9kdWN0cy5jYXRlZ29yeWlkIApqb2luIG9yZGVyaXRlbXMgCm9uIHByb2R1Y3RzLnByb2R1Y3RpZD1vcmRlcml0ZW1zLm9yZGVyaWQ7CiAKLS1DdXN0b21lcnMgd2hvIG5ldmVyIHBsYWNlZCBhbiBvcmRlcgpzZWxlY3QgY3VzdG9tZXJzLiogCmZyb20gY3VzdG9tZXJzIGxlZnQgam9pbiBvcmRlcnMgCm9uIGN1c3RvbWVycy5jdXN0b21lcmlkPW9yZGVycy5jdXN0b21lcmlkCndoZXJlIG9yZGVycy5vcmRlcmlkIGlzIG51bGw7CiAKLS1PcmRlcnMgd2l0aCBubyBwYXltZW50cwpzZWxlY3Qgb3JkZXJzLioKZnJvbSBvcmRlcnMgbGVmdCBqb2luIHBheW1lbnRzIApvbiBvcmRlcnMub3JkZXJpZD1wYXltZW50cy5vcmRlcmlkCndoZXJlIHBheW1lbnRzLm9yZGVyaWQgaXMgbnVsbDsKIAotLSBwYXJ0IDIKLS0gTnVtYmVyIG9mIG9yZGVycyBwZXIgY3VzdG9tZXIKc2VsZWN0IGN1c3RvbWVycy5jdXN0b21lcmlkLGN1c3RvbWVycy5uYW1lICxjb3VudCgqKSBhcyBOdW1iZXJPZk9yZGVycwpmcm9tIG9yZGVycyBpbm5lciBqb2luIGN1c3RvbWVycwpvbiBvcmRlcnMuY3VzdG9tZXJpZD1jdXN0b21lcnMuY3VzdG9tZXJpZApncm91cCBieSBjdXN0b21lcnMuY3VzdG9tZXJpZCxjdXN0b21lcnMubmFtZTsKIAotLVRvdGFsIHNwZW5kaW5nIHBlciBjdXN0b21lcgpzZWxlY3QgY3VzdG9tZXJzLmN1c3RvbWVyaWQsc3VtKGFtb3VudCkgYXMgdG90YWxfYW1vdW50CmZyb20gb3JkZXJzIGpvaW4gY3VzdG9tZXJzIApvbiBvcmRlcnMuY3VzdG9tZXJpZCA9Y3VzdG9tZXJzLmN1c3RvbWVyaWQgCmpvaW4gcGF5bWVudHMgCm9uIG9yZGVycy5vcmRlcmlkID1wYXltZW50cy5vcmRlcmlkIApncm91cCBieSBjdXN0b21lcnMuY3VzdG9tZXJpZAogCi0tTnVtYmVyIG9mIHByb2R1Y3RzIHBlciBjYXRlZ29yeQpzZWxlY3QgcHJvZHVjdHMuY2F0ZWdvcnlpZCxjb3VudChwcm9kdWN0aWQpIGFzIG5vX29mX3Byb2R1Y3RzCmZyb20gcHJvZHVjdHMgam9pbiBjYXRlZ29yaWVzCm9uIHByb2R1Y3RzLmNhdGVnb3J5aWQgPWNhdGVnb3JpZXMuY2F0ZWdvcnlpZCAKZ3JvdXAgYnkgcHJvZHVjdHMuY2F0ZWdvcnlpZDsKIAogCi0tQXZlcmFnZSByYXRpbmcgcGVyIHByb2R1Y3QKc2VsZWN0IHByb2R1Y3RzLnByb2R1Y3RpZCwgYXZnIChyYXRpbmcpIGFzIGF2Z19yYXRpbmcKZnJvbSBwcm9kdWN0cyBqb2luIHJldmlld3MKb24gcHJvZHVjdHMucHJvZHVjdGlkID1yZXZpZXdzLnByb2R1Y3RpZCAKZ3JvdXAgYnkgcHJvZHVjdHMucHJvZHVjdGlkIAogCiAKLS1Ub3RhbCBxdWFudGl0eSBzb2xkIHBlciBwcm9kdWN0IGZvciB0aG9zZSBldmVyIHNvbGQKc2VsZWN0IHByb2R1Y3RzLnByb2R1Y3RpZCxzdW0ocXVhbnRpdHkpIGFzIHRvdGFsCmZyb20gcHJvZHVjdHMgam9pbiBvcmRlcml0ZW1zIApvbiBwcm9kdWN0cy5wcm9kdWN0aWQgPW9yZGVyaXRlbXMucHJvZHVjdGlkIApqb2luIG9yZGVycwpvbiBvcmRlcml0ZW1zLm9yZGVyaWQgPW9yZGVycy5vcmRlcmlkCmdyb3VwIGJ5IHByb2R1Y3RzLnByb2R1Y3RpZAogCi0tVG90YWwgcmV2ZW51ZSBwZXIgb3JkZXIKc2VsZWN0IHByb2R1Y3RzLnByb2R1Y3RpZCBhcyBwcm9kdWN0X2lkLGNvdW50KCopIGFzIHRvdGFsIApmcm9tIHByb2R1Y3RzIGpvaW4gcmV2aWV3cyAKb24gcHJvZHVjdHMucHJvZHVjdGlkID1yZXZpZXdzLnByb2R1Y3RpZCAKZ3JvdXAgYnkgcHJvZHVjdF9pZAogCi0tQ3VzdG9tZXJzIHdobyBtYWRlIG1vcmUgdGhhbiA1IG9yZGVycwpzZWxlY3QgY3VzdG9tZXJzLmN1c3RvbWVyaWQKZnJvbSBjdXN0b21lcnMgam9pbiBvcmRlcnMgCm9uIGN1c3RvbWVycy5jdXN0b21lcmlkID1vcmRlcnMuY3VzdG9tZXJpZCAKZ3JvdXAgYnkgY3VzdG9tZXJzLmN1c3RvbWVyaWQKaGF2aW5nIGNvdW50KG9yZGVyaWQpPjU7CiAKLS1DdXN0b21lcnMgd2hvIHNwZW50IG1vcmUgdGhhbiAxMDAwCiAKc2VsZWN0IGN1c3RvbWVycy5jdXN0b21lcmlkCmZyb20gb3JkZXJzIGpvaW4gY3VzdG9tZXJzIApvbiBvcmRlcnMuY3VzdG9tZXJpZCA9Y3VzdG9tZXJzLmN1c3RvbWVyaWQgCmpvaW4gcGF5bWVudHMgCm9uIG9yZGVycy5vcmRlcmlkID1wYXltZW50cy5vcmRlcmlkIApncm91cCBieSBjdXN0b21lcnMuY3VzdG9tZXJpZApoYXZpbmcgc3VtKGFtb3VudCk+MTAwMDsKIAogCi0tT3JkZXJzIHdpdGggdG90YWwgdmFsdWUgPiA1MDAKc2VsZWN0IG9yZGVycy5vcmRlcmlkCmZyb20gb3JkZXJzIGpvaW4gcGF5bWVudHMKb24gb3JkZXJzLm9yZGVyaWQgPXBheW1lbnRzLm9yZGVyaWQKZ3JvdXAgYnkgb3JkZXJzLm9yZGVyaWQKaGF2aW5nIHN1bShhbW91bnQpPjUwMDsKIAogCi0tUHJvZHVjdHMgd2l0aCBwcmljZSBhYm92ZSBhdmVyYWdlCnNlbGVjdCBwcm9kdWN0aWQKZnJvbSBwcm9kdWN0cwp3aGVyZSBwcmljZQo+CigKc2VsZWN0IGF2ZyhwcmljZSkKZnJvbSBwcm9kdWN0cykKIAotLU1vc3QgZXhwZW5zaXZlIHByb2R1Y3QKc2VsZWN0ICogZnJvbSBwcm9kdWN0cyAKd2hlcmUgcHJpY2U9KHNlbGVjdCBtYXgocHJpY2UpIGZyb20gcHJvZHVjdHMpOw==