Anand Prasad Agasar

Greenhorn
+ Follow
since May 03, 2011
Cows and Likes
Cows
Total received
0
In last 30 days
0
Total given
0
Likes
Total received
0
Received in last 30 days
0
Total given
0
Given in last 30 days
0
Forums and Threads
Scavenger Hunt
expand Ranch Hand Scavenger Hunt
expand Greenhorn Scavenger Hunt

Recent posts by Anand Prasad Agasar

Hi please find the code where i am able to do rotation,etc only print option is left.. i am getting only first button on the print copy.


import javax.imageio.ImageIO;

import javax.swing.ImageIcon;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToolBar;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.ByteArrayInputStream;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

import javax.swing.*;
import javax.swing.border.Border;

import java.net.*;










public class First extends JApplet{

private static BufferedImage clouds[]=new BufferedImage[2];
private JScrollPane scroll;
URL url = null;
URLConnection servletConnection = null;
private int flag = 0;
//private int scale = 1;
private int newAngle = 0;
private BufferedImage temp;
private int zoomState=0;
Scrollbar slider;
int sliderValue;
int number=0;
// PrintImagePanel fImgPanel;



/** The customer header comp. */
// private CustomerHeaderComp customerHeaderComp;

public void init() {
File input = new File("D:\\Pooja\\flower030.gif");
File input1=new File("D:\\Pooja\\rose.jpg");


/*String image1 = getParameter("image1");
String image2 = getParameter("image2"); */

try {




// url = new URL(getCodeBase(), "rose.jpg");
// URL imageURL = new URL(getCodeBase()+"/ChequeImgRetrievalServlet");
// String base64encJPG = (String)request.getParameter("data");
// byte decoded[] = new sun.misc.BASE64Decoder().decodeBuffer(image1);
// byte img1by[] = image1.getBytes();
// InputStream in = new ByteArrayInputStream(img1by);
// BufferedImage img = ImageIO.read(imageURL);
// clouds[0] = img;

// url = new URL(getCodeBase(), "ff.jpg");
// byte decoded1[] = new sun.misc.BASE64Decoder().decodeBuffer(image2);
// byte img2by[] = image2.getBytes();
// InputStream in1 = new ByteArrayInputStream(img2by);
// img = ImageIO.read(url);
// clouds[1] = img;
clouds[0] = ImageIO.read(input);
clouds[1]=ImageIO.read(input1);


} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Demo demo = new Demo();
getContentPane().add(demo);
getContentPane().add("South", new DemoControls(demo));



}


public class Demo extends Canvas
{
public String direction = "image";
public Object scalingFactor = "100%";
public JScrollPane scrollPane;
public Demo() {

setBackground(Color.white);

}

public void drawDemo(int width, int height, Graphics g) {
Graphics2D g2 = (Graphics2D) g;

/* if (scalingFactor.equals("100%")) {
scale = 1;
} else if (scalingFactor.equals("200%")) {
scale = 2;
} else if (scalingFactor.equals("300%")) {
scale = 3;
}*/
if (direction.equals("image")) {
temp = Rotation(clouds[number], 0);
newAngle = 0;

} else if (direction.equals(">>>")) {
temp = Rotation(clouds[number], newAngle - 90);

newAngle = newAngle - 90;
flag = 0;
} else if (direction.equals("<<<")) {

temp = Rotation(clouds[number], newAngle + 90);

newAngle = newAngle + 90;
flag = 1;
} /*else if (direction.equals("zoom")) {

if(scalingFactor.equals("50%")){
temp = zoomOut(Rotation(clouds[number], newAngle),2);}
else
temp=zoomIn(Rotation(clouds[number], newAngle), scale);
//spd = new ScrollPaneDemo(temp);
}*/
else if(direction.equals("zoomIn")){
zoomState=zoomState+1;
temp=resizeImage(zoomState);
}
else if(direction.equals("zoomOut")){
zoomState=zoomState-1;
temp=resizeImage(zoomState);
}
else if (direction.equals("back")){
number=0;
temp=Rotation(clouds[number], 0);
}
else if (direction.equals("next")){

number=1;
temp = Rotation(clouds[number], 0);
}

// temp = Rotation(clouds[number], 0);
// newAngle = 0;
// int frame_width = 360;
// int frame_height = 360;
//
// /* PrintTestApp f = new PrintTestApp();
// f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
//
// f.init (temp);
// f.setSize (frame_width, frame_height);
// f.setVisible (true);*/
// PrintingApplet pa=new PrintingApplet();
// } // main
//
//


return;
}

public BufferedImage resizeImage(int zoomState){
BufferedImage img=null;
if(zoomState<0){
img=zoomOut(Rotation(clouds[number], newAngle),(-1*zoomState)+1);

}
else if(zoomState>0){
img=zoomIn(Rotation(clouds[number], newAngle),zoomState+1);
}
else if(zoomState==0){
img=zoomIn(Rotation(clouds[number], newAngle),1);
}

switch(zoomState){
case 3:img=zoomIn(Rotation(clouds[number], newAngle),4);System.out.println("3");break;
case 2:img=zoomIn(Rotation(clouds[number], newAngle),3);System.out.println("2");break;
case 1:img=zoomIn(Rotation(clouds[number], newAngle),2);System.out.println("1");break;
case 0:img=zoomIn(Rotation(clouds[number], newAngle),1);System.out.println("0");break;
case -1:img=zoomOut(Rotation(clouds[number], newAngle),2);System.out.println("-1");break;
case -2:img=zoomOut(Rotation(clouds[number], newAngle),3);System.out.println("-2");break;
case -3:img=zoomOut(Rotation(clouds[number], newAngle),4);System.out.println("-3");break;
}
return img;
}


// Function For ZoomIn
public BufferedImage zoomIn(BufferedImage bi, int scale) {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] gs = ge.getScreenDevices();
int screenWidth=0 ;
int screenHeight=0;
for (int i=0; i<gs.length; i++) {
DisplayMode dm = gs[i].getDisplayMode();
screenWidth = dm.getWidth();
screenHeight = dm.getHeight();
}

int width = scale * bi.getWidth();
int height = scale * bi.getHeight();
BufferedImage biScale = new BufferedImage(width, height,
bi.getType());
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
biScale.setRGB(i, j, bi.getRGB(i / scale, j / scale));
if((screenWidth<width)||(screenHeight<height)){
System.out.println("Screen out Of Bound");

}
return biScale;
}

// Function For ZoomOut
public BufferedImage zoomOut(BufferedImage bi,int d) {
int width = (bi.getWidth() / d);
int height = (bi.getHeight() / d);
BufferedImage biScale = new BufferedImage(width, height,bi.getType());
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
biScale.setRGB(i, j, bi.getRGB(i*d, j * d));
return biScale;
}

// Method For Rotating Image
public <Picture> BufferedImage Rotation(BufferedImage pic, double angl) {
Picture pic1 = (Picture) pic;
int width = pic.getWidth();
int height = pic.getHeight();
double angle = Math.toRadians(angl);
double sin = Math.sin(angle);
double cos = Math.cos(angle);
double x0 = 0.5 * (width - 1); // point to rotate about
double y0 = 0.5 * (height - 1); // center of image
BufferedImage pic2 = new BufferedImage(width, height, 8);
// rotation
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
double a = x - x0;
double b = y - y0;
int xx = (int) (+a * cos - b * sin + x0);
int yy = (int) (+a * sin + b * cos + y0);

// plot pixel (x, y) the same color as (xx, yy) if it's in
// bounds
if (xx >= 0 && xx < width && yy >= 0 && yy < height) {
pic2.setRGB(x, y, pic.getRGB(xx, yy));
// pic2.set(x, y, pic1.get(xx, yy));
}
}
}
return pic2;
}

//For Printing


public void paint(Graphics g) {

{Graphics2D g2 = (Graphics2D) g;
Dimension d = getSize();
g.clearRect(0, 0, d.width, d.height);
drawDemo(d.width, d.height, g);
g2.drawImage(temp, 100, 20, this);}



}

}

static class DemoControls extends JPanel implements ActionListener,Printable
{
Demo demo;
JToolBar toolbar;
protected JTextArea textArea;

public DemoControls(Demo demo) {
ImageIcon theIcon = new ImageIcon("D:\\Pooja\\printer.png");
ImageIcon clockwise = new ImageIcon("D:\\Pooja\\arrow3.png");
ImageIcon anticlockwise = new ImageIcon("D:\\Pooja\\arrowanti.png");
this.demo = demo;
demo.setBackground(Color.white);
add(toolbar = new JToolBar(), BorderLayout.PAGE_START);
toolbar.setFloatable(true);
addTool("image", "true Image",theIcon, true);
addTool("<<<", "anticlockwise",anticlockwise, false);
addTool(">>>", "clockwise",clockwise, false);
//addTool("zoom", "zoom", false);
//addTool("zoomIn","zoomIn",false);
//addTool("zoomOut","zoomOut",false);
addTool("back","last image",theIcon,false);
addTool("next","next image",theIcon,false);
addTool("print","Printing",theIcon,false);


/*add(combo = new JComboBox());
combo.addItem("50%");
combo.addItem("100%");
combo.addItem("200%");
combo.addItem("300%");
combo.addItemListener(this);*/
}

public void addTool(String str, String tooltip,ImageIcon curr, boolean state) {
JButton b = (JButton) toolbar.add(new JButton(str));
b.setBackground(state ? Color.pink : Color.lightGray);
b.setIcon(curr);
b.setToolTipText(tooltip);
b.setSelected(state);
b.setOpaque(false);
b.addActionListener(this);
}

/*public void itemStateChanged(ItemEvent event) {
if (event.getSource() == combo
&& event.getStateChange() == ItemEvent.SELECTED) {
System.out.println("Change:" + combo.getSelectedItem());
//System.out.println("Inside Item Listener");
demo.scalingFactor = combo.getSelectedItem();
}
}*/

public void actionPerformed(ActionEvent e) {

for (int i = 0; i < toolbar.getComponentCount(); i++) {
//System.out.println("Inside Action Listener");
JButton b = (JButton) toolbar.getComponentAtIndex(i);
b.setBackground(Color.lightGray);

}
JButton b = (JButton) e.getSource();
b.setBackground(Color.GRAY);
demo.direction = b.getText();
if(b.getText().equalsIgnoreCase("print")){
PrinterJob printJob = PrinterJob.getPrinterJob();
printJob.setPrintable(this);
System.out.println("prrint dialog"+printJob.printDialog());
if (printJob.printDialog())
{
try
{
printJob.print();
}
catch (Exception ex)
{
ex.printStackTrace();
}
}

}
demo.repaint();
}
public int print(Graphics g, PageFormat pf, int pi) throws PrinterException {
if (pi >= 1) {
return Printable.NO_SUCH_PAGE;
}

g.translate(100, 100);
Font f = new Font("Monospaced",Font.PLAIN,12);
g.setFont (f);
paint (g);
return Printable.PAGE_EXISTS;
}
}

public static void main(String[] args) {
First demo = new First();
demo.init();
JFrame f = new JFrame("ToolBar");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});

f.pack();
f.setSize(new Dimension(200, 200));
f.show();



}


}


10 years ago
I have developed the applet code to embed in the jsf page for Image processing like zoom , rotate , print , back next ,. I have the problem with print, getting blank page printed, i think any security issues or code issues exists.
and also i need any ones help in adding scrollbar , pagination if multiple image exists, as of now i am using back - next.

Find the code below, please help me, as soon as possible.
import javax.imageio.ImageIO;

import javax.print.attribute.PrintRequestAttributeSet;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.JToolBar;
import javax.swing.ScrollPaneConstants;

import java.applet.Applet;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.PrintJob;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Properties;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.net.*;
import javax.print.*;
import javax.print.attribute.*;
import javax.print.attribute.standard.*;
import javax.swing.*;



import sun.awt.ScrollPaneWheelScroller;

public class First extends JApplet{

private static BufferedImage clouds[]=new BufferedImage[2];
private JScrollPane scroll;
private int flag = 0;
private int scale = 1;
private int newAngle = 0;
private BufferedImage temp;
private int zoomState=0;
Scrollbar slider;
int sliderValue;
int number=0;
// PrintImagePanel fImgPanel;

public void init() {
// File input = new File("D:\\Pooja\\flower030.gif");
// File input1=new File("D:\\Pooja\\rose.jpg");
try {
URL url = new URL(getCodeBase(), "rose.jpg");
BufferedImage img = ImageIO.read(url);
clouds[0] = img;

url = new URL(getCodeBase(), "rose.jpg");
img = ImageIO.read(url);
clouds[1] = img;
// clouds[0] = ImageIO.read(input);
// clouds[1]=ImageIO.read(input1);


} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Demo demo = new Demo();
getContentPane().add(demo);
getContentPane().add("North", new DemoControls(demo));



}


public class Demo extends Canvas
{
public String direction = "image";
public Object scalingFactor = "100%";
public JScrollPane scrollPane;
public Demo() {

setBackground(Color.white);

}

public void drawDemo(int width, int height, Graphics g) {
Graphics2D g2 = (Graphics2D) g;

if (scalingFactor.equals("100%")) {
scale = 1;
} else if (scalingFactor.equals("200%")) {
scale = 2;
} else if (scalingFactor.equals("300%")) {
scale = 3;
}
if (direction.equals("image")) {
temp = Rotation(clouds[number], 0);
newAngle = 0;

} else if (direction.equals(">>>")) {
temp = Rotation(clouds[number], newAngle - 90);

newAngle = newAngle - 90;
flag = 0;
} else if (direction.equals("<<<")) {

temp = Rotation(clouds[number], newAngle + 90);

newAngle = newAngle + 90;
flag = 1;
} else if (direction.equals("zoom")) {

if(scalingFactor.equals("50%")){
temp = zoomOut(Rotation(clouds[number], newAngle),2);}
else
temp=zoomIn(Rotation(clouds[number], newAngle), scale);
//spd = new ScrollPaneDemo(temp);
}
else if(direction.equals("zoomIn")){
zoomState=zoomState+1;
temp=resizeImage(zoomState);
}
else if(direction.equals("zoomOut")){
zoomState=zoomState-1;
temp=resizeImage(zoomState);
}
else if (direction.equals("back")){
number=0;
temp=Rotation(clouds[number], 0);
}
else if (direction.equals("next")){

number=1;
temp = Rotation(clouds[number], 0);
}

// temp = Rotation(clouds[number], 0);
// newAngle = 0;
// int frame_width = 360;
// int frame_height = 360;
//
// /* PrintTestApp f = new PrintTestApp();
// f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
//
// f.init (temp);
// f.setSize (frame_width, frame_height);
// f.setVisible (true);*/
// PrintingApplet pa=new PrintingApplet();
// } // main
//
//


return;
}

public BufferedImage resizeImage(int zoomState){
BufferedImage img=null;
if(zoomState<0){
img=zoomOut(Rotation(clouds[number], newAngle),(-1*zoomState)+1);

}
else if(zoomState>0){
img=zoomIn(Rotation(clouds[number], newAngle),zoomState+1);
}
else if(zoomState==0){
img=zoomIn(Rotation(clouds[number], newAngle),1);
}

switch(zoomState){
case 3:img=zoomIn(Rotation(clouds[number], newAngle),4);System.out.println("3");break;
case 2:img=zoomIn(Rotation(clouds[number], newAngle),3);System.out.println("2");break;
case 1:img=zoomIn(Rotation(clouds[number], newAngle),2);System.out.println("1");break;
case 0:img=zoomIn(Rotation(clouds[number], newAngle),1);System.out.println("0");break;
case -1:img=zoomOut(Rotation(clouds[number], newAngle),2);System.out.println("-1");break;
case -2:img=zoomOut(Rotation(clouds[number], newAngle),3);System.out.println("-2");break;
case -3:img=zoomOut(Rotation(clouds[number], newAngle),4);System.out.println("-3");break;
}
return img;
}


// Function For ZoomIn
public BufferedImage zoomIn(BufferedImage bi, int scale) {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] gs = ge.getScreenDevices();
int screenWidth=0 ;
int screenHeight=0;
for (int i=0; i<gs.length; i++) {
DisplayMode dm = gs[i].getDisplayMode();
screenWidth = dm.getWidth();
screenHeight = dm.getHeight();
}

int width = scale * bi.getWidth();
int height = scale * bi.getHeight();
BufferedImage biScale = new BufferedImage(width, height,
bi.getType());
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
biScale.setRGB(i, j, bi.getRGB(i / scale, j / scale));
if((screenWidth<width)||(screenHeight<height)){
System.out.println("Screen out Of Bound");

}
return biScale;
}

// Function For ZoomOut
public BufferedImage zoomOut(BufferedImage bi,int d) {
int width = (bi.getWidth() / d);
int height = (bi.getHeight() / d);
BufferedImage biScale = new BufferedImage(width, height,bi.getType());
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
biScale.setRGB(i, j, bi.getRGB(i*d, j * d));
return biScale;
}

// Method For Rotating Image
public <Picture> BufferedImage Rotation(BufferedImage pic, double angl) {
Picture pic1 = (Picture) pic;
int width = pic.getWidth();
int height = pic.getHeight();
double angle = Math.toRadians(angl);
double sin = Math.sin(angle);
double cos = Math.cos(angle);
double x0 = 0.5 * (width - 1); // point to rotate about
double y0 = 0.5 * (height - 1); // center of image
BufferedImage pic2 = new BufferedImage(width, height, 8);
// rotation
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
double a = x - x0;
double b = y - y0;
int xx = (int) (+a * cos - b * sin + x0);
int yy = (int) (+a * sin + b * cos + y0);

// plot pixel (x, y) the same color as (xx, yy) if it's in
// bounds
if (xx >= 0 && xx < width && yy >= 0 && yy < height) {
pic2.setRGB(x, y, pic.getRGB(xx, yy));
// pic2.set(x, y, pic1.get(xx, yy));
}
}
}
return pic2;
}

//For Printing


public void paint(Graphics g) {

{Graphics2D g2 = (Graphics2D) g;
Dimension d = getSize();
g.clearRect(0, 0, d.width, d.height);
drawDemo(d.width, d.height, g);
g2.drawImage(temp, 100, 20, this);}



}

}

static class DemoControls extends JPanel implements ActionListener,Printable,ItemListener
{
Demo demo;
JToolBar toolbar;
private JComboBox combo;
protected JTextArea textArea;

public DemoControls(Demo demo) {
this.demo = demo;
demo.setBackground(Color.white);
add(toolbar = new JToolBar(), BorderLayout.PAGE_START);
toolbar.setFloatable(true);
addTool("image", "true Image", true);
addTool("<<<", "anticlockwise", false);
addTool(">>>", "clockwise", false);
addTool("zoom", "zoom", false);
addTool("zoomIn","zoomIn",false);
addTool("zoomOut","zoomOut",false);
addTool("back","last image",false);
addTool("next","next image",false);
addTool("print","Printing",false);


add(combo = new JComboBox());
combo.addItem("50%");
combo.addItem("100%");
combo.addItem("200%");
combo.addItem("300%");
combo.addItemListener(this);
}

public void addTool(String str, String tooltip, boolean state) {
JButton b = (JButton) toolbar.add(new JButton(str));
b.setBackground(state ? Color.pink : Color.lightGray);
b.setToolTipText(tooltip);
b.setSelected(state);
b.addActionListener(this);
}

public void itemStateChanged(ItemEvent event) {
if (event.getSource() == combo
&& event.getStateChange() == ItemEvent.SELECTED) {
System.out.println("Change:" + combo.getSelectedItem());
//System.out.println("Inside Item Listener");
demo.scalingFactor = combo.getSelectedItem();
}
}

public void actionPerformed(ActionEvent e) {

for (int i = 0; i < toolbar.getComponentCount(); i++) {
//System.out.println("Inside Action Listener");
JButton b = (JButton) toolbar.getComponentAtIndex(i);
b.setBackground(Color.lightGray);

}
JButton b = (JButton) e.getSource();
b.setBackground(Color.GRAY);
demo.direction = b.getText();
if(b.getText().equalsIgnoreCase("print")){
PrinterJob printJob = PrinterJob.getPrinterJob();
printJob.setPrintable(this);
if (printJob.printDialog())
{
try
{
printJob.print();
}
catch (Exception ex)
{
ex.printStackTrace();
}
}

}
demo.repaint();
}

public int print(Graphics g, PageFormat arg1, int arg2)
throws PrinterException {
// TODO Auto-generated method stub
Graphics pg = getGraphics();
paint(pg);
demo.repaint();
return 0;
}
}

public static void main(String[] args) {
First demo = new First();
demo.init();
JFrame f = new JFrame("ToolBar");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});

f.pack();
f.setSize(new Dimension(200, 200));
f.show();



}


}


11 years ago
Hi,
When i click the link in the data tabel, I will get JSF pop-up page, in that i am embeding html file including<iframe> ,html file which will display image and the controls to rotate,zoom,print,pagination. I used to display image from /images folder in the project .Now i need to display the image which comes from remote and will get two images in binary. How to convert binary file which will have two images and display dynamically.Please help me on this.
Hi John, Eric
Thanks for your reply. Its working now i placed the code in one file and named it as .html and using <iframe> adding that file in xhtml.
its working now
Rather integrating , i am copying the code in the xhtml. But facing problem script error "object doesnt support this property or method.
HI,
I need help in integrating one xhtml in another xhtml
I tried with sample code using <iframe> tag but the xhtml contains the java script etc. because of which error displayed when i run the application. Error: alert is displayed saying " your current security settings prohibit active-x control to run on your page.....
I would appreciate if i get any help on this soon.
HI,
I need help in integrating one xhtml in another xhtml
I tried with sample code using <iframe> tag but the xhtml contains the java script etc. because of which error displayed when i run the application. alert is displayed saying " your current security settings prohibit active-x control to run on your page.....
HI,
I am in need of applet code to print an image and also the zooming and rotation of the images in the applet.
I tried with samples which is giving problem like image will be cleared from screen when print preview window is displayed and if i cancel the print preview window, it is displayed continuously..infinite loop.
I would really appreciate if i get solution for this because this is need for an hour.
11 years ago